+1
-1
@@ -1,2 +0,2 @@ | ||
| ((a,b,c,d,e,f,g,h)=>{String.prototype[d]=1,f=(i,j={},...k)=>({[d]:1,E:i,P:j[d]&&k.unshift(j)&&{C:k}||(j.C=k)&&j}),a.R=g=(i,j,k='',l=j.childNodes,m=0)=>{for((i.map?i:[i]).map((n,o,p,q=k+'.'+o,r=e[q]||[{},n.E],s=e[q]=r[1]==n.E?r:[{},n.E],t=l[m++],u)=>{n.E&&n.E.call&&(n=n.E(n.P,s[0],v=>c.assign(s[0],v)&&g(i,j,k))),u=n.trim?b.createTextNode(n):b.createElement(n.E),(u=t?t.E!=n.E&&t.data!=n?j.replaceChild(u,t)&&u:t:j.appendChild(u)).E=n.E,n.trim?u.data=n:c.keys(n.P).map((v,w,x,y=n.P[v])=>'style'==v?c.assign(u[v],y):'C'!=v&&(u[v]=y))&&g(n.P.C,u,q)});l[m];)j.removeChild(l[m])},h=i=>new Proxy(i,{get:(j,k,l)=>h((...m)=>((l=j(...m)).P.className=[l.P.className]+' '+k,l))}),a.H=new Proxy(f,{get:(i,j)=>h(f.bind(a,j))})})(window,document,Object,Symbol(),{}); | ||
| ((a,b,c,d,e,f,g,h)=>{String.prototype[d]=1,f=(i,j={},...k)=>({[d]:1,E:i,P:j[d]?{C:[].concat(j,...k)}:(j.C=[].concat(...k))&&j}),a.R=g=(i,j,k='',l=j.childNodes,m=0)=>{for((i.map?i:[i]).map((n,o,p,q=k+'.'+o,r=e[q]||[{},n.E],s=e[q]=r[1]==n.E?r:[{},n.E],t=l[m++],u)=>{n.E&&n.E.call&&(n=n.E(n.P,s[0],v=>c.assign(s[0],v)&&g(i,j,k))),u=n.trim?b.createTextNode(n):b.createElement(n.E),(u=t?t.E!=n.E&&t.data!=n?j.replaceChild(u,t)&&u:t:j.appendChild(u)).E=n.E,n.trim?u.data=n:c.keys(n.P).map((v)=>'style'==v?c.assign(u[v],n.P[v]):u[v]!==n.P[v]&&(u[v]=n.P[v]))&&g(n.P.C,u,q)});l[m];)j.removeChild(l[m])},h=i=>new Proxy(i,{get:(j,k,l)=>h((...m)=>((l=j(...m)).P.className=[l.P.className]+' '+k,l))}),a.H=new Proxy(f,{get:(i,j)=>i[j]||h(f.bind(a,j))})})(window,document,Object,Symbol(),{}); | ||
+3
-3
| { | ||
| "name": "dot-dom", | ||
| "version": "0.2.1", | ||
| "version": "0.2.2", | ||
| "description": "A tiny (less than 512 byte) template engine that uses virtual DOM and some of react principles", | ||
| "main": "dotdom.min.js", | ||
| "main": "src/dotdom.js", | ||
| "scripts": { | ||
| "test": "./node_modules/.bin/jest", | ||
| "build": "./node_modules/.bin/babili src/dotdom.js | tee dotdom.min.js | gzip -9 > dotdom.min.js.gz" | ||
| "build": "cat src/dotdom.js | perl -0pe 's/BEGIN NPM-GLUE.*END NPM-GLUE//s' | ./node_modules/.bin/babili | tee dotdom.min.js | gzip -9 > dotdom.min.js.gz" | ||
| }, | ||
@@ -10,0 +10,0 @@ "repository": { |
+70
-9
@@ -1,4 +0,4 @@ | ||
| # .dom [](https://travis-ci.org/wavesoft/dot-dom) | ||
| # .dom [](https://travis-ci.org/wavesoft/dot-dom) [](https://codepen.io/anon/pen/YNdNwv?editors=0010) | ||
| > A tiny (510 byte) virtual DOM template engine for embedded projects | ||
| > A tiny (511 byte) virtual DOM template engine for embedded projects | ||
@@ -13,7 +13,18 @@ | <img src="https://raw.githubusercontent.com/godban/browsers-support-badges/master/src/images/edge.png" alt="IE / Edge" width="16px" height="16px" /> IE / Edge | <img src="https://raw.githubusercontent.com/godban/browsers-support-badges/master/src/images/firefox.png" alt="Firefox" width="16px" height="16px" /> Firefox | <img src="https://raw.githubusercontent.com/godban/browsers-support-badges/master/src/images/chrome.png" alt="Chrome" width="16px" height="16px" /> Chrome | <img src="https://raw.githubusercontent.com/godban/browsers-support-badges/master/src/images/safari.png" alt="Safari" width="16px" height="16px" /> Safari | <img src="https://raw.githubusercontent.com/godban/browsers-support-badges/master/src/images/opera.png" alt="Opera" width="16px" height="16px" /> Opera | <img src="https://raw.githubusercontent.com/godban/browsers-support-badges/master/src/images/safari-ios.png" alt="iOS Safari" width="16px" height="16px" /> iOS Safari | <img src="https://raw.githubusercontent.com/godban/browsers-support-badges/master/src/images/chrome-android.png" alt="Chrome for Android" width="16px" height="16px" /> Chrome for Android | | ||
| [Try it in codepen.io](https://codepen.io/anon/pen/YNdNwv?editors=0010) | ||
| ### Features | ||
| * _Tiny by design_ : The library should never exceed the 512 bytes in size. The goal is not to have yet another template engine, but to have as many features as possible in 512 bytes. If a new feature is needed, an other must be sacraficed or the scope must be reduced. | ||
| * _Built for the future_ : The library is heavily exploiting the ES6 specifications, meaning that it's **not** supported by older borwsers. Currently it's supported by the 70% of the browsers in the market, but expect this to be 90% within the next year. | ||
| * _Declarative_ : Describe your HTML DOM in a structured, natural manner, helping you create powerful yet readable user interfaces. | ||
| * _Component-Oriented_ : Just like React.js, **.dom** promotes the use of functional components. | ||
| * _"Write less" accelerators_ : The library API is designed specifically to have short function names and accelerators, allowing you to describe your views with less code. | ||
| ## Installation | ||
| For minimum footprint, include `dotdom.min.js.gz` (510b) to your project. | ||
| For minimum footprint, include `dotdom.min.js.gz` (511b) to your project. | ||
@@ -24,6 +35,6 @@ ```html | ||
| Alternatively you can just include the minified version of the library directly before your script. Just copy-paste the following (755b): | ||
| Alternatively you can just include the minified version of the library directly before your script. Just copy-paste the following (779b): | ||
| ```js | ||
| ((a,b,c,d,e,f,g,h)=>{String.prototype[d]=1,f=(i,j={},...k)=>({[d]:1,E:i,P:j[d]&&k.unshift(j)&&{C:k}||(j.C=k)&&j}),a.R=g=(i,j,k='',l=j.childNodes,m=0)=>{for((i.map?i:[i]).map((n,o,p,q=k+'.'+o,r=e[q]||[{},n.E],s=e[q]=r[1]==n.E?r:[{},n.E],t=l[m++],u)=>{n.E&&n.E.call&&(n=n.E(n.P,s[0],v=>c.assign(s[0],v)&&g(i,j,k))),u=n.trim?b.createTextNode(n):b.createElement(n.E),(u=t?t.E!=n.E&&t.data!=n?j.replaceChild(u,t)&&u:t:j.appendChild(u)).E=n.E,n.trim?u.data=n:c.keys(n.P).map((v,w,x,y=n.P[v])=>'style'==v?c.assign(u[v],y):'C'!=v&&(u[v]=y))&&g(n.P.C,u,q)});l[m];)j.removeChild(l[m])},h=i=>new Proxy(i,{get:(j,k,l)=>h((...m)=>((l=j(...m)).P.className=[l.P.className]+' '+k,l))}),a.H=new Proxy(f,{get:(i,j)=>h(f.bind(a,j))})})(window,document,Object,Symbol(),{}); | ||
| ((a,b,c,d,e,f,g,h)=>{String.prototype[d]=1,f=(i,j={},...k)=>({[d]:1,E:i,P:j[d]?{C:[].concat(j,...k)}:(j.C=[].concat(...k))&&j}),a.R=g=(i,j,k='',l=j.childNodes,m=0)=>{for((i.map?i:[i]).map((n,o,p,q=k+'.'+o,r=e[q]||[{},n.E],s=e[q]=r[1]==n.E?r:[{},n.E],t=l[m++],u)=>{n.E&&n.E.call&&(n=n.E(n.P,s[0],v=>c.assign(s[0],v)&&g(i,j,k))),u=n.trim?b.createTextNode(n):b.createElement(n.E),(u=t?t.E!=n.E&&t.data!=n?j.replaceChild(u,t)&&u:t:j.appendChild(u)).E=n.E,n.trim?u.data=n:c.keys(n.P).map((v)=>'style'==v?c.assign(u[v],n.P[v]):u[v]!==n.P[v]&&(u[v]=n.P[v]))&&g(n.P.C,u,q)});l[m];)j.removeChild(l[m])},h=i=>new Proxy(i,{get:(j,k,l)=>h((...m)=>((l=j(...m)).P.className=[l.P.className]+' '+k,l))}),a.H=new Proxy(f,{get:(i,j)=>i[j]||h(f.bind(a,j))})})(window,document,Object,Symbol(),{}); | ||
| ``` | ||
@@ -204,2 +215,25 @@ | ||
| #### Functional Components | ||
| Instead of a tag name you can provide a function that returns a Virtual DOM | ||
| according to some higher-level logic. Such function have the following signature: | ||
| ```js | ||
| const Component = (props, state, setState) { | ||
| // Return your Virtual DOM | ||
| return div( ... ) | ||
| } | ||
| ``` | ||
| The `props` property contains the properties object as given when the component | ||
| was created. | ||
| The `state` is initialized to an empty object `{}` and it's updated by calling | ||
| the `setState({ newState })` method. The latter will also trigger an update to | ||
| the component and it's children. | ||
| You can also assign properties to the `state` object directly if you don't want | ||
| to cause an update. | ||
| ### Tag Shorthand `tag( [properties], [children ...] )` | ||
@@ -258,5 +292,32 @@ | ||
| 1. *Always explain your code with a comment* : Since you will most probably going to do some extreme javascript corner cases in order to be able to squeeze your logic. | ||
| 2. *All comments should start on column 70 and wrap after column 120* : In order to perserve code-style consistency. | ||
| 3. *The GZipped result should __never__ be bigger than 512 bytes* : Since that's the whole purpose of the library. If you are adding a completely new feature, consider sacraficing another one, or try to reduce scope, in order to keep the balance. | ||
| 1. Install a local development environment (you will need node.js **6.x** or later) | ||
| ``` | ||
| npm install | ||
| ``` | ||
| 2. **Always** run the following when you think you are ready for a pull request: | ||
| ``` | ||
| npm test && npm run build && ls -l dotdom.min.js.gz | ||
| ``` | ||
| 3. If tests pass and the size of `dotdom.min.js.gz` is smaller than or equal to 512 bytes, create a pull request. Otherwise reduce your scope or think of another implementation in order to bring it back down to 512 bytes. | ||
| 4. Make sure to properly comments your code, since you will most probably have to do some extreme javascript hacking. The gudeliens are the following: | ||
| ```js | ||
| /** | ||
| * Functions are commented as JSDoc blocks | ||
| * | ||
| * @param {VNode|Array<VNode>} vnodes - The node on an array of nodes to render | ||
| * ... | ||
| */ | ||
| global.R = render = ( | ||
| vnodes, // Flat-code comments start on column 70 and | ||
| dom, // wrap after column 120. | ||
| /* Logical separations can be commented like this */ | ||
| ... | ||
| ``` |
+119
-50
@@ -1,3 +0,2 @@ | ||
| require('../dotdom'); | ||
| const dd = window; | ||
| const dd = require('../dotdom'); | ||
@@ -7,65 +6,135 @@ describe('.dom', function () { | ||
| describe('#H', function () { | ||
| it('should create vnode without arguments', function () { | ||
| const vdom = dd.H('div'); | ||
| expect(vdom.E).toEqual('div'); | ||
| expect(vdom.P).toEqual({C: []}); | ||
| }); | ||
| describe('Factory', function () { | ||
| it('should create vnode with props', function () { | ||
| const vdom = dd.H('div', {foo: 'bar'}); | ||
| it('should create vnode without arguments', function () { | ||
| const vdom = dd.H('div'); | ||
| expect(vdom.E).toEqual('div'); | ||
| expect(vdom.P).toEqual({foo: 'bar', C: []}); | ||
| }); | ||
| expect(vdom.E).toEqual('div'); | ||
| expect(vdom.P).toEqual({C: []}); | ||
| }); | ||
| it('should create vnode with props and children', function () { | ||
| const cdom = dd.H('div'); | ||
| const vdom = dd.H('div', {foo: 'bar'}, cdom); | ||
| it('should create vnode with props', function () { | ||
| const vdom = dd.H('div', {foo: 'bar'}); | ||
| expect(vdom.E).toEqual('div'); | ||
| expect(vdom.P).toEqual({ | ||
| foo: 'bar', | ||
| C: [ cdom ] | ||
| expect(vdom.E).toEqual('div'); | ||
| expect(vdom.P).toEqual({foo: 'bar', C: []}); | ||
| }); | ||
| }); | ||
| it('should create vnode with props and mixed children', function () { | ||
| const cdom = dd.H('div'); | ||
| const vdom = dd.H('div', {foo: 'bar'}, 'foo', cdom); | ||
| it('should create vnode with props and children', function () { | ||
| const cdom = dd.H('div'); | ||
| const vdom = dd.H('div', {foo: 'bar'}, cdom); | ||
| expect(vdom.E).toEqual('div'); | ||
| expect(vdom.P).toEqual({ | ||
| foo: 'bar', | ||
| C: [ 'foo', cdom ] | ||
| expect(vdom.E).toEqual('div'); | ||
| expect(vdom.P).toEqual({ | ||
| foo: 'bar', | ||
| C: [ cdom ] | ||
| }); | ||
| }); | ||
| }); | ||
| it('should create vnode with props and string children', function () { | ||
| const vdom = dd.H('div', {foo: 'bar'}, 'foo'); | ||
| it('should create vnode with props and children as array', function () { | ||
| const cdom1 = dd.H('div'); | ||
| const cdom2 = dd.H('div'); | ||
| const cdom3 = dd.H('div'); | ||
| const vdom = dd.H('div', {foo: 'bar'}, cdom1, [cdom2, cdom3]); | ||
| expect(vdom.E).toEqual('div'); | ||
| expect(vdom.P).toEqual({ | ||
| foo: 'bar', | ||
| C: [ 'foo' ] | ||
| expect(vdom.E).toEqual('div'); | ||
| expect(vdom.P).toEqual({ | ||
| foo: 'bar', | ||
| C: [ cdom1, cdom2, cdom3 ] | ||
| }); | ||
| }); | ||
| }); | ||
| it('should create vnode with only child', function () { | ||
| const vdom = dd.H('div', 'foo'); | ||
| it('should create vnode with props and mixed children', function () { | ||
| const cdom = dd.H('div'); | ||
| const vdom = dd.H('div', {foo: 'bar'}, 'foo', cdom); | ||
| expect(vdom.E).toEqual('div'); | ||
| expect(vdom.P).toEqual({ | ||
| C: [ 'foo' ] | ||
| expect(vdom.E).toEqual('div'); | ||
| expect(vdom.P).toEqual({ | ||
| foo: 'bar', | ||
| C: [ 'foo', cdom ] | ||
| }); | ||
| }); | ||
| it('should create vnode with props and string children', function () { | ||
| const vdom = dd.H('div', {foo: 'bar'}, 'foo'); | ||
| expect(vdom.E).toEqual('div'); | ||
| expect(vdom.P).toEqual({ | ||
| foo: 'bar', | ||
| C: [ 'foo' ] | ||
| }); | ||
| }); | ||
| it('should create vnode with only child', function () { | ||
| const vdom = dd.H('div', 'foo'); | ||
| expect(vdom.E).toEqual('div'); | ||
| expect(vdom.P).toEqual({ | ||
| C: [ 'foo' ] | ||
| }); | ||
| }); | ||
| it('should create vnode with children', function () { | ||
| const vdom = dd.H('div', 'foo', 'bar', 'baz'); | ||
| expect(vdom.E).toEqual('div'); | ||
| expect(vdom.P).toEqual({ | ||
| C: [ 'foo', 'bar', 'baz' ] | ||
| }); | ||
| }); | ||
| it('should create vnode with children in arrays', function () { | ||
| const vdom = dd.H('div', 'foo', ['bar', 'baz']); | ||
| expect(vdom.E).toEqual('div'); | ||
| expect(vdom.P).toEqual({ | ||
| C: [ 'foo', 'bar', 'baz' ] | ||
| }); | ||
| }); | ||
| it('should create vnode with only mixed children', function () { | ||
| const cdom = dd.H('div'); | ||
| const vdom = dd.H('div', cdom, 'foo'); | ||
| expect(vdom.E).toEqual('div'); | ||
| expect(vdom.P).toEqual({ | ||
| C: [ cdom, 'foo' ] | ||
| }); | ||
| }); | ||
| }); | ||
| it('should create vnode with only mixed children', function () { | ||
| const cdom = dd.H('div'); | ||
| const vdom = dd.H('div', cdom, 'foo'); | ||
| describe('Proxy', function () { | ||
| expect(vdom.E).toEqual('div'); | ||
| expect(vdom.P).toEqual({ | ||
| C: [ cdom, 'foo' ] | ||
| it('H.apply should be proxied', function () { | ||
| const cdom = dd.H('div'); | ||
| const vdom = dd.H.apply({}, ['div', cdom, 'foo']); | ||
| expect(vdom.E).toEqual('div'); | ||
| expect(vdom.P).toEqual({ | ||
| C: [ cdom, 'foo' ] | ||
| }); | ||
| }); | ||
| it('H.call should be proxied', function () { | ||
| const cdom = dd.H('div'); | ||
| const vdom = dd.H.call({}, 'div', cdom, 'foo'); | ||
| expect(vdom.E).toEqual('div'); | ||
| expect(vdom.P).toEqual({ | ||
| C: [ cdom, 'foo' ] | ||
| }); | ||
| }); | ||
| it('H.tag should be a shorthand', function () { | ||
| const cdom = dd.H('div'); | ||
| const vdom = dd.H.div(cdom, 'foo'); | ||
| expect(vdom.E).toEqual('div'); | ||
| expect(vdom.P).toEqual({ | ||
| C: [ cdom, 'foo' ] | ||
| }); | ||
| }); | ||
| }); | ||
@@ -296,4 +365,4 @@ | ||
| return dd.H('div', | ||
| H(Component), | ||
| H(Component) | ||
| dd.H(Component), | ||
| dd.H(Component) | ||
| ) | ||
@@ -384,4 +453,4 @@ } | ||
| const vdom = dd.H('div', | ||
| H(Component), | ||
| H(Component) | ||
| dd.H(Component), | ||
| dd.H(Component) | ||
| ); | ||
@@ -388,0 +457,0 @@ |
+22
-15
@@ -18,2 +18,14 @@ /** | ||
| */ | ||
| /* BEGIN NPM-GLUE */ | ||
| // This code block will be striped when building the stand-alone version. | ||
| // When using `npm` this exports the correct functions in order to be easily | ||
| // imported in the correct scope, without leaking to the global scope. | ||
| const window = {}; | ||
| module.exports = window; | ||
| /* END NPM-GLUE */ | ||
| ((global, document, Object, vnodeFlag, globalState, createElement, render, wrapClassProxy) => { | ||
@@ -45,4 +57,6 @@ | ||
| P: props[vnodeFlag] // If the props argument is a renderable VNode, | ||
| && children.unshift(props) && {C: children} // ... prepend it to the children | ||
| || (props.C = children) && props // ... otherwise append 'C' to the property | ||
| ? {C: [].concat(props, ...children)} // ... prepend it to the children | ||
| : (props.C = [].concat(...children)) && props // ... otherwise append 'C' to the property | ||
| // the .concat ensures that arrays of children | ||
| // will be flattened into a single array. | ||
| }) | ||
@@ -145,9 +159,3 @@ | ||
| ( | ||
| key, // 1. The property name | ||
| _unused2, // 2. Index is unused | ||
| _unused3, // 3. Array is unused | ||
| _value=vnode.P[key] // a. We cache the property value | ||
| key // 1. The property name | ||
| ) => | ||
@@ -159,8 +167,7 @@ | ||
| _new_dom[key], // '[key]' is shorter than '.style' | ||
| _value | ||
| vnode.P[key] | ||
| ) | ||
| : (key != 'C' && // 'C' is the children, so we skip it | ||
| (_new_dom[key] = _value)) // All properties are applied directly to DOM | ||
| : (_new_dom[key] !== vnode.P[key] && // All properties are applied directly to DOM, as | ||
| (_new_dom[key] = vnode.P[key])) // long as they are different than ther value in the | ||
| // instance. This includes `onXXX` event handlers. | ||
@@ -221,4 +228,4 @@ | ||
| { | ||
| get: (_unused4, tagName) => | ||
| wrapClassProxy( | ||
| get: (targetFn, tagName) => | ||
| targetFn[tagName] || wrapClassProxy( | ||
| createElement.bind(global, tagName) | ||
@@ -225,0 +232,0 @@ ) |
-116
| ((global, document, Object, isvNode, expandTags, createElement, render) => { | ||
| // Make all strings considered child nodes | ||
| String.prototype[isvNode] = 1; | ||
| /** | ||
| * Create a VNode element | ||
| */ | ||
| global.H = createElement = (element, props={}, ...children) => ({ | ||
| [isvNode]: 1, // The isvNode symbol is used by the code | ||
| // in the 'P' property to check if the `props` | ||
| // argument is not an object, but a renderable | ||
| // VNode child | ||
| E: element, // 'E' holds the name or function passed as | ||
| // first argument | ||
| P: props[isvNode] // If the props argument is a renderable VNode, | ||
| && children.unshift(props) && {C: children} // ... prepend it to the children | ||
| || (props.C = children) && props, // ... otherwise append 'C' to the property | ||
| F: children.length && | ||
| children | ||
| .map((child) => child.trim ? {$:child} : child) | ||
| .reduce((prev, next) => prev.N = next) || children[0] | ||
| }) | ||
| /** | ||
| * Render a DOM node | ||
| */ | ||
| render = (vnode, parent, previous={}, _props=vnode.P, _instance=0) => | ||
| _instance = | ||
| vnode.call | ||
| ? render( | ||
| vnode( | ||
| _props, | ||
| previous.S || vnode.S, | ||
| (newState) => | ||
| Object.assign(vnode.S, newState) && | ||
| reconcile( | ||
| vnode, | ||
| parent, | ||
| _instance | ||
| ) | ||
| ) | ||
| ) | ||
| : vnode.$ | ||
| ? document.createTextNode(vnode.$) | ||
| : Object.keys(_props).reduce( | ||
| (instance, key, unused1, unused2, _value=_props[key]) => | ||
| ( | ||
| 'style' == key ? | ||
| Object.assign( | ||
| instance[key], | ||
| _value | ||
| ) | ||
| : /^on/.exec(key) ? | ||
| instance.addEventListener( | ||
| key.substr(2), | ||
| _value | ||
| ) | ||
| : instance.setAttribute( | ||
| key, | ||
| _value | ||
| ) | ||
| ) | ||
| && instance || instance | ||
| , | ||
| document.createElement(vnode.E) | ||
| ) | ||
| /** | ||
| * The reconciliation process brings the DOM tree given as the | ||
| * host parameter in sync with the virtual DOM tree. | ||
| */ | ||
| global.R = reconcile = (vnode, host, element=host.firstChild) => | ||
| vnode | ||
| ? reconcile( | ||
| vnode.F, | ||
| element | ||
| ? element._ == vnode.E | ||
| ? element | ||
| : host.replaceChild( | ||
| element, | ||
| render(vnode, host, element._) | ||
| ) | ||
| : host.appendChild( | ||
| render(vnode, host) | ||
| ) | ||
| ) | ||
| : element | ||
| ? element.remove() | ||
| : 1 | ||
| || | ||
| reconcile( | ||
| vnode.N, | ||
| element.nextSibling | ||
| ) | ||
| /** | ||
| * a( [props], [children ...] ) | ||
| * | ||
| * Expanded HTML Tags as vnode constructors | ||
| */ | ||
| expandTags | ||
| .split('.') | ||
| .map( | ||
| (dom) => | ||
| global[dom] = createElement.bind({},dom) | ||
| ) | ||
| })(window, document, Object, Symbol(), 'a.b.button.i.span.div.img.p.h1.h2.h3.h4.table.tr.td.th.ul.ol.li.form.input.select'); | ||
| R(H('div', 'test'),document.body); |
-139
| ((global, document, Object, isvNode, assign, expandTags, createElement, render) => { | ||
| // Make all strings considered child nodes | ||
| // String.prototype[isvNode] = 1; | ||
| /** | ||
| * Create a VNode element | ||
| */ | ||
| // global.H = createElement = (element, props={}, ...children) => | ||
| // Object[assign]( | ||
| // { | ||
| // [isvNode]: 1, | ||
| // E: element | ||
| // }, | ||
| // props[isvNode] | ||
| // ? { | ||
| // C: [props].concat(children), | ||
| // P: {} | ||
| // } | ||
| // : { | ||
| // C: children, | ||
| // P: props | ||
| // } | ||
| // ) | ||
| global.H = createElement = (element, ...children) => ({ | ||
| [isvNode]: 1, | ||
| E: element, | ||
| P: children[0] && children[0][isvNode] && children.shift() || {}, | ||
| C: children | ||
| }) | ||
| // global.H = createElement = (element, props={}, ...children) => | ||
| // ({ | ||
| // [isvNode]: 1, // The isvNode symbol is used by the code | ||
| // // in the 'P' property to check if the `props` | ||
| // // argument is not an object, but a renderable | ||
| // // VNode child | ||
| // E: element, // 'E' holds the name or function passed as | ||
| // // first argument | ||
| // P: props[isvNode] // If the props argument is a renderable VNode, | ||
| // && children.unshift(props) && {C: children} // ... prepend it to the children | ||
| // || (props.C = children) && props // ... otherwise append 'C' to the property | ||
| // }) | ||
| /** | ||
| * Render a DOM node | ||
| */ | ||
| render = (vnode, parent, previous={}, _props=vnode.P, _instance=0) => | ||
| _instance = | ||
| vnode.call | ||
| ? render( | ||
| vnode( | ||
| _props, | ||
| previous.S || vnode.S, | ||
| (newState) => | ||
| Object[assign](vnode.S, newState) && | ||
| reconcile( | ||
| vnode, | ||
| // parent, | ||
| _instance | ||
| ) | ||
| ) | ||
| ) | ||
| : vnode.trim | ||
| ? document.createTextNode(vnode) | ||
| : Object.keys(_props).reduce( | ||
| (instance, key, unused1, unused2, _value=_props[key]) => | ||
| ( | ||
| 'style' == key ? | ||
| Object[assign]( | ||
| instance[key], | ||
| _value | ||
| ) | ||
| : /^on/.exec(key) ? | ||
| instance.addEventListener( | ||
| key.substr(2), | ||
| _value | ||
| ) | ||
| : instance.setAttribute( | ||
| key, | ||
| _value | ||
| ) | ||
| ) | ||
| && instance || instance | ||
| , | ||
| document.createElement(vnode.E) | ||
| ) | ||
| /** | ||
| * The reconciliation process brings the DOM tree given as the | ||
| * host parameter in sync with the virtual DOM tree. | ||
| */ | ||
| global.R = reconcile = (vnodes, host, i=0, element=host && host.childNodes[i], vnode=vnodes && vnodes[i]) => | ||
| vnode | ||
| ? reconcile( | ||
| vnode.C, | ||
| element | ||
| ? element._ == vnode.E | ||
| ? element | ||
| : host.replaceChild( | ||
| element, | ||
| render(vnode, host, element._) | ||
| ) | ||
| : host.appendChild( | ||
| render(vnode, host) | ||
| ) | ||
| ) | ||
| : element | ||
| ? element.remove() | ||
| : 1 | ||
| || | ||
| reconcile( | ||
| vnodes, | ||
| host, | ||
| i+1 | ||
| ) | ||
| /** | ||
| * a( [props], [children ...] ) | ||
| * | ||
| * Expanded HTML Tags as vnode constructors | ||
| */ | ||
| expandTags | ||
| .split('.') | ||
| .map( | ||
| (dom) => | ||
| global[dom] = createElement.bind({},dom) | ||
| ) | ||
| })(window, document, Object, Symbol(), 'assign', 'a.b.button.i.span.div.img.p.h1.h2.h3.h4.table.tr.td.th.ul.ol.li.form.input.select'); | ||
| // R([H('div', 'test')],document.body); |
-184
| ((global, document, Object, isvNode, jsonStringify, assign, expandTags, createElement, render) => { | ||
| // Make all strings considered child nodes | ||
| String.prototype[isvNode] = 1; | ||
| /** | ||
| * Create a VNode element | ||
| */ | ||
| global.H = createElement = (element, props={}, ...children) => | ||
| ({ | ||
| [isvNode]: 1, // The isvNode symbol is used by the code | ||
| // in the 'P' property to check if the `props` | ||
| // argument is not an object, but a renderable | ||
| // VNode child | ||
| E: element, // 'E' holds the name or function passed as | ||
| // first argument | ||
| S: {}, | ||
| P: props[isvNode] // If the props argument is a renderable VNode, | ||
| && children.unshift(props) && {C: children} // ... prepend it to the children | ||
| || (props.C = children) && props // ... otherwise append 'C' to the property | ||
| }) | ||
| /** | ||
| * Render a DOM node | ||
| */ | ||
| var id = 0; | ||
| global.R = render = (vnodes, host, _i=0, _children=host.childNodes) => { | ||
| console.debug('- Render', vnodes, 'on', host); | ||
| (vnodes.map ? vnodes : [vnodes]).map( | ||
| ( | ||
| vnode, | ||
| _unused1, | ||
| _unused2, | ||
| _prevDom=_children[_i++], | ||
| _newDom | ||
| ) => { | ||
| console.debug('- Rendering', vnode, 'on', _prevDom); | ||
| /* Replace stateful DOM */ | ||
| vnode = (vnode.E && vnode.E.call) | ||
| ? console.log('- Using state from', _prevDom, ':', _prevDom && _prevDom.D.S || {}) || | ||
| vnode.E( | ||
| vnode.P, | ||
| _prevDom ? _prevDom.D.S : {}, | ||
| (newState) => { | ||
| Object[assign]( | ||
| _newDom.D.S, | ||
| newState | ||
| ) | ||
| console.info('+ Update ', _newDom, '(', _newDom.D, ')'); | ||
| render( | ||
| vnodes, | ||
| host | ||
| ) | ||
| } | ||
| ) | ||
| : vnode; | ||
| console.debug('- Translated vnode=', vnode); | ||
| /* Render the DOM Node */ | ||
| (_newDom = vnode.trim | ||
| ? document.createTextNode(vnode) | ||
| : Object.keys(vnode.P).reduce( | ||
| (instance, key, unused1, unused2, _value=vnode.P[key]) => | ||
| 'style' == key ? | ||
| Object[assign]( | ||
| instance[key], | ||
| _value | ||
| ) && instance | ||
| : /^on/.exec(key) ? | ||
| instance.addEventListener( | ||
| key.substr(2), | ||
| _value | ||
| ) || instance | ||
| : 'C' != key ? | ||
| instance.setAttribute( | ||
| key, | ||
| _value | ||
| ) | ||
| : instance | ||
| , | ||
| document.createElement(vnode.E) | ||
| ) | ||
| ).D = vnode | ||
| _newDom.id = `id-${++id}`; | ||
| console.debug('- Instantiated DOM=', _newDom, '(', _newDom.D, ')'); | ||
| /* Reconcile */ | ||
| // _prevDom | ||
| // ? jsonStringify(_prevDom.D) == jsonStringify(vnode) | ||
| // ? (_newDom = _prevDom) | ||
| // : host.replaceChild( | ||
| // _newDom, | ||
| // _prevDom | ||
| // ) | ||
| // : host.appendChild( | ||
| // _newDom | ||
| // ) | ||
| if (_prevDom) { | ||
| if (jsonStringify(_prevDom.D) == jsonStringify(vnode)) { | ||
| console.debug('- Old DOM in Sync:', _prevDom); | ||
| console.debug(' =)', _prevDom.D, vnode); | ||
| _newDom = _prevDom | ||
| } else { | ||
| console.warn('- Replacing', _prevDom, 'with', _newDom); | ||
| console.debug(' a)', _prevDom.outerHTML, '->', _newDom.outerHTML); | ||
| while (_prevDom.childNodes.length > 0) { | ||
| _newDom.appendChild(_prevDom.childNodes[0]); | ||
| } | ||
| console.debug(' b)', _prevDom.outerHTML, '->', _newDom.outerHTML); | ||
| host.replaceChild( | ||
| _newDom, | ||
| _prevDom | ||
| ) | ||
| vnode.S ? _newDom.D.S = Object[assign]( | ||
| _prevDom.D.S, | ||
| vnode.S | ||
| ) : 0 | ||
| } | ||
| } else { | ||
| console.debug('- Appending new DOM'); | ||
| host.appendChild( | ||
| _newDom | ||
| ) | ||
| } | ||
| console.debug('- Reconciling children'); | ||
| /* Reconcile children */ | ||
| vnode.P && | ||
| render( | ||
| vnode.P.C, | ||
| _newDom | ||
| ) | ||
| } | ||
| ) | ||
| while (_children.length > _i) | ||
| _children[_i].remove(); | ||
| } | ||
| /** | ||
| * a( [props], [children ...] ) | ||
| * | ||
| * Expanded HTML Tags as vnode constructors | ||
| */ | ||
| expandTags | ||
| .split('.') | ||
| .map( | ||
| (dom) => | ||
| global[dom] = createElement.bind({},dom) | ||
| ) | ||
| })(window, document, Object, Symbol(), JSON.stringify, 'assign', 'a.b.button.i.span.div.img.p.h1.h2.h3.h4.table.tr.td.th.ul.ol.li.form.input.select'); | ||
| function Clicker(props, {counter=1}, setState) { | ||
| return button({ | ||
| onclick() { | ||
| setState({counter: counter+1}) | ||
| } | ||
| }, `${props.name} ${counter} times`); | ||
| } | ||
| function Complex(props, {counter=1}, setState) { | ||
| return div( | ||
| button({ | ||
| onclick() { | ||
| setState({counter: counter+1}) | ||
| } | ||
| }, `Super Clicked ${counter} times`), | ||
| H(Clicker, {name: 'First'}), | ||
| H(Clicker, {name: 'Second'}) | ||
| ); | ||
| } | ||
| R(div(H(Complex)), document.body); |
-159
| ((global, document, Object, isvNode, jsonStringify, assign, expandTags, createElement, render) => { | ||
| // Make all strings considered child nodes | ||
| String.prototype[isvNode] = 1; | ||
| /** | ||
| * Create a VNode element | ||
| */ | ||
| global.H = createElement = (element, props={}, ...children) => | ||
| ({ | ||
| [isvNode]: 1, // The isvNode symbol is used by the code | ||
| // in the 'P' property to check if the `props` | ||
| // argument is not an object, but a renderable | ||
| // VNode child | ||
| E: element, // 'E' holds the name or function passed as | ||
| // first argument | ||
| S: {}, | ||
| P: props[isvNode] // If the props argument is a renderable VNode, | ||
| && children.unshift(props) && {C: children} // ... prepend it to the children | ||
| || (props.C = children) && props // ... otherwise append 'C' to the property | ||
| }) | ||
| /** | ||
| * Render a DOM node | ||
| */ | ||
| global.R = render = (vnodes, host, _i=0, _children=host.childNodes) => { | ||
| (vnodes.map ? vnodes : [vnodes]).map( | ||
| ( | ||
| vnode, | ||
| _unused1, | ||
| _unused2, | ||
| _vnodeProps = vnode.P, | ||
| _prevDom = _children[_i++], | ||
| _prevState = _prevDom ? _prevDom.D.S : {}, | ||
| _prevChildren = _prevDom ? _prevDom.childNodes : [], | ||
| _newDom | ||
| ) => { | ||
| /* Replace stateful DOM */ | ||
| if ((vnode.E || 0).call) { | ||
| vnode = vnode.E( | ||
| _vnodeProps, | ||
| _prevState, | ||
| (newState) => { | ||
| Object[assign]( | ||
| _newDom.D.S, | ||
| newState | ||
| ) | ||
| render( | ||
| vnodes, | ||
| host | ||
| ) | ||
| } | ||
| ) | ||
| } | ||
| /* Render the DOM Node */ | ||
| (_newDom = vnode.trim | ||
| ? document.createTextNode(vnode) | ||
| : Object.keys(_vnodeProps = vnode.P).reduce( | ||
| (instance, key, unused1, unused2, _value=_vnodeProps[key]) => | ||
| 'style' == key ? | ||
| Object[assign]( | ||
| instance[key], | ||
| _value | ||
| ) && instance | ||
| : /^on/.exec(key) ? | ||
| instance.addEventListener( | ||
| key.substr(2), | ||
| _value | ||
| ) || instance | ||
| : 'C' != key ? | ||
| instance.setAttribute( | ||
| key, | ||
| _value | ||
| ) | ||
| : instance | ||
| , | ||
| document.createElement(vnode.E) | ||
| ) | ||
| ).D = vnode | ||
| /* Reconcile */ | ||
| if (_prevDom) { | ||
| if (jsonStringify(_prevDom.D) == jsonStringify(vnode)) { | ||
| _newDom = _prevDom | ||
| } else { | ||
| while (_prevChildren[0]) { | ||
| _newDom.appendChild(_prevChildren[0]); | ||
| } | ||
| host.replaceChild( | ||
| _newDom, | ||
| _prevDom | ||
| ) | ||
| vnode.S ? _newDom.D.S = Object[assign]( | ||
| _prevState, | ||
| vnode.S | ||
| ) : 0 | ||
| } | ||
| } else { | ||
| host.appendChild( | ||
| _newDom | ||
| ) | ||
| } | ||
| /* Reconcile children */ | ||
| _vnodeProps && | ||
| render( | ||
| vnode.P.C, | ||
| _newDom | ||
| ) | ||
| } | ||
| ) | ||
| while (_children.length > _i) | ||
| _children[_i].remove(); | ||
| } | ||
| /** | ||
| * a( [props], [children ...] ) | ||
| * | ||
| * Expanded HTML Tags as vnode constructors | ||
| */ | ||
| expandTags | ||
| .split('.') | ||
| .map( | ||
| (dom) => | ||
| global[dom] = createElement.bind({},dom) | ||
| ) | ||
| })(window, document, Object, Symbol(), JSON.stringify, 'assign', 'a.b.button.i.span.div.img.p.h1.h2.h3.h4.table.tr.td.th.ul.ol.li.form.input.select'); | ||
| function Clicker(props, {counter=1}, setState) { | ||
| return button({ | ||
| onclick() { | ||
| setState({counter: counter+1}) | ||
| } | ||
| }, `${props.name} ${counter} times`); | ||
| } | ||
| function Complex(props, {counter=1}, setState) { | ||
| return div( | ||
| button({ | ||
| onclick() { | ||
| setState({counter: counter+1}) | ||
| } | ||
| }, `Super Clicked ${counter} times`), | ||
| H(Clicker, {name: 'First'}), | ||
| H(Clicker, {name: 'Second'}) | ||
| ); | ||
| } | ||
| R(div(H(Complex)), document.body); |
-164
| ((global, document, Object, isvNode, jsonStringify, assign, createElement, render) => { | ||
| // Make all strings considered child nodes | ||
| String.prototype[isvNode] = 1; | ||
| /** | ||
| * Create a VNode element | ||
| */ | ||
| global.H = createElement = (element, props={}, ...children) => | ||
| ({ | ||
| [isvNode]: 1, // The isvNode symbol is used by the code | ||
| // in the 'P' property to check if the `props` | ||
| // argument is not an object, but a renderable | ||
| // VNode child | ||
| E: element, // 'E' holds the name or function passed as | ||
| // first argument | ||
| S: {}, | ||
| P: props[isvNode] // If the props argument is a renderable VNode, | ||
| && children.unshift(props) && {C: children} // ... prepend it to the children | ||
| || (props.C = children) && props // ... otherwise append 'C' to the property | ||
| }) | ||
| /** | ||
| * Render a DOM node | ||
| */ | ||
| global.R = render = (vnodes, host, _i=0, _children=host.childNodes) => { | ||
| (vnodes.map ? vnodes : [vnodes]).map( | ||
| ( | ||
| vnode, | ||
| _unused1, | ||
| _unused2, | ||
| _vnodeProps = vnode.P, | ||
| _prevDom = _children[_i++], | ||
| _prevState = _prevDom ? _prevDom.D.S : {}, | ||
| _prevChildren = _prevDom ? _prevDom.childNodes : [], | ||
| _newDom | ||
| ) => { | ||
| /* Replace stateful DOM */ | ||
| if ((vnode.E || 0).call) { | ||
| vnode = vnode.E( | ||
| _vnodeProps, | ||
| _prevState, | ||
| (newState) => { | ||
| Object[assign]( | ||
| vnode.S, | ||
| newState | ||
| ) | ||
| render( | ||
| vnodes, | ||
| host | ||
| ) | ||
| } | ||
| ) | ||
| } | ||
| /* Render the DOM Node */ | ||
| (_newDom = vnode.trim | ||
| ? document.createTextNode(vnode) | ||
| : Object.keys(_vnodeProps = vnode.P).reduce( | ||
| (instance, key, unused1, unused2, _value=_vnodeProps[key]) => | ||
| 'style' == key ? | ||
| Object[assign]( | ||
| instance[key], | ||
| _value | ||
| ) && instance | ||
| : /^on/.exec(key) ? | ||
| instance.addEventListener( | ||
| key.substr(2), | ||
| _value | ||
| ) || instance | ||
| : 'C' != key ? | ||
| instance.setAttribute( | ||
| key, | ||
| _value | ||
| ) || instance | ||
| : instance | ||
| , | ||
| document.createElement(vnode.E) | ||
| ) | ||
| ).D = vnode | ||
| /* Reconcile */ | ||
| _prevDom | ||
| ? jsonStringify(_prevDom.D) == jsonStringify(vnode) | ||
| ? (_newDom = _prevDom) | ||
| : (_ => { | ||
| // Move children from previous DOM to the new DOM | ||
| while (_prevChildren[0]) { | ||
| _newDom.appendChild(_prevChildren[0]); | ||
| } | ||
| // Replace element | ||
| host.replaceChild( | ||
| _newDom, | ||
| _prevDom | ||
| ) | ||
| // Perserve state | ||
| _prevState && Object[assign]( | ||
| vnode.S, | ||
| _prevState | ||
| ) | ||
| })() | ||
| : host.appendChild( | ||
| _newDom | ||
| ) | ||
| /* Nest */ | ||
| _vnodeProps && | ||
| render( | ||
| vnode.P.C, | ||
| _newDom | ||
| ) | ||
| } | ||
| ) | ||
| while (_children.length > _i) | ||
| host.removeChild(_children[_i]); | ||
| } | ||
| /** | ||
| * a( [props], [children ...] ) | ||
| * | ||
| * Expanded HTML Tags as vnode constructors | ||
| */ | ||
| 'a.b.button.i.span.div.img.p.h1.h2.h3.h4.table.tr.td.th.ul.ol.li.form.input.select' | ||
| .split('.') | ||
| .map( | ||
| (dom) => | ||
| global[dom] = createElement.bind({},dom) | ||
| ) | ||
| })(window, document, Object, Symbol(), JSON.stringify, 'assign'); | ||
| // function Clicker(props, {counter=1}, setState) { | ||
| // return button({ | ||
| // onclick() { | ||
| // setState({counter: counter+1}) | ||
| // } | ||
| // }, `${props.name} ${counter} times`); | ||
| // } | ||
| // function Complex(props, {counter=1}, setState) { | ||
| // return div( | ||
| // button({ | ||
| // onclick() { | ||
| // setState({counter: counter+1}) | ||
| // } | ||
| // }, `Super Clicked ${counter} times`), | ||
| // H(Clicker, {name: 'First'}), | ||
| // H(Clicker, {name: 'Second'}) | ||
| // ); | ||
| // } | ||
| // R(div(H(Complex)), document.body); |
-125
| (( | ||
| global, | ||
| document, | ||
| Object, | ||
| isvNode, | ||
| jsonStringify, | ||
| assign, | ||
| createElement, | ||
| render | ||
| ) => { | ||
| // Make all strings considered child nodes | ||
| String.prototype[isvNode] = 1; | ||
| /** | ||
| * Create a VNode element | ||
| */ | ||
| global.H = createElement = (element, props = {}, ...children) => ({ | ||
| [isvNode]: 1, // The isvNode symbol is used by the code | ||
| E: element, // 'E' holds the name or function passed as | ||
| P: ( | ||
| props[isvNode] // If the props argument is a renderable VNode, | ||
| ? children.unshift(props) && { C: children } // ... prepend it to the children | ||
| : (props.C = children) && props | ||
| ) // ... otherwise append 'C' to the property | ||
| }); | ||
| global.R = render = ( | ||
| nodes, | ||
| dom, | ||
| prev_nodes, | ||
| prev_dom = dom.childNodes, | ||
| c = -1 | ||
| ) => | ||
| (nodes.map ? nodes : nodes = [nodes]).map( | ||
| ( | ||
| node, | ||
| index, | ||
| unused1, | ||
| pnode = prev_nodes[++c], | ||
| pdom = prev_dom[c], | ||
| vnodeElement = node.E || {}, | ||
| instance, | ||
| props | ||
| ) => | ||
| ( | ||
| vnodeElement.call && ( | ||
| node = vnodeElement( | ||
| node.P, | ||
| node.S, | ||
| newState => render( | ||
| nodes | ||
| .slice(0, (i++)) | ||
| .concat( | ||
| { | ||
| S: Object.assign(vnode.S, newState), | ||
| P: vnode.P | ||
| }, | ||
| nodes.slice(i) | ||
| ), | ||
| dom, | ||
| nodes | ||
| ) | ||
| ) | ||
| ) | ||
| , instance = node.trim | ||
| ? document.createTextNode(node) | ||
| : Object.keys(props = node.P).reduce( | ||
| (instance, key, unused1, unused2, _value = props[key]) => | ||
| "style" == key | ||
| ? Object[assign](instance[key], _value) && instance | ||
| : /^on/.exec(key) | ||
| ? instance.addEventListener(key.substr(2), _value) || | ||
| instance | ||
| : "C" = key | ||
| ? render(), | ||
| : instance.setAttribute(key, _value), | ||
| document.createElement(node.E) | ||
| ), pnode | ||
| ? jsonStringify(pnode) != jsonStringify(node) && | ||
| dom.replaceChild(pdom, instance) | ||
| : dom.appendChild(instance), | ||
| ) | ||
| ); | ||
| /** | ||
| * a( [props], [children ...] ) | ||
| * | ||
| * Expanded HTML Tags as vnode constructors | ||
| */ | ||
| "a.b.button.i.span.div.img.p.h1.h2.h3.h4.table.tr.td.th.ul.ol.li.form.input.select.option" | ||
| .split(".") | ||
| .map(dom => global[dom] = createElement.bind({}, dom)); | ||
| })(window, document, Object, Symbol(), JSON.stringify, "assign"); | ||
| function Clicker(props, { counter = 1 }, setState) { | ||
| return button( | ||
| { | ||
| onclick() { | ||
| setState({ counter: counter + 1 }); | ||
| } | ||
| }, | ||
| `${props.name} ${counter} times` | ||
| ); | ||
| } | ||
| function Complex(props, { counter = 1 }, setState) { | ||
| return div( | ||
| button( | ||
| { | ||
| onclick() { | ||
| setState({ counter: counter + 1 }); | ||
| } | ||
| }, | ||
| `Super Clicked ${counter} times` | ||
| ), | ||
| H(Clicker, { name: "First" }), | ||
| H(Clicker, { name: "Second" }) | ||
| ); | ||
| } | ||
| function Table(props) { | ||
| return table(tr(td("row"), td("col"))); | ||
| } | ||
| R(div(H(Complex)), document.body); |
-208
| ((global, document, Object, vnodeFlag, expandTags, createElement, render) => { | ||
| // Make all strings considered child nodes | ||
| String.prototype[vnodeFlag] = 1; | ||
| /** | ||
| * Create a VNode element | ||
| */ | ||
| global.H = createElement = (element, props={}, ...children) => ({ | ||
| [vnodeFlag]: 1, // The vnodeFlag symbol is used by the code | ||
| // in the 'P' property to check if the `props` | ||
| // argument is not an object, but a renderable | ||
| // VNode child | ||
| E: element, // 'E' holds the name or function passed as | ||
| // first argument | ||
| S: {}, | ||
| P: props[vnodeFlag] // If the props argument is a renderable VNode, | ||
| && children.unshift(props) && {C: children} // ... prepend it to the children | ||
| || (props.C = children) && props // ... otherwise append 'C' to the property | ||
| }) | ||
| replaceTree = (old_node, node, _i=0) => ( | ||
| console.log(old_node, '->', node), | ||
| (old_node.E == node.E) && Object.assign(node.S, old_node.S), | ||
| node.P.C.map( | ||
| (child, u1, u2, _child=old_node.P.C[i++]) => | ||
| _child && replaceTree(_child, child) | ||
| ), | ||
| // node.P.C.splice(_i), | ||
| node | ||
| ) | ||
| /** | ||
| * Render the given VNode structure given to the DOM element given | ||
| * | ||
| * @param {VNode} - A VNode instance, created with `createElement` | ||
| * @param {DOMElement} - The HTML DOM element | ||
| * @returns {DOMElement} - The rendered DOM element | ||
| */ | ||
| global.R = render = (vnode, dom, _render, _element=vnode.E, _props=vnode.P) => | ||
| vnode.trim // Strings have a `.trim` function | ||
| ? dom.appendChild( // ** String Node ** | ||
| document.createTextNode(vnode) | ||
| ) | ||
| : _element.call // If element is a functional component, it | ||
| // will have the 'call' property defined. | ||
| // ** Stateful Render ** | ||
| ? (_render = (x, _instance, _dom=vnode) => // Create a heper function that will be called | ||
| // when the component has changed. | ||
| _instance = render( // Keep a reference to the DOM element mounted in | ||
| // order to be able to remove it on update | ||
| _dom = replaceTree( | ||
| _dom, | ||
| _element( // Call the component function passing down: | ||
| _props, // 1) Properties | ||
| _dom.S, // 2) State | ||
| (newState) => // 3) setState(newState) function | ||
| dom.replaceChild( // We trigger a new render cycle, replacing | ||
| _render( // the old DOM element with the render result. | ||
| Object.assign( // We pass down to the render function the updated | ||
| _dom.S, // state. | ||
| newState | ||
| ) | ||
| ), | ||
| _instance, | ||
| _dom | ||
| ) | ||
| ) | ||
| ), | ||
| dom | ||
| ) | ||
| )() // Initial call of the render cycle | ||
| // ** Native Render ** | ||
| : Object.keys(_props) // We are going to apply the properties by | ||
| // iterating on each property individually | ||
| .reduce( | ||
| ( | ||
| instance, // Reference to the new DOM element | ||
| key, // The property to apply | ||
| index, // Not used | ||
| array, // Not used | ||
| _value=_props[key] // Local reference to the property value | ||
| ) => | ||
| ( | ||
| key == 'C' ? // ## Children ## | ||
| _value.map((child) => // DOM VNodes are iterated through | ||
| render( | ||
| child, | ||
| instance | ||
| ) | ||
| ) | ||
| /* OR */ | ||
| : key == 'style' ? // ## Style ## | ||
| Object.assign( // Style property is applied recursively to the | ||
| instance[key], // CSS style of the element instance. | ||
| _value | ||
| ) | ||
| /* OR */ | ||
| : /^on/.exec(key) ? // ## Callbacks ## | ||
| instance.addEventListener( // Properties starting with `on` are registered | ||
| key.substr(2), // as event listeners to the DOM instance | ||
| _value | ||
| ) | ||
| /* OR */ | ||
| : instance.setAttribute( // ## Attributes ## | ||
| key, // Any other properties are assigned as attributes | ||
| _value | ||
| ) | ||
| ) && instance || instance // Make sure to *always* return the instance | ||
| , // We are passing to the reduce function a new | ||
| // child mounted to the DOM element | ||
| dom.appendChild( // We are appending to the `dom` argument a new | ||
| document.createElement( | ||
| _element | ||
| ) | ||
| ) | ||
| ) | ||
| /** | ||
| * Expand some of the default tags | ||
| */ | ||
| expandTags | ||
| .split('.') | ||
| .map( | ||
| (dom) => | ||
| global[dom] = createElement.bind(global, dom) | ||
| ) | ||
| })(window, document, Object, Symbol(), 'a.b.button.i.span.div.img.p.h1.h2.h3.h4.table.tr.td.th.ul.ol.li.form.input.select'); | ||
| function Clicker(props, state, setState) { | ||
| const {counter=1} = state; | ||
| return div( | ||
| div( | ||
| `Current ${props.name} value is ${counter}` | ||
| ), | ||
| div( | ||
| input({ | ||
| type: 'button', | ||
| value: 'Increment', | ||
| onclick() { | ||
| setState({counter: counter+1}) | ||
| props.onclick(); | ||
| } | ||
| }) | ||
| ) | ||
| ); | ||
| } | ||
| function Table(props) { | ||
| const {rows=[]} = props; | ||
| const rowElm = rows.map((row, i) => { | ||
| return tr( | ||
| td(`Item ${i}`), | ||
| td(row) | ||
| ); | ||
| }); | ||
| return table( | ||
| tr( | ||
| th('Item'), | ||
| th('Button') | ||
| ), | ||
| ...rowElm | ||
| ); | ||
| } | ||
| function Host(props, state, setState) { | ||
| const {rows=[]} = state; | ||
| return div( | ||
| H(Clicker, {name: 'first', onclick() { | ||
| setState({rows: rows.concat(['first'])}) | ||
| }}), | ||
| H(Clicker, {name: 'second', onclick() { | ||
| setState({rows: rows.concat(['second'])}) | ||
| }}), | ||
| H(Table, {rows: rows}) | ||
| ); | ||
| } | ||
| R(H(Host), document.body); |
-262
| ((global, document, Object, vnodeFlag, expandTags, createElement, render, global_state={}, cssKey) => { | ||
| // Make all strings considered child nodes | ||
| String.prototype[vnodeFlag] = 1; | ||
| /** | ||
| * CSS short name aliasing | ||
| */ | ||
| global.C = cssKey = (key) => | ||
| Object | ||
| .keys(document.body.style) | ||
| .find( | ||
| _candidate => | ||
| _candidate == key || | ||
| /(.)(?:.*?([A-Z]))?(?:.*(.))?/ | ||
| .exec(_candidate) | ||
| .slice(1,5) | ||
| .join('') == key | ||
| ) | ||
| /** | ||
| * Create a VNode element | ||
| */ | ||
| global.H = createElement = (element, props={}, ...children) => ({ | ||
| [vnodeFlag]: 1, // The vnodeFlag symbol is used by the code | ||
| // in the 'P' property to check if the `props` | ||
| // argument is not an object, but a renderable | ||
| // VNode child | ||
| E: element, // 'E' holds the name or function passed as | ||
| // first argument | ||
| P: props[vnodeFlag] // If the props argument is a renderable VNode, | ||
| && children.unshift(props) && {C: children} // ... prepend it to the children | ||
| || (props.C = children) && props // ... otherwise append 'C' to the property | ||
| }) | ||
| /** | ||
| * Render the given VNode structure given to the DOM element given | ||
| * | ||
| * @param {VNode} - A VNode instance, created with `createElement` | ||
| * @param {DOMElement} - The HTML DOM element | ||
| * @returns {DOMElement} - The rendered DOM element | ||
| */ | ||
| global.R = render = (vnode, dom, _path='', _update, _element=vnode.E, _props=vnode.P) => | ||
| vnode.trim // Strings have a `.trim` function | ||
| ? dom.appendChild( // ** String Node ** | ||
| document.createTextNode(vnode) | ||
| ) | ||
| : _element.call // If element is a functional component, it | ||
| // will have the 'call' property defined. | ||
| // ** Stateful Render ** | ||
| ? (_update = ( // Create a helper function that will be called | ||
| // when the component is updated. | ||
| state = [{}], // Default falue if the global state is missing | ||
| _state = | ||
| state[1] == _element // If the global state holds stale information | ||
| ? state[0] // about the component we are rendering, then | ||
| : (global_state[_path] = [{}])[0], // reset the state object | ||
| _instance // Local variable for the mounted DOM instance | ||
| ) => | ||
| _instance = render( // In the update function we render the new DOM | ||
| // element and we keep track of it | ||
| _element( // We call the component function to create the | ||
| // new virtual DOM, passing the following props: | ||
| _props, // - The properties of the component | ||
| _state, // - The current state of the component | ||
| newState => { // - The `setState` function | ||
| dom.replaceChild( // The setState function replaces the previous | ||
| // DOM instance with the re-render of the | ||
| // component, by calling the update function | ||
| _update( | ||
| global_state[_path] = [ // We also update the global state for the | ||
| // component path, ensuring that we keep: | ||
| Object.assign( // - The new state | ||
| _state, | ||
| newState | ||
| ), | ||
| _element // - The component function, to use it for | ||
| // stale detection (check above) | ||
| ] | ||
| ), | ||
| _instance | ||
| ) | ||
| console.log(global_state); | ||
| } | ||
| ), | ||
| dom, | ||
| _path | ||
| ) | ||
| )(global_state[_path]) // We pass the current state of this component | ||
| // that will default to `[{}, undefined]` | ||
| // ** Native Render ** | ||
| : Object.keys(_props) // We are going to apply the properties by | ||
| // iterating on each property individually | ||
| .reduce( | ||
| ( | ||
| instance, // Reference to the new DOM element | ||
| key, // The property to apply | ||
| index, // Not used | ||
| array, // Not used | ||
| _value=_props[key] // Local reference to the property value | ||
| ) => | ||
| ( | ||
| key == 'C' ? // ## Children ## | ||
| _value.map((child,i) => // DOM VNodes are iterated through | ||
| render( | ||
| child, | ||
| instance, | ||
| _path+'.'+i | ||
| ) | ||
| ) | ||
| /* OR */ | ||
| : key == 'style' ? // ## Style ## | ||
| Object.assign( // Style property is applied recursively to the | ||
| instance[key], // CSS style of the element instance. | ||
| _value | ||
| ) | ||
| /* OR */ | ||
| : /^on/.exec(key) ? // ## Callbacks ## | ||
| instance.addEventListener( // Properties starting with `on` are registered | ||
| key.substr(2), // as event listeners to the DOM instance | ||
| _value | ||
| ) | ||
| /* OR */ | ||
| : instance.setAttribute( // ## Attributes ## | ||
| key, // Any other properties are assigned as attributes | ||
| _value | ||
| ) | ||
| ) && instance || instance // Make sure to *always* return the instance | ||
| , // We are passing to the reduce function a new | ||
| // child mounted to the DOM element | ||
| dom.appendChild( // We are appending to the `dom` argument a new | ||
| document.createElement( | ||
| _element | ||
| ) | ||
| ) | ||
| ) | ||
| /** | ||
| * Expand some of the default tags | ||
| */ | ||
| expandTags | ||
| .split('.') | ||
| .map( | ||
| (dom) => | ||
| global[dom] = createElement.bind(global, dom) | ||
| ) | ||
| })(window, document, Object, Symbol(), 'a.b.button.i.span.div.img.p.h1.h2.h3.h4.table.tr.td.th.ul.ol.li.form.input.select'); | ||
| // function ClickerOdd(props, state, setState) { | ||
| // const {counter=1} = state; | ||
| // return div( | ||
| // div( | ||
| // `Current [even] ${props.name} value is ${counter}` | ||
| // ), | ||
| // div( | ||
| // input({ | ||
| // type: 'button', | ||
| // value: 'Increment', | ||
| // onclick() { | ||
| // setState({counter: counter+1}) | ||
| // props.onclick(); | ||
| // } | ||
| // }) | ||
| // ) | ||
| // ); | ||
| // } | ||
| // function ClickerEven(props, state, setState) { | ||
| // const {counter=1} = state; | ||
| // return div( | ||
| // div( | ||
| // `Current [odd] ${props.name} value is ${counter}` | ||
| // ), | ||
| // div( | ||
| // input({ | ||
| // type: 'button', | ||
| // value: 'Increment', | ||
| // onclick() { | ||
| // setState({counter: counter+1}) | ||
| // props.onclick(); | ||
| // } | ||
| // }) | ||
| // ) | ||
| // ); | ||
| // } | ||
| // function Table(props) { | ||
| // const {rows=[]} = props; | ||
| // const rowElm = rows.map((row, i) => { | ||
| // return tr( | ||
| // td(`Item ${i}`), | ||
| // td(row) | ||
| // ); | ||
| // }); | ||
| // return table( | ||
| // tr( | ||
| // th('Item'), | ||
| // th('Button') | ||
| // ), | ||
| // ...rowElm | ||
| // ); | ||
| // } | ||
| // function Host(props, state, setState) { | ||
| // const children = []; | ||
| // let {rows=[], clicks=0} = state; | ||
| // if (clicks) { | ||
| // children.push( | ||
| // H(ClickerEven, {name: 'first', onclick() { | ||
| // setState({rows: rows.concat(['first']), clicks: ++clicks}) | ||
| // }}), | ||
| // H(ClickerOdd, {name: 'second', onclick() { | ||
| // setState({rows: rows.concat(['second']), clicks: ++clicks}) | ||
| // }}) | ||
| // ); | ||
| // } else { | ||
| // children.push( | ||
| // H(ClickerOdd, {name: 'first', onclick() { | ||
| // setState({rows: rows.concat(['first']), clicks: ++clicks}) | ||
| // }}), | ||
| // H(ClickerEven, {name: 'second', onclick() { | ||
| // setState({rows: rows.concat(['second']), clicks: ++clicks}) | ||
| // }}) | ||
| // ); | ||
| // } | ||
| // return div( | ||
| // ...children, | ||
| // H(Table, {rows: rows}) | ||
| // ); | ||
| // } | ||
| // R(H(Host), document.body); |
Sorry, the diff of this file is not supported yet
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
320
23.55%1
-50%56789
-41.19%10
-44.44%742
-60.19%