├── README.md ├── aris.js ├── aris.min.js ├── converter.html ├── logo.svg └── package.json /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ![NPM](https://img.shields.io/npm/l/aris) 4 | ![npm](https://img.shields.io/npm/v/aris) 5 | ![npm bundle size](https://img.shields.io/bundlephobia/minzip/aris) 6 | ![Dependencies](https://img.shields.io/badge/dependencies-0-success) 7 | ![Snyk Vulnerabilities for npm package](https://img.shields.io/snyk/vulnerabilities/npm/aris) 8 | 9 | # Aris - Write HTML in JS easily. 10 | 11 | Aris is a simple library that allows you to write HTML in JS easily. 12 | 13 | *If you know HTML and JS, you already know Aris.* 14 | 15 | ## Usage 16 | 17 | **Browser / CDN:** 18 | ```html 19 | 20 | ``` 21 | 22 | **NPM:** 23 | ```bash 24 | npm i aris 25 | ``` 26 | 27 | Or you can clone/download this GitHub repository. 28 | 29 | ## Converter 30 | 31 | [Convert HTML to Aris.](https://bkys.io/aris/converter.html) 32 | 33 | ## The Idea 34 | 35 | Imagine you want to write the following shit: 36 | 37 | ```javascript 38 | var dropdownHTML = ''; 39 | for (var i = 0; i < dropdownValues.length; ++i) { 40 | dropdownHTML += '' + dropdownValues[i] + ''; 41 | } 42 | el.innerHTML = ''; 57 | ``` 58 | 59 | Wouldn't it be better to write it like: 60 | 61 | ```javascript 62 | el.innerHTML = HTML(['div', {class: 'dropdown'}, 63 | ['button', dropdown.text, { 64 | class: 'btn dropdown-toggle', 65 | type: 'button', 66 | id: 'dropdownMenuButton', 67 | dataToggle: 'dropdown', 68 | ariaHaspopup: true, 69 | ariaExpanded: false, 70 | disabled: [dropdownDisabled] 71 | }], 72 | ['div', {class: 'dropdown-menu', ariaLabelledby: 'dropdownMenuButton'}, 73 | dropdownValues, function (x) { 74 | return ['a', {class: 'dropdown-item'}, x] 75 | } 76 | ] 77 | ]); 78 | ``` 79 | 80 | Wow! Such syntax. Much clean. 81 | 82 | ## Functions 83 | 84 | ### HTML 85 | 86 | - `HTML(context)` 87 | Creates a HTML string with the context. 88 | 89 | #### Example: 90 | 91 | ```javascript 92 | HTML(["div", {id: "y", class: "a b", style: {color: "red"}, ariaLabel: "x"}, 93 | "Text", 94 | ["a", {href: "example.com", target: "_blank"}, "link"], 95 | {style: {width: 1, opacity: 0.5}, class: "c", pos: 1}, 96 | ['A', 'B', 'C'], function (x) { return ["div", x] }, 97 | [ [0, 1, 2], function (x) { return ["span", x] } ] 98 | ]) 99 | ``` 100 | 101 | **Turns into:** 102 | 103 | ```HTML 104 |
106 | Text 107 | link 108 |
A
B
C
109 | 012 110 |
111 | ``` 112 | 113 | Explanation (skip if you can figure out from the example): 114 | 115 | - If the starting element is a string, it is treated as a tag name. 116 | `['div', 'Text']` → `
Text
` 117 | 118 | - Attributes are added via objects. 119 | The object can be anywhere in the array except for the starting element. 120 | You can use any preferred style: 121 | `['div', {id: 'x'}, 'a', 'b', 'c']` OR 122 | `['div', 'a', 'b', 'c', {id: 'x'}]` 123 | This allows you to specialize contexts by pushing classes onto them. 124 | 125 | - Attributes can be defined via camelCase or snake_case. 126 | They will automatically converted to camelCase, kebab-case and snake_case. 127 | This is so that you can avoid using quotes on the keys. 128 | `{ariaLabel: "x"}` → `aria-label="x"` 129 | 130 | - If the starting element is an array, the contents of the entire 131 | array will be converted to HTML and joined. 132 | `[['div', 0], ['div', 1]]` → `
0
1
` 133 | 134 | - Inline CSS can be defined via objects or strings. 135 | They will be combined in sequential order. 136 | Repeated CSS properties will be replaced. 137 | The CSS will be **auto-magically** prefixed. 138 | For numerical properties, `px` will be automatically added if where applicable. (similar to jQuery). 139 | `['div', {style: {opacity: 0, width: 2}}, 'x', {style: "opacity: 1; filter: grayscale(100%)"}]` → 140 | `
x
` 141 | 142 | - Classes are joined with spaces if repeated in an object. 143 | `['div', {class: 'a'}, 'x', {class: 'b'}]` → `
x
` 144 | 145 | - Other attributes are replaced if repeated in an object. 146 | `['div', {id: 'a'}, 'x', {id: 'b'}]` → `
x
` 147 | 148 | - If an element is an array, and the next element is a function, 149 | the array will be automatically mapped to the function. 150 | `['div', [1,2,3], function (x) { return x*2 }]` → `
246
` 151 | `['div', [[1,2,3], function (x) { return x*2 }] ]` → `
246
` 152 | 153 | ### Escaping HTML special characters 154 | 155 | - `HTML.escape(text)` 156 | Returns the chunk of text with special HTML characters (`<>?"'`) escaped. 157 | 158 | To allow HTML to be used in text, Aris does not auto-escape special HTML characters. 159 | Please use this function to manually escape the characters where intended. 160 | 161 | ### HTML Boolean Attributes 162 | 163 | - `['button', {disabled: [true]}]` → `` 164 | `['button', {disabled: [false]}]` → `` 165 | For a boolean attribute, wrap it in an array. A truthy value denotes its presence. 166 | 167 | ### HTML Output Key Order and Hash 168 | 169 | - `HTML(['a', {href: 'x.com', id: 'link'}, 'x'])` → `x` 170 | `HTML(['a', 'x', {id: 'link', href: 'x.com'}])` → `x` 171 | The HTML output is deterministic, with attribute keys sorted in ascending order. 172 | 173 | - `HTML.hash(['a', {href: 'x.com', id: 'link'}, 'x'])` → `841135124` 174 | `HTML.hash(['a', 'x', {id: 'link', href: 'x.com'}])` → `841135124` 175 | `HTML.hash(HTML(['a', 'x', {id: 'link', href: 'x.com'}]))` → `841135124` 176 | `HTML.hash('some string')` → `-984100687` 177 | HTML contexts and strings can be hashed to 32-bit integers for compact storage and quick comparison. 178 | 179 | ## Why use Aris? 180 | 181 | - No dependencies. 182 | - No tooling. 183 | - No bloat. 184 | - No brainer. 185 | - No time wasted. 186 | - It just works. 187 | - Fast. 188 | 189 | If you think something else is better, feel free to try it and do your own comparisons. 190 | 191 | ## Support 192 | 193 | Aris is actively maintained and constantly tested against all major browsers (even IE). 194 | 195 | If you have any suggestions, questions, or bug reports, please raise an issue. 196 | 197 | ## FAQ 198 | 199 | - **How does Aris help me create high-performance user interfaces?** 200 | 201 | Aris is just plain old Javascript, all HTML generation is close to the metal. 202 | 203 | Use Aris to generate complex HTML and update the only the elements you need. 204 | 205 | This minimizes reflows and you will have a snappy user interface. 206 | 207 | - **What does Aris stands for?** 208 | 209 | Aris stands for "A Revolution In Syntax". 210 | 211 | We initially wanted to name our library `html.js`, but the name was taken on npm. 212 | 213 | If there is a namespace collision, you can use `aris` instead of `HTML`. 214 | `HTML` → `aris` 215 | `HTML.SVG` → `aris.svg` 216 | `HTML.SVG.Path` → `aris.svg.path` 217 | 218 | ## Bonus Features 219 | 220 | ### SVG 221 | 222 | For the artsy coders. 223 | 224 | - `HTML.SVG(width, height, ...context)` 225 | Creates a SVG string, with common boilerplate attributes automatically-filled. 226 | 227 | - `HTML.SVG.Path(...context).(...).(...)` 228 | Creates an SVG Path string. 229 | See \(\) 230 | for an overview on the path commands. 231 | 232 | #### Example: 233 | 234 | ```javascript 235 | var SVG = HTML.SVG, P = HTML.SVG.Path; 236 | HTML(SVG(30, 30, 237 | ['circle', {class: 'frame', cx: 15, cy: 15, r: 12}], 238 | P({class: 'hand hour'}).M(15,15).L(20,15), 239 | P({class: 'hand minute'}).M(15,15).L(15,2), 240 | P().M(0,0).L(1,1), 241 | P.M(0,0).L(1,1), // Path can be also be called without args! 242 | )) 243 | ``` 244 | 245 | **Is equivalent to:** 246 | 247 | ```javascript 248 | HTML(['svg', {xmlns: 'http://www.w3.org/2000/svg', 249 | width: '30px', height: '30px', viewBox: '0 0 30 30'}, 250 | ['circle', {class: 'frame', cx: 15, cy: 15, r: 12}], 251 | ['path', {class: 'hand hour', d: 'M15,15 L20,15'}], 252 | ['path', {class: 'hand minute', d: 'M15,15 L15,2'}], 253 | ['path', {d: 'M0,0 L1,1'}], 254 | ['path', {d: 'M0,0 L1,1'}], 255 | ]) 256 | ``` 257 | 258 | **Which turns into:** 259 | 260 | ```HTML 261 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | ``` 270 | 271 | You can even use this to create complex animated SVGs. ;) 272 | 273 | ### Lazy Loading 274 | 275 | This is just a bonus feature to make making single-page-apps easier. 276 | 277 | - `HTML.load(file0, file1, ...).done(fn)` 278 | Loads (.js, .css) files, then execute the done function `fn` (optionally). 279 | The files are downloaded asynchronously in parallel, but attached to the webpage in the specified order. 280 | Each file will be only loaded **once**. 281 | The done function is **always executed once per load call**, 282 | *irregardless* of whether the files have been loaded previously. 283 | 284 | The files are treated accordingly with their file extension. 285 | To force a file to be treated as a JS or CSS file, prefix the url with (`js:` or `css:`): 286 | `js: js/main` (whitespace around the `:` is ignored) 287 | 288 | CSS files will be **auto-magically** prefixed. 289 | 290 | Lazily loaded JS can be [debugged easily](https://developer.mozilla.org/en-US/docs/Tools/Debugger/How_to/Debug_eval_sources) in modern browsers, 291 | as we auto-prepend the sourceURL directive to the JS files. 292 | 293 | ### Hash Routing 294 | 295 | This is just a bonus feature to make making single-page-apps easier. 296 | 297 | - `HTML.route("path/to/page/anchor", fn)` 298 | Attaches the function `fn` to `#path/to/page/anchor`. 299 | 300 | - `HTML.route.go("path/to/page/anchor")` 301 | Executes the function attached to `#path/to/page/anchor`. 302 | 303 | - `HTML.route.go("path/to/page/:anchor")` 304 | Attemps to execute the function attached to the path. 305 | The prefix `:` on the path component denotes that it is is default option. 306 | If the visitor has visited `#path/to/page/one`, or if the address bar points to `#path/to/page/one`, it will execute the function attached to `#path/to/page/one`. 307 | Otherwise, it will execute the function attached to `#path/to/page/anchor`. 308 | 309 | - `HTML.route.go(":path/:to/:page")` 310 | You can prefix any path component with ":" to mark it as the default option. 311 | 312 | - `HTML.route.go()` 313 | Attempts to execute the function attached to the path in the address bar. 314 | (i.e. `window.location.hash`) 315 | 316 | ## License 317 | 318 | MIT -------------------------------------------------------------------------------- /aris.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Aris JavaScript Library v1.0.11 3 | * @author vectorized.eth 4 | * MIT license 5 | * 6 | * Includes PrefixFree v1.0.7 7 | * https://leaverou.github.io/prefixfree 8 | */ 9 | 10 | /** 11 | * Functions 12 | * ========= 13 | * 14 | * HTML writing functions 15 | * ---------------------- 16 | * 17 | * - HTML(context) 18 | * Creates a HTML string. 19 | * 20 | * Lazy Loading functions 21 | * ---------------------- 22 | * 23 | * - HTML.load(file0, file1, ...).done(fn) 24 | * 25 | * Loads (.js, .css) files in sequence, then execute the done function. 26 | * The files are downloaded asyncronously. 27 | * Each file is only loaded once. 28 | * The done function is executed once per load call, 29 | * irregardless of whether the files are already loaded. 30 | * 31 | * The files are treated accordingly by their file extension. 32 | * To force a file to be treated like a file extension, prefix it with 33 | * `js:` or `css:` (whitespace is around the `:` is ignored): 34 | * 35 | * `js: http://website.com/files?name=mainjs` 36 | * 37 | * Hash routing functions 38 | * ---------------------- 39 | * 40 | * - HTML.route("#path/to/page/anchor", fn) 41 | * 42 | * Attaches the function to "#path/to/page/anchor". 43 | * 44 | * - HTML.route.go(#path/to/page/anchor") 45 | * 46 | * Executes the function attached to "#path/to/page/anchor". 47 | * 48 | * - HTML.route.go(#path/to/page/:anchor") 49 | * 50 | * Attemps to execute the function attached to the path. 51 | * If the visitor has visited "#path/to/page/one", 52 | * or the address bar points to "#path/to/page/one", 53 | * it will execute the function attached to "#path/to/page/one". 54 | * Otherwise, it will execute the function attached to 55 | * "#path/to/page/anchor". 56 | * 57 | * - HTML.route.go("#:path/:to/:page") 58 | * 59 | * You can prefix any path component with ":" to mark it 60 | * as the default fallback. 61 | * 62 | * - HTML.route.go() 63 | * 64 | * Attempts to execute the function attached to the path in 65 | * the address bar. 66 | * 67 | * HTML context example 68 | * ==================== 69 | * 70 | * HTML(["div", {id: "y", class: "a b", style: {color: "red"}, ariaLabel: "x"}, 71 | * "Text", 72 | * ["a", {href: "example.com", target: "_blank"}, "link"], 73 | * {style: {width: 1, opacity: 0.5}, class: "c", pos: 1}, 74 | * [["div", 0], ["div", 1]] 75 | * ]) 76 | * 77 | * Turns into: 78 | * 79 | *
81 | * Text 82 | * link 83 | *
0
1
84 | *
85 | * 86 | * - If the starting element is a string, it is treated as a tag name. 87 | * 88 | * ['div', 'Text'] =>
Text
89 | * 90 | * - Attributes are added via objects. 91 | * The object can be anywhere in the array except for 92 | * the starting element. 93 | * You can use any preferred style: 94 | * 95 | * ['div', {id: 'x'}, 'a', 'b', 'c'] OR 96 | * ['div', 'a', 'b', 'c', {id: 'x'}] 97 | * 98 | * - Attributes can be defined via camelCase. 99 | * They will automatically converted to kebab-case and snake_case. 100 | * This is so that you can avoid using quotes on the keys. 101 | * 102 | * {ariaLabel: "x"} => aria-label="x" 103 | * 104 | * - If the starting element is an array, the contents of the entire 105 | * array will be converted to HTML and joined. 106 | * 107 | * [['div', 0], ['div', 1]] =>
0
1
108 | * 109 | * - Inline css can be defined via objects. 110 | * They will be combined in sequential order. 111 | * CSS will be auto-prefixed. 112 | * For applicable numericl units, 'px' will be automatically added 113 | * if a number is given. (similar to jQuery). 114 | * 115 | * Tips 116 | * ==== 117 | * 118 | * - You can make functions to return html contexts, 119 | * enabling you to reuse common html. Write less, do more! 120 | * 121 | * - You can add attributes or children to contexts to 122 | * specialize them. 123 | * 124 | * - HTML contexts are syntax-highlighted by most js editors 125 | * without addons. Helps you code easily and make lesser errors. 126 | * 127 | * - HTML contexts are efficiently parsed by js engines. 128 | * Minimal processing overhead compared to conventional templates. 129 | * 130 | * - Syntax errors are automatically detected by js engines 131 | * when the js is compiled. 132 | * Check the console for the line of the error if your page 133 | * has display errors. 134 | * 135 | * - No need for transpilers and complicated build tools. 136 | * A browser and text editor is all you need. 137 | * Get up to speed quick! 138 | * 139 | * - Think of HTML.js as a simple, well-made kitchen knife: 140 | * Barebones, lightweight, flexible. 141 | * 142 | * With a little practice, 143 | * you'll find that it is often more than capable of 144 | * doing stuff the big frameworks can do. 145 | * 146 | * Less than 5kb minified + gzipped, 147 | * but gives you the power to create complex Single-Page-Apps 148 | * in a clean and efficient manner. 149 | * 150 | * As long you are clear on which parts of the DOM to modify directly, 151 | * you should be good to go. 152 | * 153 | * SVG 154 | * === 155 | * 156 | * SVG writing functions 157 | * --------------------- 158 | * 159 | * - HTML.SVG(width, height, ...context) 160 | * Creates a HTML SVG string, 161 | * with common boilerplate attributes automatically-filled. 162 | * 163 | * - HTML.SVG.Path(...context) 164 | * .(...) 165 | * .(...) 166 | * Creates an HTML SVG Path string. 167 | * See (https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths) 168 | * for a tutorial on the path commands. 169 | * 170 | * SVG context example 171 | * ------------------- 172 | * 173 | * var SVG = HTML.SVG, P = HTML.SVG.Path; 174 | * HTML(SVG(30, 30, 175 | * ['circle', {class:'frame', cx: 15, cy: 15, r: 12}], 176 | * P({class: 'hand hour'}).M(15,15).L(20,15), 177 | * P({class: 'hand minute'}).M(15,15).L(15,2), 178 | * P().M(0,0).L(1,1) 179 | * P.M(0,0).L(1,1) // path can be also be called without args 180 | * )) 181 | * => 182 | * 183 | * HTML(['svg', {xmlns:'http://www.w3.org/2000/svg', 184 | * width:'30px', height:'30px', viewBox:'0 0 30 30'}, 185 | * ['circle', {class:'frame', cx:15, cy:15, r:12}], 186 | * ['path', {class:'hand hour', d:'M15,15 L20,15'}], 187 | * ['path', {class:'hand minute', d:'M15,15 L15,2'}], 188 | * ['path', {d:'M0,0 L1,1'}], 189 | * ['path', {d:'M0,0 L1,1'}], 190 | * ]) 191 | * => 192 | * 193 | * 195 | * 196 | * 197 | * 198 | * 199 | * 200 | * 201 | */ 202 | ( function( global, factory ) { 203 | 204 | "use strict"; 205 | 206 | if ( typeof module === "object" && typeof module.exports === "object" ) { 207 | module.exports = factory(global, 1); 208 | } else { 209 | factory(global); 210 | } 211 | 212 | } )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { 213 | 214 | "use strict"; 215 | 216 | var document = window.document; 217 | var gcs = function (x) { return window.getComputedStyle(x) }; 218 | var isUndefined = function (x) { return typeof(x) == 'undefined'; }; 219 | 220 | var noBrowser = isUndefined(document); 221 | 222 | var toSet = function (s) { 223 | for (var d = {}, i = (s = s.split(',')).length; i--;) d[s[i]] = 1; 224 | return d; 225 | }; 226 | var cssNumber = toSet('column-count,fill-opacity,font-weight,line-height,opacity,orphans,widows,z-index,zoom'); 227 | var emptyTags = toSet('area,base,br,col,embed,hr,img,input,keygen,link,meta,param,source,track,wbr'); 228 | 229 | var cssBracketRe = /((?:\\.|("|')(?:\\.|.)*?\2|[^{}])*)([{}])/g; 230 | var cssPropRe = /(?:^|\{|\s|;)([A-Za-z0-9\-]+)\s*\:\s*?((?:\\.|("|')(?:\\.|.)*?\3|[^;}])*)/g; 231 | var cssUrlRe = /url\(\s*?["']?(.*?)["']?\s*?\)/g; 232 | var cssAbsUrlRe = /^\s*?(data\:|.{1,6}\:\/\/)/; 233 | var cssCommentRe = /\/\*[\s\S]*?\*\//g; 234 | var fileExtRe = /\.([A-Za-z0-9]+)(?:[\?#]|$)/; 235 | var filePreExtRe = /^(?:\s*?(js|css)\s*?\:)?\s*?(\S[\S\s]*)/i; 236 | var stringTrimRe = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g; 237 | var splitWordsRe = /(?:(?:^|[A-Z])[a-z]+|[0-9]+|[A-Za-z]+)/g; 238 | 239 | var locationPathPopRe = /((^|\/)[^\/]*)$/; 240 | var htmlTagRe = /^[\w]+$/; 241 | 242 | var noop = function (x) { return x; }; 243 | var head = noBrowser ? noop : document.head; 244 | 245 | var splitWords = function (s) { 246 | for (var a = [], m; m = splitWordsRe.exec(s);) a.push(m[0]); 247 | return a; 248 | }; 249 | var populateCaseVariations = function (o) { 250 | var d = {}, k, w, v; 251 | for (k in o) { 252 | v = o[k]; 253 | if ((w = splitWords(k)).length > 1) { 254 | d[w.join('-').toLowerCase()] = d[w.join('_').toLowerCase()] = v; 255 | } 256 | d[k] = v; 257 | } 258 | return d; 259 | }; 260 | var isT = function (s) { return (function (x) { 261 | return x && Object.prototype.toString.call(x) == '[object '+s+']' }) }; 262 | var isArray = isT('Array'); 263 | var isObject = isT('Object'); 264 | var isFunction = isT('Function'); 265 | var trim = function (s) { return String.prototype.trim ? s.trim() : s.replace(stringTrimRe, ''); }; 266 | 267 | 268 | var styles = noBrowser ? [] : gcs(document.documentElement, null); 269 | var cssTester = noBrowser ? [] : document.createElement('div').style; 270 | var cssPropsList = []; 271 | var cssProps = {}, bestPrefix = '', bestPrefixCount = 0; 272 | 273 | // CSS Prefixing via PrefixFree. (https://leaverou.github.io/prefixfree) 274 | 275 | // Modifications: 276 | // 277 | // Instead of a whitelist of stuff to prefix, we just blacklist 278 | // all the css props that we know that doesn't need prefixing. 279 | // This makes a safer approach that enables stuff like 280 | // -webikit-filter to work in old Safari. 281 | // 282 | // We also parse the css bracket by bracket, instead of using 283 | // single regex replace. 284 | // This is for selectors like i:hover which can be confused as a property. 285 | 286 | // NOTE: CSS prefixing is by default OFF for non browser environments (e.g. node). 287 | // To turn it on, change the following line. 288 | // Currently, only prefixing properties with all prefixes is supported 289 | // for non-browser environments. 290 | 291 | var prefixWithoutBrowser = false; 292 | var cssPrefixes = toSet('-webkit-,-moz-,-ms-,-o-'); 293 | if (!prefixWithoutBrowser && noBrowser) 294 | cssPrefixes = {}; 295 | 296 | if (styles && styles.length > 0) { 297 | cssPropsList = styles; 298 | } else { 299 | var re = /[A-Z]/g, p, f = function(x) { return '-' + x.toLowerCase() }; 300 | for (p in styles) cssPropsList.push(p.replace(re, f)); 301 | } 302 | for (var j = 0, i, p, s, o, pf; j < 2; ++j) { 303 | for (i = cssPropsList.length; i--;) { 304 | p = cssPropsList[i].split('-'); 305 | if (j < 1 && p[0] != '') { 306 | for (; p.length >= 1; p.pop()) { 307 | for (s = p[0], o = 1; o < p.length; ++o) 308 | s += p[o][0].toUpperCase() + p[o].substring(1); 309 | if (s in cssTester) cssProps[p.join('-')] = 1; 310 | } 311 | } else if (j < 2 && p[0] == '') { 312 | pf = '-'+p[1]+'-'; 313 | if (cssPrefixes[pf]) { 314 | for (p = p.slice(2); p.length >= 1; p.pop()) { 315 | delete cssProps[p.join('-')]; 316 | } 317 | cssPrefixes[pf]++; 318 | } 319 | } 320 | } 321 | } 322 | for (var pf in cssPrefixes) { 323 | if (cssPrefixes[pf] > bestPrefixCount) { 324 | bestPrefixCount = cssPrefixes[pf]; 325 | bestPrefix = pf; 326 | } 327 | } 328 | 329 | var getCSSFixer = function (what, before, after, replacement) { 330 | var re = RegExp(before + '(' + what.join('|') + ')' + after, 'g'); 331 | return function (css) { 332 | return what.length ? css.replace(re, replacement) : css; 333 | } 334 | }; 335 | 336 | var fixCSSFunctions = noBrowser ? noop : (function () { 337 | var bgi = 'backgroundImage', gradient = '-gradient'; // for better compression lol 338 | var cu = 'cursor', di = 'display', wi = 'width'; 339 | var functions = [], keywords = [], t; 340 | 341 | var functionsTests = { 342 | 'calc': [wi, '1px + 5%'], 343 | 'element': [bgi, '#foo'], 344 | 'cross-fade': [bgi, 'url(a.png), url(b.png), 50%'], 345 | 'image-set': [bgi, 'url(a.png) 1x, url(b.png) 2x'] 346 | }; 347 | functionsTests['repeating-linear'+gradient] = 348 | functionsTests['repeating-radial'+gradient] = 349 | functionsTests['radial'+gradient] = 350 | functionsTests['linear'+gradient] = [bgi, 'red, teal']; 351 | 352 | var supported = function (value, property) { 353 | cssTester[property] = ''; 354 | cssTester[property] = value; 355 | return !!cssTester[property]; 356 | }; 357 | 358 | for (t in functionsTests) { 359 | var test = functionsTests[t], property = test[0], value = t + '(' + test[1] + ')'; 360 | if (!supported(value, property) && supported(bestPrefix + value, property)) { 361 | // It's supported, but with a prefix 362 | functions.push(t); 363 | } 364 | } 365 | var functionsFix = getCSSFixer(functions, '(\\s|:|,)', '\\s*\\(', '$1' + bestPrefix + '$2('); 366 | 367 | var keywordsTests = { 368 | 'initial': 'color', 369 | 'grab': cu, 370 | 'grabbing': cu, 371 | 'zoom-in': cu, 372 | 'zoom-out': cu, 373 | 'box': di, 374 | 'flexbox': di, 375 | 'inline-flexbox': di, 376 | 'flex': di, 377 | 'inline-flex': di, 378 | 'grid': di, 379 | 'inline-grid': di, 380 | 'max-content': wi, 381 | 'min-content': wi, 382 | 'fit-content': wi, 383 | 'fill-available': wi, 384 | 'contain-floats': wi 385 | }; 386 | for (t in keywordsTests) { 387 | var property = keywordsTests[t]; 388 | if (!supported(t, property) && supported(bestPrefix + t, property)) { 389 | // It's supported, but with a prefix 390 | keywords.push(t); 391 | } 392 | } 393 | var keywordsFix = getCSSFixer(keywords, '(\\s|:)', '(\\s|;|\\}|$)', '$1' + bestPrefix + '$2$3'); 394 | 395 | return function (css) { 396 | for (var i = functions.length, lg = 'linear-gradient'; i--; ) if (functions[i] == lg) { 397 | // Gradients are supported with a prefix, convert angles to legacy 398 | css = css.replace(/(\s|:|,)(repeating-)?linear-gradient\(\s*(-?\d*\.?\d*)deg/ig, 399 | function ($0, delim, repeating, deg) { 400 | return delim + (repeating || '') + lg + '(' + (90-deg) + 'deg'; 401 | }); 402 | i = 0; 403 | } 404 | css = functionsFix(css); 405 | css = keywordsFix(css); 406 | return css; 407 | }; 408 | })(); 409 | 410 | var fixCSSSelectors = noBrowser ? noop : (function () { 411 | var selectors = [], atrules = []; 412 | var pl = ':placeholder'; 413 | var selectorsTests = { 414 | ':any-link': 0, 415 | '::backdrop': 0, 416 | ':fullscreen': 0, 417 | ':full-screen': ':fullscreen', 418 | //sigh 419 | '::placeholder': 0, 420 | ':placeholder': pl + '-shown', 421 | '::input-placeholder': ':' + pl, 422 | ':input-placeholder': pl + '-shown', 423 | ':read-only': 0, 424 | ':read-write': 0, 425 | '::selection': 0 426 | }; 427 | var atrulesTests = { 428 | 'keyframes': 'name', 429 | 'viewport': 0, 430 | 'document': 'regexp(".")' 431 | }; 432 | 433 | var selectorMap = {}, t, test; 434 | var style = head.appendChild(document.createElement('style')); 435 | 436 | var supported = function (selector) { 437 | style.textContent = selector + '{}'; // Safari 4 has issues with style.innerHTML 438 | return !!style.sheet.cssRules.length; 439 | }; 440 | 441 | 442 | for (t in selectorsTests) { 443 | var standard = selectorsTests[t] || t; 444 | var prefixed = t.replace(/::?/, function($0) { return $0 + bestPrefix }) 445 | if(!supported(standard) && supported(prefixed)) { 446 | selectors.push(standard); 447 | selectorMap[standard] = prefixed; 448 | } 449 | } 450 | 451 | for (t in atrulesTests) { 452 | test = t + ' ' + (atrulesTests[t] || ''); 453 | if(!supported('@' + test) && supported('@' + bestPrefix + test)) { 454 | atrules.push(t); 455 | } 456 | } 457 | var selectorsFix = getCSSFixer(selectors, '', '\\b', function (selector) { 458 | return selectorMap[selector] || selector; 459 | }); 460 | var atrulesFix = getCSSFixer(atrules, '@', '\\b', '@' + bestPrefix + '$1'); 461 | 462 | head.removeChild(style); 463 | 464 | return function (css) { 465 | return atrulesFix(selectorsFix(css)); 466 | }; 467 | })(); 468 | 469 | var autoFixCSS = function (css) { 470 | 471 | var af, k, v, r = '', sc = 0, mSub, m, pf, k, af; 472 | if (isObject(css)) { 473 | af = {}; 474 | for (k in css) if (css.hasOwnProperty(k)) { 475 | v = css[k]; 476 | k = trim(k); 477 | if (typeof(v) == 'number' && !cssNumber[k]) { 478 | v += 'px'; 479 | } 480 | v = fixCSSFunctions(v); 481 | if (!(cssProps[k])) { 482 | for (pf in cssPrefixes) { 483 | af[pf + k] = v; 484 | } 485 | } 486 | af[k] = v; 487 | } 488 | return af; 489 | } 490 | 491 | css = css.replace(cssCommentRe, ''); 492 | // Yup, we parse it bracket to bracket! 493 | while (m = cssBracketRe.exec(css)) { 494 | var padding = '', prettify = 0, b = m[3], j; 495 | if (prettify) for (j = sc; j--;) padding += '\t'; 496 | if (b == '{') { 497 | r += (prettify ? '\n' + padding : '') + m[1] + (prettify ? ' ' : '') + b; 498 | ++sc; 499 | } else if (b == '}') { 500 | if (prettify) padding = padding.substring(1); 501 | af = {}; 502 | while (mSub = cssPropRe.exec(m[1])) { 503 | if (!(cssProps[mSub[1]])) { 504 | for (pf in cssPrefixes) { 505 | af[pf + mSub[1]] = mSub[2]; 506 | } 507 | } 508 | af[mSub[1]] = mSub[2]; 509 | } 510 | for (k in af) { 511 | r += (prettify ? '\n' + padding + '\t' : '') + k + ':' + af[k] + ';'; 512 | } 513 | r += (prettify ? '\n' + padding : '') + b + (prettify ? '\n' : ''); 514 | sc = sc > 0 ? sc - 1 : 0; 515 | } 516 | } 517 | return fixCSSSelectors(fixCSSFunctions(r)); 518 | }; 519 | 520 | var loadedFiles = {}; 521 | 522 | var fixCSSRelUrls = function (url, css) { 523 | url = trim(url); 524 | if (url[0] != '/') { 525 | url = window.location.pathname.replace(locationPathPopRe, '') + '/' + url; 526 | } 527 | url = url.replace(locationPathPopRe, ''); 528 | return css.replace(cssUrlRe, function (x, g) { 529 | if (g.match(cssAbsUrlRe)) return x; 530 | var urlComps = url.split('/'), cssURLComps = g.split('/'), i; 531 | for (i = 0; i < cssURLComps.length; ++i) { 532 | if (cssURLComps[i] == '..') urlComps.pop(); 533 | else urlComps.push(cssURLComps[i]); 534 | } 535 | return 'url(\'' + urlComps.join('/') + '\')'; 536 | }); 537 | } 538 | 539 | var fileReadyChecker = function (xhr, i, urlMatch, ctl) { 540 | return function() { 541 | 542 | if (xhr.readyState == 4) { 543 | var status = xhr.status, responseText = ''; 544 | var lastModified = xhr.getResponseHeader('Last-Modified'); 545 | if (status >= 200 && status < 300) { 546 | loadedFiles[urlMatch[0]] = [ 547 | lastModified, 548 | responseText = xhr.responseText 549 | ]; 550 | } else if (status == 304) { 551 | responseText = loadedFiles[urlMatch[0]][1] 552 | } 553 | ctl.push([i, urlMatch, responseText]); 554 | } 555 | ctl.c(); 556 | }; 557 | }; 558 | var imageReadyChecker = function (img, i, urlMatch, ctl) { 559 | return function () { 560 | var x = [i, urlMatch, ''], p = function () { 561 | ctl.push(x); 562 | ctl.c(); 563 | }; 564 | if (img.naturalWidth) { 565 | p(); 566 | } else { 567 | setTimeout(p, 100); 568 | } 569 | }; 570 | }; 571 | 572 | var loadFiles = function (urls) { 573 | var required = [], i, r, s, xhr, m, t, img, 574 | ctl = [], ctlWrap = { 575 | done: function (f) { 576 | ctl.d = isFunction(f) ? f : noop; 577 | return ctlWrap; 578 | } 579 | }, imageExtensions = toSet('png,bmp,gif,jpg,jpeg,svg,webp'); 580 | ctl.c = function () { 581 | if (ctl.length == ctl.n && ctl.n) { 582 | ctl.n = 0; 583 | ctl.sort(function (a, b) { return a[0] - b[0]; }); 584 | var j, r, m, el, t, url; 585 | for (j = 0; j < ctl.length; ++j) { 586 | r = ctl[j], t = r[1][1], url = r[1][2]; 587 | if (!t && (m = url.match(fileExtRe))) 588 | t = m[1].toLowerCase(); 589 | if (t == 'css') { 590 | el = document.createElement('style'); 591 | el.type = 'text/css'; 592 | el.innerText = autoFixCSS(fixCSSRelUrls(url, r[2]).replace(/[\r\n]/g, '')); 593 | head.appendChild(el); 594 | } 595 | if (t == 'js') { 596 | el = document.createElement('script'); 597 | // Allows easier debugging. 598 | el.text = '//# sourceURL=' + url + '\n' + r[2]; 599 | head.appendChild(el).parentNode.removeChild(el); 600 | } 601 | } 602 | 603 | ctl.d(); 604 | } 605 | }; 606 | ctl.d = noop; 607 | for (i = 0; i < urls.length; ++i) { 608 | m = filePreExtRe.exec(urls[i]); 609 | m[0] = (isUndefined(m[1]) ? '' : m[1]) + ':' + m[2]; 610 | required.push(m); 611 | } 612 | ctl.n = required.length; 613 | for (i = 0; i < ctl.n; ++i) { 614 | r = required[i]; 615 | if ((''+r[1]).toLowerCase() == 'img' || 616 | ((m = (''+r[2]).match(fileExtRe)) && imageExtensions[m[1].toLowerCase()])) { 617 | img = new Image(); 618 | img.onload = img.onerror = imageReadyChecker(img, i, r, ctl); 619 | img.src = r[2]; 620 | } else { 621 | xhr = new XMLHttpRequest(); 622 | xhr.onreadystatechange = fileReadyChecker(xhr, i, r, ctl); 623 | s = r[2].indexOf('?') > -1 ? '&' : '?'; 624 | xhr.open('GET', r[2] + s + Math.random(), 1); 625 | if (s = loadedFiles[r[0]]) { 626 | xhr.setRequestHeader('If-Modified-Since', s[0]); 627 | } 628 | xhr.responseType = 'text'; 629 | xhr.send(); 630 | } 631 | } 632 | if (!ctl.n) { 633 | setTimeout(ctl.d, 10); 634 | } 635 | return ctlWrap; 636 | }; 637 | 638 | var collectLeafs = function (a, collected) { 639 | for (var i = 0; i < a.length; i++) { 640 | if (isArray(a[i])) { 641 | collectLeafs(a[i], collected) 642 | } else { 643 | collected.push(a[i]); 644 | } 645 | } 646 | }; 647 | 648 | var load = function () { 649 | var urls = []; 650 | collectLeafs(arguments, urls); 651 | return loadFiles(urls); 652 | }; 653 | 654 | var mapNext = function (context, i) { 655 | var v = context[i].slice(), j, o = i + 1, n = v.length, r = ''; 656 | for (o = i + 1; isFunction(context[o]); ++o) 657 | for (j = 0; j < n; ++j) 658 | v[j] = context[o](v[j], j); 659 | for (j = 0; j < n; ++j) 660 | r += HTML(v[j]); 661 | return {r: r, i: o - 1}; 662 | }; 663 | 664 | var isUndefinedOrNull = function (x) { return isUndefined(x) || x === null; }; 665 | 666 | var HTML = function(context) { 667 | 668 | if (isUndefinedOrNull(context)) return ''; 669 | 670 | var a = arguments, r, i, obj, k, k2, t, v, css, mSub, j, mn, sk, skk, f, 671 | content = '', attrs = {}; 672 | 673 | if (a.length > 1) { 674 | for (content = [], i = 0; i < a.length; ++i) 675 | content.push(a[i]); 676 | return HTML(content); 677 | } 678 | 679 | if (!isArray(context)) return '' + context; 680 | 681 | var n = context.length, tag = context[0] + ''; 682 | 683 | if (!n) return ''; 684 | 685 | if (n && (isArray(context[0]) || isUndefinedOrNull(context[0]) || !tag.match(htmlTagRe))) { 686 | for (r = '', i = 0; i < n; i++) { 687 | if (isFunction(context[i+1])) { 688 | mn = mapNext(context, i); 689 | r += mn.r; 690 | i = mn.i; 691 | } else { 692 | r += HTML(context[i]); 693 | } 694 | 695 | } 696 | return r; 697 | } 698 | 699 | for (i = 1; i < n; i++) if (!isUndefinedOrNull(context[i])) { 700 | obj = context[i]; 701 | if (isArray(obj)) { 702 | if (isFunction(context[i+1])) { 703 | mn = mapNext(context, i); 704 | content += mn.r; 705 | i = mn.i; 706 | } else { 707 | content += HTML(obj); 708 | } 709 | } else if (isObject(obj)) { 710 | for (k in obj) { 711 | v = obj[k]; 712 | t = trim(k).toLowerCase(); 713 | if (t == 'style' && !isObject(v)) { 714 | v += ''; 715 | css = {}; 716 | while (mSub = cssPropRe.exec(v)) 717 | css[mSub[1]] = mSub[2]; 718 | v = css; 719 | } 720 | if (obj.hasOwnProperty(k) && !isUndefinedOrNull(v)) { 721 | if (isObject(v)) { 722 | if (!attrs.hasOwnProperty(k) || !isObject(attrs[k])) 723 | attrs[k] = {}; 724 | for (k2 in v) if (v.hasOwnProperty(k2)) 725 | attrs[k][k2] = v[k2]; 726 | } else { 727 | if (t != 'class' || !attrs.hasOwnProperty(k)) 728 | attrs[k] = v; 729 | else 730 | attrs[k] += ' ' + v; 731 | } 732 | } 733 | } 734 | } else if (!isUndefinedOrNull(obj)) { 735 | content += obj; 736 | } 737 | } 738 | r = '<' + tag; 739 | attrs = populateCaseVariations(attrs); 740 | v = Object.keys; 741 | sk = v(attrs).sort(); 742 | for (i = 0; i < sk.length; ++i) { 743 | k = sk[i]; 744 | t = ''; 745 | f = 1; 746 | if (isObject(attrs[k])) { // css case 747 | css = autoFixCSS(attrs[k]); 748 | skk = v(css).sort(); 749 | for (j = 0; j < skk.length; ++j) { 750 | k2 = skk[j] 751 | t += k2 + ':' + css[k2] + ';'; 752 | } 753 | } else if (isArray(attrs[k])) { 754 | for (j = 0; f && j < attrs[k].length; ++j) { 755 | if (attrs[k][j]) { 756 | r += ' ' + k; 757 | f = 0; 758 | } 759 | } 760 | f = 0; 761 | } else { 762 | t += attrs[k]; 763 | } 764 | if (f) 765 | r += ' ' + k + '="' + HTML.escape(t) + '"'; 766 | } 767 | 768 | if (emptyTags[trim(tag).toLowerCase()] && !content) 769 | r += '>'; 770 | else 771 | r += '>' + content + ''; 772 | return r; 773 | }; 774 | 775 | HTML.bool = function (name, isTrue) { 776 | var attrs = {}; 777 | if (isTrue) attrs[name] = name; 778 | return attrs; 779 | }; 780 | 781 | HTML.hash = function () { 782 | var s, a = arguments, h = 0, i, j; 783 | for (j = 0; j < a.length; ++j) { 784 | for (s = HTML(a[j]), i = 0; i < s.length; ++i) { 785 | h = (((h << 5) - h) + s.charCodeAt(i)) | 0; 786 | } 787 | } 788 | return h; 789 | }; 790 | 791 | var htmlEscapeChars = { 792 | '&': '&', 793 | '<': '<', 794 | '>': '>', 795 | '"': '"', 796 | "'": ''' 797 | }, 798 | htmlEscapeRe = /[&<>"']/g, 799 | htmlEscapeFunc = function(m) { return htmlEscapeChars[m] }; 800 | 801 | HTML.escape = function(text) { 802 | return text.replace(htmlEscapeRe, htmlEscapeFunc); 803 | }; 804 | 805 | HTML.SVG = function(width, height) { 806 | var a = arguments, s = ['svg', { 807 | width: width + 'px', 808 | height: height + 'px', 809 | viewBox: '0 0 ' + width + ' ' + height, 810 | xmlns: 'http://www.w3.org/2000/svg'}], i; 811 | for (i = 2; i < a.length; i++) { 812 | s.push(a[i]); 813 | } 814 | return s; 815 | }; 816 | 817 | var svgCmds = 'mlhvcsqtaz'; 818 | svgCmds = toSet((svgCmds + svgCmds.toUpperCase()).split('').join(',')); 819 | 820 | var svgPath = function () { 821 | var attrs = {d:''}, path = ['path', attrs], a = arguments, i, p, k, 822 | P = function (command) { 823 | return function() { 824 | attrs.d += command; 825 | for (var a = arguments, j = 0; j < a.length; ++j) 826 | attrs.d += a[j] + ', '[j&1]; 827 | return path; 828 | }; 829 | }; 830 | for (i = 0; i < a.length; i++) { 831 | if (isObject(p = a[i])) { 832 | p = {}; 833 | for (k in a[i]) { 834 | if (k == 'd') { 835 | attrs.d += a[i][k] + ' '; 836 | } else { 837 | p[k] = a[i][k]; 838 | } 839 | } 840 | } 841 | path.push(p); 842 | } 843 | for (k in svgCmds) 844 | path[k] = P(k); 845 | return path 846 | }; 847 | var svgPathAppender = function (c) { 848 | return function () { return svgPath()[c].apply(null, arguments); }; 849 | }; 850 | for (var c in svgCmds) 851 | svgPath[c] = svgPathAppender(c); 852 | 853 | HTML.SVG.Path = svgPath; 854 | 855 | var onceDones = {}; 856 | var once = function (k, t, f) { 857 | if (onceDones[k]) { 858 | if (isFunction(f)) f(); 859 | return false; 860 | } else { 861 | onceDones[k] = 1; 862 | if (isFunction(t)) t(); 863 | } 864 | return true; 865 | }; 866 | once.clear = function (k) { 867 | delete onceDones[k]; 868 | return once; 869 | }; 870 | HTML.once = once; 871 | 872 | var hashPopRe = /(?:(^\/)|\/)[^\/]+[\/]*$/; // $1 873 | var hashResolveRe = /^#?\/?|(\/)(?:\.?\/)+|(?:(?!\.\.?)[^\/])+\/\.\.(?:\/|$)|([^\^])\/+$/; 874 | var hashCompsRe = /(?:(^|\/)(:?)([^\/]+))/g; 875 | 876 | var routes = {}, savedRoutes = {}, routesInited = 0, refreshable = 0, visited = []; 877 | 878 | var hashResolve = function (h) { 879 | for (var p, t = 1; t; ) { 880 | p = h; 881 | h = h.replace(hashResolveRe, '$1$2'); 882 | t = p != h; 883 | } 884 | return h; 885 | }; 886 | var setVisited = function (p) { 887 | if (visited.length < 1) { 888 | setTimeout(function () { 889 | visited = []; 890 | }, 60); 891 | } 892 | visited.push(p); 893 | } 894 | 895 | //HTML.hashResolve = hashResolve; 896 | var execRoute = function (h, s) { 897 | var p = '', j, c, m, a = hashResolve(h), t = h.length; 898 | while (m = hashCompsRe.exec(a)) { 899 | p += m[1]; 900 | c = m[3]; 901 | if (m[2] && (j = savedRoutes[p])) 902 | c = j; 903 | if (!s) savedRoutes[p] = c; 904 | p += c; 905 | } 906 | for (j = p; j && t > 0; j = j.replace(hashPopRe, '$1')) { 907 | if (routes[j]) { 908 | p = j; 909 | j = ''; 910 | } 911 | --t; 912 | } 913 | if (!s && isFunction(c = routes[p])) { 914 | if (visited.indexOf(p) < 0) { 915 | setVisited(p); 916 | c(); 917 | } else { 918 | var v = h.replace('/:', '/'); 919 | if (v != h && visited.indexOf(v) < 0) { 920 | execRoute(v); 921 | } 922 | } 923 | } 924 | return p; 925 | }; 926 | 927 | var wlh = function () { return window.location.hash; }; 928 | 929 | var setupHashChange = function () { 930 | if (routesInited) return; 931 | routesInited = 1; 932 | var a = hashResolve(wlh()), p = '', t, r, m, 933 | c, i, storedHash, h, ael = 'addEventListener', 934 | clickCallback = function (e) { 935 | for (t = refreshable && e.target; t; t = t.parentElement) 936 | if (t.tagName.toUpperCase()=='A' && 937 | (r=t.getAttribute('href')) && 938 | (r=(''+r).match('#(.*)')) && 939 | (r=execRoute(r[1],1)) == execRoute(wlh(),1) && 940 | (r=routes[r])) { r(); return; } 941 | }; 942 | while (m = hashCompsRe.exec(a)) { 943 | p += m[1] + (savedRoutes[p] = m[3]); 944 | } 945 | 946 | if ('onhashchange' in window) { 947 | window[ael]('hashchange', function () { 948 | execRoute(wlh()); 949 | }); 950 | } else { 951 | storedHash = wlh(); 952 | setInterval(function () { 953 | h = wlh(); 954 | if (h != storedHash) { 955 | storedHash = h; 956 | execRoute(storedHash); 957 | } 958 | }, 100); 959 | } 960 | if (document[ael]) { 961 | document[ael]('click', clickCallback, false); 962 | } else { 963 | document.attachEvent('onclick', clickCallback); 964 | } 965 | }; 966 | 967 | if (!noBrowser) { 968 | HTML.autoFixCSS = autoFixCSS; 969 | HTML.load = load; 970 | var rx = function (r, fn) { 971 | setupHashChange(); 972 | if (isUndefined(r)) return hashResolve(wlh()); 973 | if (fn) { 974 | routes[hashResolve(r)] = fn; 975 | // return HTML so that we can chain 976 | // HTML.route('a', fn).route('b', fn) 977 | return HTML; 978 | } 979 | return routes[execRoute(hashResolve(r), 1)]; 980 | }; 981 | 982 | rx.path = function (r) { 983 | return isUndefined(r) ? hashResolve(wlh()): execRoute(r, 1); 984 | } 985 | 986 | rx.go = function (r) { 987 | setupHashChange(); 988 | r = execRoute(isUndefined(r) ? wlh() : r); 989 | return routes[r] ? r : !!0; 990 | }; 991 | 992 | rx.refreshable = function (v) { 993 | setupHashChange(); 994 | if (isUndefined(v)) return !!refreshable; 995 | refreshable = v; 996 | return HTML; 997 | }; 998 | HTML.route = rx; 999 | } 1000 | 1001 | if (!noGlobal) { 1002 | if (isUndefined(window.HTML)) 1003 | window.HTML = HTML; 1004 | var aris = HTML; 1005 | aris.svg = aris.SVG; 1006 | aris.svg.path = aris.svg.Path; 1007 | window.aris = aris; 1008 | } 1009 | return HTML; 1010 | }); -------------------------------------------------------------------------------- /aris.min.js: -------------------------------------------------------------------------------- 1 | !function(n,r){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=r(n,1):r(n)}("undefined"!=typeof window?window:this,function(c,n){"use strict";function l(n){return"undefined"==typeof n}function p(n){for(var r={},e=(n=n[u](","))[j];e--;)r[n[e]]=1;return r}function d(n){return n}function y(n){for(var r,e=[];r=a.exec(n);)e.push(r[0]);return e}function r(r){return function(n){return n&&Object.prototype.toString.call(n)=="[object "+r+"]"}}function w(n){return String.prototype.trim?n.trim():n[v](i,"")}var e,g=c.document,u="split",j="length",$="toLowerCase",v="replace",h="createElement",s="toUpperCase",m="appendChild",S="hasOwnProperty",k="match",t=l(g),x=p("column-count,fill-opacity,font-weight,line-height,opacity,orphans,widows,z-index,zoom"),A=p("area,base,br,col,embed,hr,img,input,keygen,link,meta,param,source,track,wbr"),b=/((?:\\.|("|')(?:\\.|.)*?\2|[^{}])*)([{}])/g,z=/(?:^|\{|\s|;)([A-Za-z0-9\-]+)\s*\:\s*?((?:\\.|("|')(?:\\.|.)*?\3|[^;}])*)/g,o=/url\(\s*?["']?(.*?)["']?\s*?\)/g,f=/^\s*?(data\:|.{1,6}\:\/\/)/,C=/\/\*[\s\S]*?\*\//g,E=/\.([A-Za-z0-9]+)(?:[\?#]|$)/,T=/^(?:\s*?(js|css)\s*?\:)?\s*?(\S[\S\s]*)/i,i=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,a=/(?:(?:^|[A-Z])[a-z]+|[0-9]+|[A-Za-z]+)/g,F=/((^|\/)[^\/]*)$/,L=/^[\w]+$/,O=t?d:g.head,M=r("Array"),R=r("Object"),H=r("Function"),Z=t?[]:(e=g.documentElement,c.getComputedStyle(e)),q=t?[]:g[h]("div").style,G=[],I={},P="",V=0,N=p("-webkit-,-moz-,-ms-,-o-");if(t&&(N={}),Z&&0V&&(V=N[K],P=K);function Q(r,n,e,t){var o=RegExp(n+"("+r.join("|")+")"+e,"g");return function(n){return r[j]?n[v](o,t):n}}function Y(n){var r,e,t,o,i,u,f="",a=0;if(R(n)){for(i in u={},n)if(n[S](i)){if(r=n[i],i=w(i),"number"!=typeof r||x[i]||(r+="px"),r=un(r),!I[i])for(o in N)u[o+i]=r;u[i]=r}return u}for(n=n[v](C,"");t=b.exec(n);){var c=t[3];if("{"==c)f+=""+t[1]+c,++a;else if("}"==c){for(u={};e=z.exec(t[1]);){if(!I[e[1]])for(o in N)u[o+e[1]]=e[2];u[e[1]]=e[2]}for(i in u)f+=i+":"+u[i]+";";f+=""+c,a=0",r};function ln(n){return pn[n]}sn.bool=function(n,r){var e={};return r&&(e[n]=n),e},sn.hash=function(){var n,r,e,t=arguments,o=0;for(e=0;e":">",'"':""","'":"'"},dn=/[&<>"']/g;sn.escape=function(n){return n[v](dn,ln)},sn.SVG=function(n,r){var e,t=arguments,o=["svg",{width:n+"px",height:r+"px",viewBox:"0 0 "+n+" "+r,xmlns:"http://www.w3.org/2000/svg"}];for(e=2;e 2 | 3 | 4 | 5 | 6 | HTML to Aris Converter 7 | 8 | 9 | 10 | 11 | 12 | 383 | 384 | 385 | 386 | 400 | 401 | 402 | 403 | 404 | -------------------------------------------------------------------------------- /logo.svg: -------------------------------------------------------------------------------- 1 | aris 2 | 28 | 30 | 32 | 33 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aris", 3 | "version": "1.0.11", 4 | "description": "Write HTML in JS easily.", 5 | "main": "aris.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/Vectorized/aris.git" 12 | }, 13 | "keywords": [ 14 | "aris", 15 | "html", 16 | "css", 17 | "prefixer", 18 | "generate", 19 | "jsx", 20 | "spa" 21 | ], 22 | "author": "Vectorized", 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/Vectorized/aris/issues" 26 | }, 27 | "homepage": "https://github.com/Vectorized/aris#readme" 28 | } 29 | --------------------------------------------------------------------------------