{"id":21151137,"url":"https://github.com/johnsonjo4531/contours","last_synced_at":"2026-04-24T20:01:17.382Z","repository":{"id":85602776,"uuid":"61250838","full_name":"johnsonjo4531/contours","owner":"johnsonjo4531","description":"ES6 template string templating with support of DOM node and optionally jQuery element insertion.","archived":false,"fork":false,"pushed_at":"2017-05-15T16:42:24.000Z","size":89,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-02-15T06:26:20.427Z","etag":null,"topics":["contours","dom-node","insert-elements","templatetags","templating","ui-components","views"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/johnsonjo4531.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"license.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-06-16T00:52:13.000Z","updated_at":"2022-11-06T07:32:20.000Z","dependencies_parsed_at":null,"dependency_job_id":"237f226d-cc16-4469-9a7c-0817a706f492","html_url":"https://github.com/johnsonjo4531/contours","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/johnsonjo4531/contours","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnsonjo4531%2Fcontours","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnsonjo4531%2Fcontours/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnsonjo4531%2Fcontours/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnsonjo4531%2Fcontours/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/johnsonjo4531","download_url":"https://codeload.github.com/johnsonjo4531/contours/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnsonjo4531%2Fcontours/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32238748,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-24T13:21:15.438Z","status":"ssl_error","status_checked_at":"2026-04-24T13:21:15.005Z","response_time":64,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["contours","dom-node","insert-elements","templatetags","templating","ui-components","views"],"created_at":"2024-11-20T10:13:49.676Z","updated_at":"2026-04-24T20:01:17.339Z","avatar_url":"https://github.com/johnsonjo4531.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n**contours.js is in early alpha, and may change so be warned.**\n**symantic versioning will be followed in the stable version 1.0.0**\n\n\n# contours.js\n\n\nContents\n---\n- [Intro](#examples)\n- [Details](#details)\n- [API](#api)\n  - [contours](#contours)\n    - [Interpolation Rules](#interpolation-rules)\n  - [contours.safeHTML](#contourssafehtml)\n  - [contours.custom()](#contourscustom)\n- [License](#license)\n\n\nExamples\n----\n\n\n\nContours.js is a view micro-library for constructing views using ES2015 template strings. Contours is dependency free, but plays well with jQuery.\n\nContours provides composability with existing dom nodes and speed.\n\n### composability when you need it\n\n```\n// an existing jquery object returning function\nfunction getEl () {\n  return $(\"\u003cdiv\u003ehere's jQuery\u003c/div\u003e\");\n}\n\nvar docFrag = contours`\n\u003cdiv\u003e\n  ${getEl()}\n\u003c/div\u003e\n`\n\ndocument.body.appendChild(docFrag);\n```\n\n#### speed when you need it\n\nUse the safeHTML method of contours when creating lots of nodes.\n\n```\nlet { safeHTML } = contours;\nvar data = [...Array(1000).keys()];\nvar getSafeHTML = (datum =\u003e safeHTML`\u003cdiv\u003e${datum}\u003c/div\u003e`);\nvar obj = safeHTML`\n\u003cdiv\u003e\n  ${data.map(getSafeHTML)}\n\u003c/div\u003e\n`;\ndocument.body.appendChild(obj.toFrag());\n```\n\nHere's an example usage.\n\n```\nvar userData = [\n  {\n    name: \"Joe Jackson\",\n    picture: \"http://placehold.it/40x40\"\n  },\n  {\n    name: \"Jessica Jackson\",\n    picture: \"http://placehold.it/40x40\"\n  },\n  {\n    name: \"Jimmy Jones\",\n    picture: \"http://placehold.it/40x40\"\n  },\n];\n\nvar frag = contours`\n  \u003cdiv class=\"userlist\"\u003e\n    ${userData.map(function (user) {\n      return contours`\n        \u003cdiv\u003e\n          \u003cimg $@${{src: user.picture }}\"\u003e\n          $#${user.name}\n        \u003c/div\u003e\n      `;\n      })}\n  \u003c/div\u003e\n`\n\ndocument.body.appendChild(frag);\n```\n\nThe above produces HTML like this: (with different white-space)\n\n```\n\u003cbody\u003e\n  ...\n  \u003cdiv class=\"userlist\"\u003e\n    \u003cdiv\u003e\n      \u003cimg src=\"http://placehold.it/40x40\"\u003e\n      Joe Jackson\n    \u003c/div\u003e\n    \u003cdiv\u003e\n      \u003cimg src=\"http://placehold.it/40x40\"\u003e\n      Jessica Jackson\n    \u003c/div\u003e\n    \u003cdiv\u003e\n      \u003cimg src=\"http://placehold.it/40x40\"\u003e\n      Jimmy Jones\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003c/body\u003e\n```\n\nThe image can also be done like so:\n```\ncontours`\n  ...\n  \u003cimg src=\"${user.picture}\"\u003e\n  ...\n`\n```\n\nDetails\n----\n\n\nContours' main function is a template tag function that returns a DOM node. Which looks like this when called.\n\n```\nvar el = contours`\u003cdiv\u003eHello, world!\u003c/div\u003e`;\ndocument.body.appendChild(el);\n ```\n\n The above appends div element to body with content \"Hello, world!\"\n\nSince contours is a template tag function it is able to intercept the values sent into it. Contours main feature is the ability to add DOM nodes, HTMLCollections, NodeLists, and jQuery wrapped elements that are sent in through the interpolation brackets (e.g. `${}`) to the spot they are located in the markup. Strings are escaped by default. With this feature you can easily append nodes in your markup.\n\nAPI\n----\n###### In alphabetical order:\n\n- [contours](#contours)\n  - [Interpolation Rules](#interpolation-rules)\n- [contours.safeHTML](#contourssafehtml)\n- [contours.custom()](#contourscustom)\n\n### contours\n#### contours' template tag function\n\nUsage: ``contours`some template string possibly with an ${interpolation values} or more` ``\n\nfunction declaration: `contours(strings, ...values)`\n\nreturn value: DOM Element\n\nexample:\n```\nvar data = [\n  [\"foo\", \"bar\", \"baz\"],\n  ['100', '220', '300'],\n  ['300', '80', '400']\n];\n\ndocument.body.appendChild(contours`\n  \u003ctable\u003e\n    \u003ctbody\u003e\n      ${data.map(data =\u003e {\n        return contours`\n          \u003ctr\u003e\n            ${data.map((datum) =\u003e contours`\u003ctd\u003e$#${datum}\u003c/td\u003e`)}\n          \u003c/tr\u003e`;\n      })}\n    \u003c/tbody\u003e\n  \u003c/table\u003e\n`);\n\n/*\nbuilds a table that looks like this:\n| foo  | bar  | baz  |\n| 100  | 220  | 300  |\n| 300  | 80   | 400  |\n*/\n```\n\nThe above example uses JavaScript's built in Array.prototype.map function.\n\ndescription:\ncontours is a template tag function which constructs HTML from the strings and interpolation values provided. Calling this function like the above always uses its default. In order to use nonDefault options use `contours.custom()`.\n\ncontours uses `.innerHTML` internally but escapes strings by default instead of inserting them in as html.\n\nBelow are interpolation rules for the contours function\n\n### Interpolation rules\n\nThe following are valid interpolation symbols and their functionality with contours:\n- `${expression}`: if the value is a node like value insert it as a Node. Node like expressions must be positioned in a valid node position so make sure your value is in the right spot. If the value is a string escape it. If the value is an array containing only strings or string like objects (like safeHTML) contours will concatenate and append them as strings. If the value is an array \n- `$@${expression}`: inserts value as an attribute to an element. Must be used within an opening tag at a valid attribute location. When setting the style property its value can be either a style string or an object with camelCase letters or strings of the proper css style property. The camelCase properties will be converted to kabob-case internally for the style attributes provided. The use of a property starting with \"on\" e.g. \"onclick\" will use addEventListener (for the event with the name of the string with the \"on\" ommited e.g. \"onmouseout\" property will listen for \"mouseout\" events) on the target element internally. This works with custom events as well just prepend 'on' to the beginning of the event name when adding it as a property to the object sent into the attributes function.\n- `$#${expression}`: inserts value of expression in a text node. Must be placed any where a node can be placed.\n- `$*${expression}`: inserts value of expression in escapeHTML before sending in the value.\n\n### contours.safeHTML\n\nreturns an object\n\nexample:\n\n```\nlet data = [1,2,3,4,5],\n  {safeHTML} = contours;\n\nvar el = safeHTML`\n\u003cdiv\u003e\n  ${data.map((i) =\u003e safeHTML`\u003cdiv\u003e${i}\u003c/div\u003e`)}\n\u003c/div\u003e\n`;\n\ndocument.body.appendChild(el.toFrag());\n```\n\ndescription:\nThe safeHTML object is an obj with a property named `data` for the string being built. A custom property so contours can recognize it as a safeHTML obj and it has a `toFrag` method that turns the html into a document fragment.\n\nsafeHTML is faster than using contours' main function because it doesn't parse and create the created HTML until you tell it to create a document fragment by calling toFrag. This means if your creating 1000s of elements safeHTML is the way to go. The only down side is that you can only insert strings, safeHTML objects, or arrays containing only those two. You cannot add nodes into safeHTML.\n\n### contours.custom()\n\nUsage: `contours.custom({\n  scripts: false\n})`\n\nfunction declaration: `contours.attributes(object)`\n\nreturn value: returns the contours main template tag function with options waiting to be applied.\n\nexample:\n\n```\n// contours template tag function with all non-default options applied\nvar myContours = contours.custom({\n  includeScripts: true\n});\n\ndocument.body.appendChild(myContours`\n  \u003cdiv\u003e${document.createTextNode(\"Hey there buckaroo!\")}\u003c/div\u003e\n  \u003cscript\u003econsole.log(\"Look scripts and multiple roots!\");\u003c/script\u003e\n`);\ndocument.body.appendChild(contours`\u003cdiv\u003e${document.createTextNode(\"Default options again no change to main contours function.\")}\u003c/div\u003e`);\n```\n\nCurries the contours function to supply your options at a time when the template tag function is called. Can be stored in a variable like above or used Immediately after like below:\n\n```\ndocument.getElementById(\"app\").appendChild(\n  contours.custom({\n    includeScripts: true\n  })`\n    \u003cdiv\u003e\n      \u003cdiv\u003e${document.createTextNode(\"Here be dragons!\")}\u003c/div\u003e\n      \u003cscript\u003econsole.log(\"Script tags included, but not multiple roots.\");\u003c/script\u003e\n    \u003c/div\u003e\n  `\n);\n```\n\n\n\n\n\nLicense\n---\n### MIT\n\nCopyright (c) 2016 John Johnson\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohnsonjo4531%2Fcontours","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjohnsonjo4531%2Fcontours","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohnsonjo4531%2Fcontours/lists"}