diff --git a/.dccache b/.dccache index 0e5ae5d..795ed2b 100644 --- a/.dccache +++ b/.dccache @@ -1 +1 @@ -[{"/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/register.js":"1","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/source.js":"2","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/dist/valyrian.min.js":"3","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/bench/hyperscript.test.js":"4","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/bench/index-old.js":"5","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/bench/iterations.test.js":"6","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/bench/mount_n_update.test.js":"7","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/lib/index.ts":"8","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/plugins/hooks.js":"9","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/plugins/node.js":"10","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/plugins/node.sw.tpl.js":"11","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/plugins/request.js":"12","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/plugins/router.js":"13","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/plugins/signals.js":"14","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/plugins/store.js":"15","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/plugins/sw.js":"16","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/plugins/v-model.js":"17","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/test/directives_test.js":"18","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/test/hooks_test.js":"19","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/test/hyperscript_test.js":"20","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/test/keyed_test.js":"21","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/test/lifecycle_test.js":"22","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/test/mount_n_update_test.js":"23","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/test/node_test.js":"24","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/test/request_test.js":"25","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/test/router_test.js":"26","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/test/signals_test.js":"27","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/test/store_test.js":"28","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/plugins/utils/tree-adapter.js":"29"},[688,1617422138186.5078,"30"],[497,1619659597825.1243,"31"],[5609,1619658729019.0378,"32"],[1481,1619654764922.4663,"33"],[14148,1619654764922.4663,"34"],[2559,1619654764922.4663,"35"],[8221,1619654764922.4663,"36"],[20020,1619658102216.602,"37"],[2711,1619654764922.4663,"38"],[10475,1619659875228.1045,"39"],[4083,1601561152283.9846,"40"],[4221,1619654764926.437,"41"],[6630,1607402317220.4155,"42"],[4083,1601561161489.3032,"43"],[2041,1601561163851.908,"44"],[448,1601561166242.2478,"45"],[3182,1601561182841.262,"46"],[14550,1619654764926.437,"47"],[5492,1619654764926.437,"48"],[2791,1619654764926.437,"49"],[2478,1619654764926.437,"50"],[3854,1619654764926.437,"51"],[9107,1619658183230.6724,"52"],[7378,1619654764926.437,"53"],[8772,1619654764926.437,"54"],[9996,1619654764926.437,"55"],[5703,1619654764926.437,"56"],[4355,1619654764926.437,"57"],[14845,1602043898530.3389,"58"],"31bff5a8431e32a68275fe4e83ed7607a6132a9db824f5fc2aadc622a5934e4b","5bf71f613f53fb778178dede05d898fde311786179c56a251f3dfb92c9e3dfc8","a0de0e0c8a4c98ca2cab73d490d28d4129b2511a280dda3a038d2a4ccb65e247","47f0786340f25505cced19f4efee5fc9edebe5166a53ed5725e7cff755f2f233","6aa7b21dc8aa28b129933eadeff2632a4b52d5e9d977660a3767bf3ae2cc5aa5","3fe7303903dc5d4031d325600e7d5f6b44ebe1835805af8f1c3b17481f6e1b93","426f0fa1900c9abd9d90e28cebe0cd2d5ac49176a7e376aec5b278d81fbb9a30","fdb30402ae294f37965cccc1ab0a363f4338688e72c391c8055fc13aca7fc126","2f9c50259a30ee02d28e21cba4bae4e844a118092e1c48239181dfe5e27647f6","103b6f81405ff9da875cdc14315a4765c26c7b887bb1a6e12ab7183327e0703b","9e41c42d425160d207ad8dbe2eddd6c2bf432338665826d07c897e0f2b44a14d","2e2986dbf0786e8d84ef7ffa3eb34e891d636c82ace995a45fd29944429c60b8","7908598f1046f367c3ce6c02bf9b44970e333b35c449b43363f96dceb1008958","8d1fe0d59ee427d044a50a05fef348508a6e3c0470fe1fc027b1414ca488edb9","a950855c17dfc2667d895f978f7374e977e2631344198066f5972e92d0994289","74dd7dfefb006f754a7c5b13d8086b36990b440c16ce5b60b2b661188ac91c6c","ba3588cbe7fe65446cbdc8b9ffed65283c602fef940cb68d5fba025bb1aaad58","4509d29952f10c5c50a38c11315cfd70b6bbeb384663d259c11e9908755e8a77","d29af28903e17822e2124745feba6bd75c795abdb59b8b1768f79d10f4e2cfdb","40995000796dfc72a75a56f6c8a91a82bf7e69a58a3b9ac87a995ba90f05f5d0","682192795f6b060c66a1be5f61a7f9e1e9df373cf8cfed97face6d61ceeb13cc","ab3b54754e1dd3c4e3d4c07dfe45082705fffd50de4c09e50fae42383819586f","81d6b93cf911da0f3566fc33f79358ecb1d0827c7965d911a96110c00aa62c92","95b5d786979d8b6fe27c40e3a91a8bc2eb62aecc8519ccb679adc64170f2d898","41ebedb1c6159aa84df02d07c4e86fbed45dd005e6c1d5cb83204cf61080e10c","3f8a5325d2a53f10b134a0d201a43c0a73d01b5b9eb4f95cb8a13ee0958d8bad","cf8d15f6c280171af4626c7b7031435598c1b1db0eeb5ae6ce7f0988d1eb3936","24b75a991dd9d43aaf12333fc3b5080631ec8e5e68e0ccca7bb01b41b4bf81b6","9c0dd2ed2e6b14a644c8a2c1b28761b16f7253b182307a3f1b9fb529088b602c"] \ No newline at end of file +[{"/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/register.js":"1","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/source.js":"2","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/bench/hyperscript.test.js":"3","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/bench/index-old.js":"4","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/bench/iterations.test.js":"5","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/bench/mount_n_update.test.js":"6","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/dist/valyrian.min.js":"7","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/lib/index.ts":"8","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/plugins/hooks.js":"9","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/plugins/node.js":"10","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/plugins/node.sw.tpl.js":"11","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/plugins/request.js":"12","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/plugins/router.js":"13","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/plugins/signals.js":"14","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/plugins/store.js":"15","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/plugins/sw.js":"16","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/plugins/v-model.js":"17","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/test/directives_test.js":"18","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/test/hooks_test.js":"19","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/test/hyperscript_test.js":"20","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/test/keyed_test.js":"21","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/test/lifecycle_test.js":"22","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/test/mount_n_update_test.js":"23","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/test/node_test.js":"24","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/test/request_test.js":"25","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/test/router_test.js":"26","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/test/signals_test.js":"27","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/test/store_test.js":"28","/home/masquerade-circus/NodeJs/ownprojects/valyrian.js/plugins/utils/tree-adapter.js":"29"},[688,1617422138186.5078,"30"],[443,1619659901361.7544,"31"],[1481,1619654764922.4663,"32"],[14148,1619654764922.4663,"33"],[2559,1619654764922.4663,"34"],[8221,1619654764922.4663,"35"],[5609,1619661307189.5845,"36"],[19988,1619658151821.948,"37"],[2711,1619654764922.4663,"38"],[10393,1619659947605.038,"39"],[4083,1601561152283.9846,"40"],[4221,1619654764926.437,"41"],[6630,1607402317220.4155,"42"],[4083,1601561161489.3032,"43"],[2041,1601561163851.908,"44"],[448,1601561166242.2478,"45"],[3182,1601561182841.262,"46"],[14550,1619654764926.437,"47"],[5492,1619654764926.437,"48"],[2791,1619654764926.437,"49"],[2478,1619654764926.437,"50"],[3854,1619654764926.437,"51"],[9107,1619658183230.6724,"52"],[7378,1619654764926.437,"53"],[8772,1619654764926.437,"54"],[9996,1619654764926.437,"55"],[5703,1619654764926.437,"56"],[4355,1619654764926.437,"57"],[14845,1602043898530.3389,"58"],"31bff5a8431e32a68275fe4e83ed7607a6132a9db824f5fc2aadc622a5934e4b","12b042601675ffa2b7f81215d7b74c471f12a619525486e0dcbfd88a9386e1a7","47f0786340f25505cced19f4efee5fc9edebe5166a53ed5725e7cff755f2f233","6aa7b21dc8aa28b129933eadeff2632a4b52d5e9d977660a3767bf3ae2cc5aa5","3fe7303903dc5d4031d325600e7d5f6b44ebe1835805af8f1c3b17481f6e1b93","426f0fa1900c9abd9d90e28cebe0cd2d5ac49176a7e376aec5b278d81fbb9a30","a0de0e0c8a4c98ca2cab73d490d28d4129b2511a280dda3a038d2a4ccb65e247","4753e08fad4825b4ad364fed94932f4f0c8f4b5fad29e64fa4bb3ad71a32dedf","2f9c50259a30ee02d28e21cba4bae4e844a118092e1c48239181dfe5e27647f6","a6bd3c86f92629dd1a41b493f3cde70be7eaeaca704b277942ae7d5a83604ad7","9e41c42d425160d207ad8dbe2eddd6c2bf432338665826d07c897e0f2b44a14d","2e2986dbf0786e8d84ef7ffa3eb34e891d636c82ace995a45fd29944429c60b8","7908598f1046f367c3ce6c02bf9b44970e333b35c449b43363f96dceb1008958","8d1fe0d59ee427d044a50a05fef348508a6e3c0470fe1fc027b1414ca488edb9","a950855c17dfc2667d895f978f7374e977e2631344198066f5972e92d0994289","74dd7dfefb006f754a7c5b13d8086b36990b440c16ce5b60b2b661188ac91c6c","ba3588cbe7fe65446cbdc8b9ffed65283c602fef940cb68d5fba025bb1aaad58","4509d29952f10c5c50a38c11315cfd70b6bbeb384663d259c11e9908755e8a77","d29af28903e17822e2124745feba6bd75c795abdb59b8b1768f79d10f4e2cfdb","40995000796dfc72a75a56f6c8a91a82bf7e69a58a3b9ac87a995ba90f05f5d0","682192795f6b060c66a1be5f61a7f9e1e9df373cf8cfed97face6d61ceeb13cc","ab3b54754e1dd3c4e3d4c07dfe45082705fffd50de4c09e50fae42383819586f","81d6b93cf911da0f3566fc33f79358ecb1d0827c7965d911a96110c00aa62c92","95b5d786979d8b6fe27c40e3a91a8bc2eb62aecc8519ccb679adc64170f2d898","41ebedb1c6159aa84df02d07c4e86fbed45dd005e6c1d5cb83204cf61080e10c","3f8a5325d2a53f10b134a0d201a43c0a73d01b5b9eb4f95cb8a13ee0958d8bad","cf8d15f6c280171af4626c7b7031435598c1b1db0eeb5ae6ce7f0988d1eb3936","24b75a991dd9d43aaf12333fc3b5080631ec8e5e68e0ccca7bb01b41b4bf81b6","9c0dd2ed2e6b14a644c8a2c1b28761b16f7253b182307a3f1b9fb529088b602c"] \ No newline at end of file diff --git a/dist/valyrian.min.js b/dist/valyrian.min.js index 8ebee09..ac197d5 100644 --- a/dist/valyrian.min.js +++ b/dist/valyrian.min.js @@ -1 +1,396 @@ -(()=>{var e=class{constructor(e,o=null,n){this.props=o||{},this.children=n,this.name=e}},o=class{constructor(e){this.dom=e}},n=class{constructor(e,o=null,n){this.props=o,this.children=n,this.component=e}},t=void 0,d=null,r=Array.isArray,l="function",p="v-once",i=(e,o=!1)=>o?document.createElementNS("http://www.w3.org/2000/svg",e):document.createElement(e),s=n=>{if(1===n.nodeType){let o={};[].forEach.call(n.attributes,e=>o[e.nodeName]=e.nodeValue);let t=new e(n.nodeName,o,[]);t.dom=n;for(let e=0,o=n.childNodes.length;e{for(let n=0,t=o.children.length;n{let o=i("div");return o.innerHTML=e.trim(),[].map.call(o.childNodes,e=>s(e))};(m?global:window).v=function f(){function h(o,t=null,...d){return"string"==typeof o?new e(o,t,d):new n(o,t,d)}h.isMounted=!1,h.isNode=m;let v,g,w,y=d,N=["key","data",p,"oncreate","onupdate","onremove","onbeforeupdate"];h.reservedWords=N;let V={parentVnode:t,oldParentVnode:t,component:t};h.current=V;let C=new Map;h.usePlugin=(e,o={})=>!C.has(e)&&C.set(e,!0)&&e(h,o);let b={};function x(e){let o=e.target,n=`__on${e.type}`;for(;o;){if(o[n])return o[n](e,o),void(e.defaultPrevented||h.update());o=o.parentNode}}h.trust=u;let S=[];h.onCleanup=e=>{let o=h.current.parentVnode;o.onCleanup||(o.onCleanup=[]),o.onCleanup.push(e),-1===S.indexOf(o)&&S.push(o)};let M=e=>{for(let o in e.props){let n=e.props[o];if(!(o in e.props))return;-1!==N.indexOf(o)?L[o]&&L[o](n,e):typeof n===l?(o=`__${o}`,b[o]||(y.addEventListener(o.slice(4),x),b[o]=!0),e.dom[o]=n):o in e.dom&&!e.isSVG?e.dom[o]!=n&&(e.dom[o]=n):!1!==n&&e.dom.setAttribute(o,n)}},A=(e,o,n)=>{if(e in o.props){let t=o.props[e];-1!==N.indexOf(e)?L[e]&&L[e](t,o,n):typeof t===l?(b[e=`__${e}`]||(y.addEventListener(e.slice(4),x),b[e]=!0),o.dom[e]=t):e in o.dom&&!o.isSVG?o.dom[e]!=t&&(o.dom[e]=t):(!n||t!==n.props[e])&&(!1===t?o.dom.removeAttribute(e):o.dom.setAttribute(e,t))}};h.updateProperty=A;let G=(e,o)=>{for(let n in e.props){if(!(n in e.props))return;A(n,e,o)}},O=(e,o)=>{for(let n in o.props)-1===N.indexOf(n)&&!(n in e.props)&&(o===a||typeof o.props[n]!==l)&&(n in e.dom?e.dom[n]=t:e.dom.removeAttribute(n))},T=(e,o,n)=>{n?o.replaceChild(e,n):o.appendChild(e)},_=(e,o,n,t)=>{let d=e.childNodes[n];t?(o.dom=t.dom,p in o.props||o.props.onbeforeupdate&&!1===o.props.onbeforeupdate(o,t)?(o.children=t.children,o.dom!==d&&T(o.dom,e,d)):(O(o,t),G(o,t),o.dom!==d&&T(o.dom,e,d),h.isMounted?o.props.onupdate&&o.props.onupdate(o,t):o.props.oncreate&&o.props.oncreate(o),E(o,t))):(o.dom=i(o.name,o.isSVG),M(o),o.dom!==d&&T(o.dom,e,d),o.props.oncreate&&o.props.oncreate(o),E(o))},E=(l,s=a)=>{let m=r(l.children)?l.children:[l.children],u=s.children;V.parentVnode=l,V.oldParentVnode=s;for(let o=0;o0){for(let o=u.length;o--;)u[o]instanceof e&&c(u[o]);l.dom.textContent=""}}else if(u.length&&m[0]instanceof e&&"key"in m[0].props){let e=u.map(e=>e.props.key),o=m.map(e=>e.props.key);for(let n=0,t=o.length;n=e.length?-1:n;-1!==o?(u[o].processed=!0,_(l.dom,d,r,u[o])):_(l.dom,d,r)}}let n=u.length;for(;n--;)if(!u[n].processed){let e=u[n];c(e),e.dom&&e.dom.parentNode&&e.dom.parentNode.removeChild(e.dom)}}else{let n=u.length,t=m.length;for(;n-- >t;){let o=u[n];o instanceof e&&c(o),o.dom&&o.dom.parentNode&&o.dom.parentNode.removeChild(o.dom)}for(n=0;n{if(v)return w&&((()=>{for(let e=S.length;e--;)for(let o of S[e].onCleanup)o();S=[]})(),g=v,v=new e(v.name,v.props,[h(w,o,...n)]),v.dom=g.dom,v.isSVG="svg"===v.name,E(v,g),h.isMounted=!0),h.isNode&&v.dom.innerHTML},h.mount=(e,o,n=null,...t)=>(y=h.isNode?i(e):document.querySelectorAll(e)[0],v=s(y),w=o,h.update(n,...t)),h.unMount=()=>{y=d,w=()=>"";let e=h.update();return h.isMounted=!1,e};let L={};h.directive=(e,o)=>{let n=`v-${e}`;-1===N.indexOf(n)&&(N.push(n),L[n]=o)};let P=o=>(n,t,d)=>{if(o?n:!n){let o=document.createTextNode("");d&&d.dom&&d.dom.parentNode&&(d instanceof e&&c(d),d.dom.parentNode.replaceChild(o,d.dom)),t.name="#text",t.children=[],t.props={},t.dom=o}};return h.directive("if",P(!1)),h.directive("unless",P(!0)),h.directive("for",(e,o)=>o.children=e.map(o.children[0])),h.directive("show",(e,o)=>o.dom.style.display=e?"":"none"),h.directive("class",(e,o)=>{for(let n in e)o.dom.classList.toggle(n,e[n])}),h.directive("html",(e,o)=>o.children=u(e)),h.newInstance=f,h}()})(); \ No newline at end of file +(() => { + // lib/index.ts + var Vnode = class { + constructor(name, props = null, children) { + this.props = props || {}; + this.children = children; + this.name = name; + } + }; + var TextVnode = class { + constructor(dom) { + this.dom = dom; + } + }; + var ComponentVnode = class { + constructor(component, props = null, children) { + this.props = props; + this.children = children; + this.component = component; + } + }; + var UND = void 0; + var NULL = null; + var isArray = Array.isArray; + var functionstr = "function"; + var once = "v-once"; + var key = "key"; + var svg = "svg"; + var str = "string"; + var createElement = (tag, isSVG = false) => isSVG ? document.createElementNS("http://www.w3.org/2000/svg", tag) : document.createElement(tag); + var domToVnode = (dom) => { + if (dom.nodeType === 1) { + let props = {}; + [].forEach.call(dom.attributes, (prop) => props[prop.nodeName] = prop.nodeValue); + let vnode = new Vnode(dom.nodeName, props, []); + vnode.dom = dom; + for (let i = 0, l = dom.childNodes.length; i < l; i++) { + let childVnode = domToVnode(dom.childNodes[i]); + childVnode && vnode.children.push(childVnode); + } + return vnode; + } + if (dom.nodeType === 3) { + return new TextVnode(dom); + } + }; + var emptyNode = new Vnode("empty", NULL, []); + var callRemove = (vnode) => { + for (let i = 0, l = vnode.children.length; i < l; i++) { + vnode.children[i] instanceof Vnode && callRemove(vnode.children[i]); + } + vnode.props.onremove && vnode.props.onremove(vnode); + }; + var isNode = typeof window === "undefined" || typeof global !== "undefined"; + var trust = (htmlString) => { + let div = createElement("div"); + div.innerHTML = htmlString.trim(); + return [].map.call(div.childNodes, (item) => domToVnode(item)); + }; + function valyrian() { + function v(tagOrComponent, props = null, ...children) { + if (typeof tagOrComponent === str) { + return new Vnode(tagOrComponent, props, children); + } + return new ComponentVnode(tagOrComponent, props, children); + } + v.isMounted = false; + v.isNode = isNode; + let mainContainer = NULL; + let mainNode; + let oldMainNode; + let mountedComponent; + const reservedWords = [key, "data", once, "oncreate", "onupdate", "onremove", "onbeforeupdate"]; + v.reservedWords = reservedWords; + const current = { + parentVnode: UND, + oldParentVnode: UND, + component: UND + }; + v.current = current; + const plugins = new Map(); + v.usePlugin = (plugin, options = {}) => !plugins.has(plugin) && plugins.set(plugin, true) && plugin(v, options); + let attachedListeners = {}; + function eventListener(e) { + let dom = e.target; + let name = `__on${e.type}`; + while (dom) { + if (dom[name]) { + dom[name](e, dom); + if (!e.defaultPrevented) { + v.update(); + } + return; + } + dom = dom.parentNode; + } + } + v.trust = trust; + let vnodesToCleanup = []; + v.onCleanup = (callback) => { + let parentVnode = v.current.parentVnode; + if (!parentVnode.onCleanup) { + parentVnode.onCleanup = []; + } + parentVnode.onCleanup.push(callback); + if (vnodesToCleanup.indexOf(parentVnode) === -1) { + vnodesToCleanup.push(parentVnode); + } + }; + let cleanupVnodes = () => { + for (let l = vnodesToCleanup.length; l--; ) { + for (let callback of vnodesToCleanup[l].onCleanup) { + callback(); + } + } + vnodesToCleanup = []; + }; + const addProps = (newNode) => { + for (let name in newNode.props) { + let value = newNode.props[name]; + if (name in newNode.props === false) { + return; + } else if (reservedWords.indexOf(name) !== -1) { + if (directives[name]) { + directives[name](value, newNode); + } + } else if (typeof value === functionstr) { + name = `__${name}`; + if (!attachedListeners[name]) { + mainContainer.addEventListener(name.slice(4), eventListener); + attachedListeners[name] = true; + } + newNode.dom[name] = value; + } else if (name in newNode.dom && !newNode.isSVG) { + if (newNode.dom[name] != value) { + newNode.dom[name] = value; + } + } else if (value !== false) { + newNode.dom.setAttribute(name, value); + } + } + }; + const updateProperty = (name, newNode, oldNode) => { + if (name in newNode.props) { + let value = newNode.props[name]; + if (reservedWords.indexOf(name) !== -1) { + if (directives[name]) { + directives[name](value, newNode, oldNode); + } + } else if (typeof value === functionstr) { + name = `__${name}`; + if (!attachedListeners[name]) { + mainContainer.addEventListener(name.slice(4), eventListener); + attachedListeners[name] = true; + } + newNode.dom[name] = value; + } else if (name in newNode.dom && !newNode.isSVG) { + if (newNode.dom[name] != value) { + newNode.dom[name] = value; + } + } else if (!oldNode || value !== oldNode.props[name]) { + if (value === false) { + newNode.dom.removeAttribute(name); + } else { + newNode.dom.setAttribute(name, value); + } + } + } + }; + v.updateProperty = updateProperty; + let updateProps = (newNode, oldNode) => { + for (let name in newNode.props) { + if (name in newNode.props === false) { + return; + } + updateProperty(name, newNode, oldNode); + } + }; + let removeProps = (newNode, oldNode) => { + for (let name in oldNode.props) { + if (reservedWords.indexOf(name) === -1 && name in newNode.props === false && (oldNode === emptyNode || typeof oldNode.props[name] !== functionstr)) { + if (name in newNode.dom) { + newNode.dom[name] = UND; + } else { + newNode.dom.removeAttribute(name); + } + } + } + }; + let moveDom = (dom, $parent, oldDom) => { + oldDom ? $parent.replaceChild(dom, oldDom) : $parent.appendChild(dom); + }; + let updateKeyedNode = ($parent, newNode, newIndex, compareNode) => { + let oldDom = $parent.childNodes[newIndex]; + if (compareNode) { + newNode.dom = compareNode.dom; + if (once in newNode.props || newNode.props.onbeforeupdate && newNode.props.onbeforeupdate(newNode, compareNode) === false) { + newNode.children = compareNode.children; + newNode.dom !== oldDom && moveDom(newNode.dom, $parent, oldDom); + } else { + removeProps(newNode, compareNode); + updateProps(newNode, compareNode); + newNode.dom !== oldDom && moveDom(newNode.dom, $parent, oldDom); + if (v.isMounted) { + newNode.props.onupdate && newNode.props.onupdate(newNode, compareNode); + } else { + newNode.props.oncreate && newNode.props.oncreate(newNode); + } + patch(newNode, compareNode); + } + } else { + newNode.dom = createElement(newNode.name, newNode.isSVG); + addProps(newNode); + newNode.dom !== oldDom && moveDom(newNode.dom, $parent, oldDom); + newNode.props.oncreate && newNode.props.oncreate(newNode); + patch(newNode); + } + }; + let patch = (parentNode, oldParentNode = emptyNode) => { + let newTree = isArray(parentNode.children) ? parentNode.children : [parentNode.children]; + let oldTree = oldParentNode.children; + current.parentVnode = parentNode; + current.oldParentVnode = oldParentNode; + for (let i = 0; i < newTree.length; i++) { + let childVnode = newTree[i]; + if (childVnode instanceof Vnode) { + childVnode.isSVG = parentNode.isSVG || childVnode.name === svg; + } else if (childVnode === NULL || childVnode === UND) { + newTree.splice(i--, 1); + } else if (childVnode instanceof ComponentVnode) { + current.component = childVnode; + newTree.splice(i--, 1, ("view" in childVnode.component ? childVnode.component.view : childVnode.component).call(childVnode.component, childVnode.props, ...childVnode.children)); + } else if (isArray(childVnode)) { + newTree.splice(i--, 1, ...childVnode); + } + } + if (newTree.length === 0) { + if (oldTree.length > 0) { + for (let i = oldTree.length; i--; ) { + oldTree[i] instanceof Vnode && callRemove(oldTree[i]); + } + parentNode.dom.textContent = ""; + } + } else if (oldTree.length && newTree[0] instanceof Vnode && key in newTree[0].props) { + let oldKeys = oldTree.map((vnode) => vnode.props.key); + let newKeys = newTree.map((vnode) => vnode.props.key); + for (let i = 0, l2 = newKeys.length; i < l2; i++) { + let key2 = newKeys[i]; + let newNode = newTree[i]; + if (key2 === oldKeys[i]) { + oldTree[i].processed = true; + updateKeyedNode(parentNode.dom, newNode, i, oldTree[i]); + } else { + let oldIndex = oldKeys.indexOf(key2); + let newIndex = i >= oldKeys.length ? -1 : i; + if (oldIndex !== -1) { + oldTree[oldIndex].processed = true; + updateKeyedNode(parentNode.dom, newNode, newIndex, oldTree[oldIndex]); + } else { + updateKeyedNode(parentNode.dom, newNode, newIndex); + } + } + } + let l = oldTree.length; + while (l--) { + if (!oldTree[l].processed) { + let oldVnode = oldTree[l]; + callRemove(oldVnode); + oldVnode.dom && oldVnode.dom.parentNode && oldVnode.dom.parentNode.removeChild(oldVnode.dom); + } + } + } else { + let i = oldTree.length; + let l = newTree.length; + while (i-- > l) { + let oldVnode = oldTree[i]; + oldVnode instanceof Vnode && callRemove(oldVnode); + oldVnode.dom && oldVnode.dom.parentNode && oldVnode.dom.parentNode.removeChild(oldVnode.dom); + } + for (i = 0; i < l; i++) { + let newNode = newTree[i]; + let oldNode = oldTree[i]; + if (newNode instanceof Vnode) { + if (oldNode && newNode.name === oldNode.name) { + newNode.dom = oldNode.dom; + if (once in newNode.props || newNode.props.onbeforeupdate && newNode.props.onbeforeupdate(newNode, oldNode) === false) { + newNode.children = oldNode.children; + } else { + removeProps(newNode, oldNode); + updateProps(newNode, oldNode); + if (v.isMounted) { + newNode.props.onupdate && newNode.props.onupdate(newNode, oldNode); + } else { + newNode.props.oncreate && newNode.props.oncreate(newNode); + } + patch(newNode, oldNode); + } + } else { + newNode.dom = createElement(newNode.name, newNode.isSVG); + addProps(newNode); + if (oldNode) { + oldNode instanceof Vnode && callRemove(oldNode); + parentNode.dom.replaceChild(newNode.dom, parentNode.dom.childNodes[i]); + } else { + parentNode.dom.appendChild(newNode.dom); + } + newNode.props.oncreate && newNode.props.oncreate(newNode); + patch(newNode); + } + } else { + let dom; + let value = newNode instanceof TextVnode ? newNode.dom.nodeValue : String(newNode); + if (oldNode instanceof TextVnode) { + dom = oldNode.dom; + if (value != dom.nodeValue) { + dom.nodeValue = value; + } + } else { + dom = document.createTextNode(value); + if (oldNode) { + callRemove(oldNode); + parentNode.dom.replaceChild(dom, oldNode.dom); + } else { + parentNode.dom.appendChild(dom); + } + } + newTree[i] = new TextVnode(dom); + } + } + } + parentNode.children = newTree; + }; + v.update = (props = null, ...children) => { + if (mainNode) { + if (mountedComponent) { + cleanupVnodes(); + oldMainNode = mainNode; + mainNode = new Vnode(mainNode.name, mainNode.props, [v(mountedComponent, props, ...children)]); + mainNode.dom = oldMainNode.dom; + mainNode.isSVG = mainNode.name === svg; + patch(mainNode, oldMainNode); + v.isMounted = true; + } + return v.isNode && mainNode.dom.innerHTML; + } + }; + v.mount = (container, component, props = null, ...children) => { + mainContainer = v.isNode ? createElement(container) : document.querySelectorAll(container)[0]; + mainNode = domToVnode(mainContainer); + mountedComponent = component; + return v.update(props, ...children); + }; + v.unMount = () => { + mainContainer = NULL; + mountedComponent = () => ""; + let result = v.update(); + v.isMounted = false; + return result; + }; + const directives = {}; + v.directive = (directive, handler) => { + let directiveName = `v-${directive}`; + if (reservedWords.indexOf(directiveName) === -1) { + reservedWords.push(directiveName); + directives[directiveName] = handler; + } + }; + let hideDirective = (test) => (bool, vnode, oldnode) => { + let value = test ? bool : !bool; + if (value) { + let newdom = document.createTextNode(""); + if (oldnode && oldnode.dom && oldnode.dom.parentNode) { + oldnode instanceof Vnode && callRemove(oldnode); + oldnode.dom.parentNode.replaceChild(newdom, oldnode.dom); + } + vnode.name = "#text"; + vnode.children = []; + vnode.props = {}; + vnode.dom = newdom; + } + }; + v.directive("if", hideDirective(false)); + v.directive("unless", hideDirective(true)); + v.directive("for", (set, vnode) => vnode.children = set.map(vnode.children[0])); + v.directive("show", (bool, vnode) => vnode.dom.style.display = bool ? "" : "none"); + v.directive("class", (classes, vnode) => { + for (let name in classes) { + vnode.dom.classList.toggle(name, classes[name]); + } + }); + v.directive("html", (html, vnode) => vnode.children = trust(html)); + v.newInstance = valyrian; + return v; + } + (isNode ? global : window).v = valyrian(); +})(); diff --git a/lib/index.ts b/lib/index.ts index 918ab70..571bd2a 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -368,7 +368,7 @@ function valyrian(): Valyrian { // If the tree is keyed list and is not first render } else if (oldTree.length && newTree[0] instanceof Vnode && key in newTree[0].props) { - let oldKeys = oldTree.map((vnode) => (vnode as Vnode).props.key); + let oldKeys = key in ((oldTree[0] as Vnode).props || {}) ? oldTree.map((vnode) => (vnode as Vnode).props.key) : []; let newKeys = newTree.map((vnode) => vnode.props.key); for (let i = 0, l = newKeys.length; i < l; i++) { @@ -400,7 +400,7 @@ function valyrian(): Valyrian { while (l--) { if (!(oldTree[l] as Vnode).processed) { let oldVnode = oldTree[l]; - callRemove(oldVnode as Vnode); + oldVnode instanceof Vnode && callRemove(oldVnode); (oldVnode as Vnode).dom && ((oldVnode as Vnode).dom as DomElement).parentNode && (((oldVnode as Vnode).dom as DomElement).parentNode as DomElement).removeChild((oldVnode as Vnode).dom as DomElement); diff --git a/test/keyed_test.js b/test/keyed_test.js index 4ea2817..4eb5540 100644 --- a/test/keyed_test.js +++ b/test/keyed_test.js @@ -2,6 +2,7 @@ import "../lib"; import expect from "expect"; import nodePlugin from "../plugins/node"; + v.usePlugin(nodePlugin); describe("Keyed lists", () => { @@ -57,6 +58,35 @@ describe("Keyed lists", () => { }); }); + it("Keyed list: Replace with string and update with list", () => { + let keys = [1, 2, 3, 4, 5]; + let useStrings = true; + let component = () => ( +
    + {keys.map((key) => { + if (useStrings) { + return String(key); + } + return
  • {key}
  • ; + })} +
+ ); + + let before = v.mount("body", component); + + useStrings = false; + let after = v.update(); + + let afterString = getString(keys); + + useStrings = true; + let afterUpdate = v.update(); + + expect(before).toEqual("
    12345
"); + expect(after).toEqual(afterString); + expect(afterUpdate).toEqual("
    12345
"); + }); + it("Keyed list: Replace with undefined and update with defined", () => { let keys = [1, 2, 3, 4, 5]; let component = () => ( @@ -65,6 +95,7 @@ describe("Keyed lists", () => { if (key) { return
  • {key}
  • ; } + return "Hello"; })} );