diff --git a/Slim.js b/Slim.js index 8675d7a..bb1f5d1 100644 --- a/Slim.js +++ b/Slim.js @@ -31,7 +31,13 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons isIE11: !!window['MSInputMethodContext'] && !!document['documentMode'] }; - var _$2 = Symbol('Slim'); + try { + __flags.isChrome = /Chrome/.test(navigator.userAgent); + } catch (err) { + __flags.isChrome = false; + } + + var _$2 = '_slim_internals_'; //Symbol('Slim') var Internals = function Internals() { _classCallCheck(this, Internals); @@ -257,7 +263,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons var collection = []; var search = function search(node, force) { collection.push(node); - var allow = !(node instanceof Slim) || node instanceof Slim && !node.template || force; + var allow = !node.__isSlim || node.__isSlim && !node.template || force; if (allow) { [].concat(_toConsumableArray(node.children)).forEach(function (childNode) { search(childNode, force); @@ -401,6 +407,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons var _this2 = _possibleConstructorReturn(this, (Slim.__proto__ || Object.getPrototypeOf(Slim)).call(this)); + _this2.__isSlim = true; Slim.debug('ctor', _this2.localName); if (Slim.checkCreationBlocking(_this2)) { return _possibleConstructorReturn(_this2); @@ -694,115 +701,12 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons ); }, function () {}, true); - Slim.customDirective(function (attr) { - return (/^s:repeat$/.test(attr.nodeName) - ); - }, function (source, templateNode, attribute) { - var path = attribute.nodeValue; - var tProp = 'data'; - if (path.indexOf(' as')) { - tProp = path.split(' as ')[1] || tProp; - path = path.split(' as ')[0]; - } - - var clones = []; - var hook = document.createComment(templateNode.localName + ' s:repeat="' + attribute.nodeValue + '"'); - Slim._$(hook); - Slim.selectRecursive(templateNode, true).forEach(function (e) { - return Slim._$(e).excluded = true; - }); - templateNode.parentElement.insertBefore(hook, templateNode); - templateNode.remove(); - Slim.unbind(source, templateNode); - Slim.asap(function () { - templateNode.setAttribute('s:iterate', ''); - templateNode.removeAttribute('s:repeat'); - }); - var oldDataSource = []; - Slim.bind(source, hook, path, function () { - var dataSource = Slim.lookup(source, path) || []; - var offset = 0; - var restOfData = []; - // get the diff - var diff = Array(dataSource.length); - dataSource.forEach(function (d, i) { - if (oldDataSource[i] !== d) { - diff[i] = true; - } - }); - oldDataSource = dataSource.concat(); - var indices = Object.keys(diff); - if (dataSource.length < clones.length) { - var disposables = clones.slice(dataSource.length); - clones = clones.slice(0, dataSource.length); - disposables.forEach(function (clone) { - return clone.remove(); - }); - // unbind disposables? - indices.forEach(function (index) { - var clone = clones[index];[clone].concat(Slim.qSelectAll(clone, '*')).forEach(function (t) { - t[_$2].repeater[tProp] = dataSource[index]; - Slim.commit(t, tProp); - }); - }); - } else { - // recycle - clones.length && indices.forEach(function (index) { - var clone = clones[index]; - if (!clone) return; - [clone].concat(Slim.qSelectAll(clone, '*')).forEach(function (t) { - t[_$2].repeater[tProp] = dataSource[index]; - Slim.commit(t, tProp); - }); - }); - restOfData = dataSource.slice(clones.length); - offset = clones.length; - } - if (!restOfData.length) return; - // new clones - var range = document.createRange(); - range.setStartBefore(hook); - var html = Array(restOfData.length).fill(templateNode.outerHTML).join(''); - var frag = range.createContextualFragment(html); - var all = []; - var i = 0; - while (i < frag.children.length) { - var e = frag.children.item(i); - clones.push(e); - all.push(e); - Slim._$(e).repeater[tProp] = dataSource[i + offset]; - var subTree = Slim.qSelectAll(e, '*'); - subTree.forEach(function (t) { - all.push(t); - Slim._$(t).repeater[tProp] = dataSource[i + offset]; - Slim.commit(t, tProp); - }); - i++; - } - source._bindChildren(all); - all.forEach(function (t) { - if (t instanceof Slim) { - t.createdCallback(); - Slim.asap(function () { - Slim.commit(t, tProp); - t[tProp] = t[_$2].repeater[tProp]; - }); - } else { - Slim.commit(t, tProp); - t[tProp] = t[_$2].repeater[tProp]; - } - }); - hook.parentElement.insertBefore(frag, hook); - }); - source[_$2].reversed[tProp] = true; - }, true); - // supported events (i.e. click, mouseover, change...) Slim.customDirective(function (attr) { return Slim[_$2].supportedNativeEvents.indexOf(attr.nodeName) >= 0; }, function (source, target, attribute) { var eventName = attribute.nodeName; - var delegate = attribute.nodeValue; + var delegate = attribute.value; Slim._$(target).eventHandlers = target[_$2].eventHandlers || {}; var allHandlers = target[_$2].eventHandlers; allHandlers[eventName] = allHandlers[eventName] || []; @@ -823,7 +727,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons return (/^s:if$/.exec(attr.nodeName) ); }, function (source, target, attribute) { - var expression = attribute.nodeValue; + var expression = attribute.value; var path = expression; var isNegative = false; if (path.charAt(0) === '!') { @@ -907,7 +811,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons return (/^s:id$/.test(attr.nodeName) ); }, function (source, target, attribute) { - Slim._$(target).boundParent[attribute.nodeValue] = target; + Slim._$(target).boundParent[attribute.value] = target; }); // bind:property @@ -917,7 +821,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons }, function (source, target, attribute, match) { var tAttr = match[2]; var tProp = Slim.dashToCamel(tAttr); - var expression = attribute.nodeValue; + var expression = attribute.value; var oldValue = void 0; var rxM = Slim.rxMethod.exec(expression); if (rxM) { @@ -948,6 +852,136 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons } }); + __flags.isChrome && Slim.customDirective(function (attr) { + return (/^s:repeat$/.test(attr.nodeName) + ); + }, function (source, templateNode, attribute) { + var path = attribute.value; + var tProp = 'data'; + if (path.indexOf(' as')) { + tProp = path.split(' as ')[1] || tProp; + path = path.split(' as ')[0]; + } + + var clones = []; + var hook = document.createComment(templateNode.localName + ' s:repeat="' + attribute.value + '"'); + Slim._$(hook); + Slim.selectRecursive(templateNode, true).forEach(function (e) { + return Slim._$(e).excluded = true; + }); + templateNode.parentElement.insertBefore(hook, templateNode); + templateNode.remove(); + Slim.unbind(source, templateNode); + Slim.asap(function () { + templateNode.setAttribute('s:iterate', ''); + templateNode.removeAttribute('s:repeat'); + }); + var oldDataSource = []; + Slim.bind(source, hook, path, function () { + var dataSource = Slim.lookup(source, path) || []; + var offset = 0; + var restOfData = []; + // get the diff + var diff = Array(dataSource.length); + dataSource.forEach(function (d, i) { + if (oldDataSource[i] !== d) { + diff[i] = true; + } + }); + oldDataSource = dataSource.concat(); + var indices = Object.keys(diff); + if (dataSource.length < clones.length) { + var disposables = clones.slice(dataSource.length); + clones = clones.slice(0, dataSource.length); + disposables.forEach(function (clone) { + return clone.remove(); + }); + // unbind disposables? + indices.forEach(function (index) { + var clone = clones[index];[clone].concat(Slim.qSelectAll(clone, '*')).forEach(function (t) { + t[_$2].repeater[tProp] = dataSource[index]; + Slim.commit(t, tProp); + }); + }); + } else { + // recycle + clones.length && indices.forEach(function (index) { + var clone = clones[index]; + if (!clone) return; + [clone].concat(Slim.qSelectAll(clone, '*')).forEach(function (t) { + t[_$2].repeater[tProp] = dataSource[index]; + Slim.commit(t, tProp); + }); + }); + restOfData = dataSource.slice(clones.length); + offset = clones.length; + } + if (!restOfData.length) return; + // new clones + var range = document.createRange(); + range.setStartBefore(hook); + var html = Array(restOfData.length).fill(templateNode.outerHTML).join(''); + var frag = range.createContextualFragment(html); + var all = []; + var i = 0; + while (i < frag.children.length) { + var e = frag.children.item(i); + clones.push(e); + all.push(e); + Slim._$(e).repeater[tProp] = dataSource[i + offset]; + var subTree = Slim.qSelectAll(e, '*'); + subTree.forEach(function (t) { + all.push(t); + Slim._$(t).repeater[tProp] = dataSource[i + offset]; + Slim.commit(t, tProp); + }); + i++; + } + source._bindChildren(all); + all.forEach(function (t) { + if (t.__isSlim) { + t.createdCallback(); + Slim.asap(function () { + Slim.commit(t, tProp); + t[tProp] = t[_$2].repeater[tProp]; + }); + } else { + Slim.commit(t, tProp); + t[tProp] = t[_$2].repeater[tProp]; + } + }); + hook.parentElement.insertBefore(frag, hook); + }); + source[_$2].reversed[tProp] = true; + }, true); + + !__flags.isChrome && Slim.customDirective(function (attr) { + return (/^s:repeat$/.test(attr.nodeName) + ); + }, function (source, templateNode, attribute) { + var path = attribute.nodeValue; + var tProp = 'data'; + if (path.indexOf(' as')) { + tProp = path.split(' as ')[1] || tProp; + path = path.split(' as ')[0]; + } + + var repeater = document.createElement('slim-repeat'); + repeater[_$2].boundParent = source; + repeater.dataProp = tProp; + repeater.dataPath = attribute.nodeValue; + repeater.templateNode = templateNode.cloneNode(true); + repeater.templateNode.removeAttribute('s:repeat'); + templateNode.parentNode.insertBefore(repeater, templateNode); + Slim.removeChild(templateNode); + Slim.bind(source, repeater, path, function () { + var dataSource = Slim.lookup(source, path); + repeater.dataSource = dataSource || []; + }); + + // source._executeBindings() + }, true); + var SlimRepeater = function (_Slim) { _inherits(SlimRepeater, _Slim); @@ -968,7 +1002,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons }); directChildren.forEach(function (child, index) { child.setAttribute('s:iterate', _this7.dataPath + ' : ' + index); - Slim.selectRecursive(child, true).forEach(function (e) { + Slim.selectRecursive(child).forEach(function (e) { Slim._$(e).repeater[_this7.dataProp] = _this7.dataSource[index]; if (e instanceof Slim) { e[_this7.dataProp] = _this7.dataSource[index]; @@ -994,12 +1028,11 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons Slim.unbind(_this8.boundParent, e); }); if (!this.dataSource || !this.templateNode || !this.boundParent) { - _get(SlimRepeater.prototype.__proto__ || Object.getPrototypeOf(SlimRepeater.prototype), 'render', this).call(this, ''); - } else { - var newTemplate = Array(this.dataSource.length).fill(this.templateNode.outerHTML).join(''); - this.innerHTML = ''; - _get(SlimRepeater.prototype.__proto__ || Object.getPrototypeOf(SlimRepeater.prototype), 'render', this).call(this, newTemplate); + return _get(SlimRepeater.prototype.__proto__ || Object.getPrototypeOf(SlimRepeater.prototype), 'render', this).call(this, ''); } + var newTemplate = Array(this.dataSource.length).fill(this.templateNode.outerHTML).join(''); + this.innerHTML = ''; + _get(SlimRepeater.prototype.__proto__ || Object.getPrototypeOf(SlimRepeater.prototype), 'render', this).call(this, newTemplate); } }, { key: 'dataSource', diff --git a/Slim.min.js b/Slim.min.js index e3ed54c..8445101 100644 --- a/Slim.min.js +++ b/Slim.min.js @@ -1 +1 @@ -"use strict";var _get=function get(object,property,receiver){if(object===null)object=Function.prototype;var desc=Object.getOwnPropertyDescriptor(object,property);if(desc===undefined){var parent=Object.getPrototypeOf(object);if(parent===null){return undefined}else{return get(parent,property,receiver)}}else if("value"in desc){return desc.value}else{var getter=desc.get;if(getter===undefined){return undefined}return getter.call(receiver)}};var _slicedToArray=function(){function sliceIterator(arr,i){var _arr=[];var _n=true;var _d=false;var _e=undefined;try{for(var _i=arr[Symbol.iterator](),_s;!(_n=(_s=_i.next()).done);_n=true){_arr.push(_s.value);if(i&&_arr.length===i)break}}catch(err){_d=true;_e=err}finally{try{if(!_n&&_i["return"])_i["return"]()}finally{if(_d)throw _e}}return _arr}return function(arr,i){if(Array.isArray(arr)){return arr}else if(Symbol.iterator in Object(arr)){return sliceIterator(arr,i)}else{throw new TypeError("Invalid attempt to destructure non-iterable instance")}}}();var _createClass=function(){function defineProperties(target,props){for(var i=0;i=0},function(source,target,attribute){var eventName=attribute.nodeName;var delegate=attribute.nodeValue;Slim._$(target).eventHandlers=target[_$2].eventHandlers||{};var allHandlers=target[_$2].eventHandlers;allHandlers[eventName]=allHandlers[eventName]||[];var handler=function handler(e){try{source[delegate].call(source,e)}catch(err){err.message='Could not respond to event "'+eventName+'" on '+target.localName+' -> "'+delegate+'" on '+source.localName+" ... "+err.message;console.warn(err)}};allHandlers[eventName].push(handler);target.addEventListener(eventName,handler);handler=null});Slim.customDirective(function(attr){return/^s:if$/.exec(attr.nodeName)},function(source,target,attribute){var expression=attribute.nodeValue;var path=expression;var isNegative=false;if(path.charAt(0)==="!"){path=path.slice(1);isNegative=true}var anchor=document.createComment("if:"+expression);target.parentNode.insertBefore(anchor,target);var fn=function fn(){var value=Slim.lookup(source,expression,target);if(isNegative){value=!value}if(value){anchor.parentNode.insertBefore(target,anchor.nextSibling)}else{Slim.removeChild(target)}};Slim.bind(source,target,path,fn)},true);Slim.customDirective(function(attr){return/^bind$/.test(attr.nodeName)},function(source,target){Slim._$(target);target[_$2].sourceText=target.innerText;var updatedText="";var matches=target.innerText.match(/\{\{([^\}\}]+)+\}\}/g);var aggProps={};var textBinds={};if(matches){matches.forEach(function(expression){var oldValue=void 0;var rxM=/\{\{(.+)(\((.+)\)){1}\}\}/.exec(expression);if(rxM){var fnName=rxM[1];var pNames=rxM[3].split(" ").join("").split(",");pNames.map(function(path){return path.split(".")[0]}).forEach(function(p){return aggProps[p]=true});textBinds[expression]=function(target){var args=pNames.map(function(path){return Slim.lookup(source,path,target)});var value=source[fnName].apply(source,args);if(oldValue===value)return;updatedText=updatedText.split(expression).join(value||"")};return}var rxP=/\{\{(.+[^(\((.+)\))])\}\}/.exec(expression);if(rxP){var path=rxP[1];aggProps[path]=true;textBinds[expression]=function(target){var value=Slim.lookup(source,path,target);if(oldValue===value)return;updatedText=updatedText.split(expression).join(value||"")}}});var chainExecutor=function chainExecutor(){updatedText=target[_$2].sourceText;Object.keys(textBinds).forEach(function(expression){textBinds[expression](target)});target.innerText=updatedText};Object.keys(aggProps).forEach(function(prop){Slim.bind(source,target,prop,chainExecutor)})}});Slim.customDirective(function(attr){return/^s:id$/.test(attr.nodeName)},function(source,target,attribute){Slim._$(target).boundParent[attribute.nodeValue]=target});Slim.customDirective(function(attr){return/^(bind):(\S+)/.exec(attr.nodeName)},function(source,target,attribute,match){var tAttr=match[2];var tProp=Slim.dashToCamel(tAttr);var expression=attribute.nodeValue;var oldValue=void 0;var rxM=Slim.rxMethod.exec(expression);if(rxM){var pNames=rxM[3].split(" ").join("").split(",");pNames.forEach(function(pName){Slim.bind(source,target,pName,function(){var fn=Slim.lookup(source,rxM[1],target);var args=pNames.map(function(prop){return Slim.extract(source,prop,target)});var value=fn.apply(source,args);if(oldValue===value)return;target[tProp]=value;target.setAttribute(tAttr,value)})});return}var rxP=Slim.rxProp.exec(expression);if(rxP){var prop=rxP[1];Slim.bind(source,target,prop,function(){var value=Slim.lookup(source,expression,target);if(oldValue===value)return;target.setAttribute(tAttr,value);target[tProp]=value})}});var SlimRepeater=function(_Slim){_inherits(SlimRepeater,_Slim);function SlimRepeater(){_classCallCheck(this,SlimRepeater);return _possibleConstructorReturn(this,(SlimRepeater.__proto__||Object.getPrototypeOf(SlimRepeater)).apply(this,arguments))}_createClass(SlimRepeater,[{key:"_bindChildren",value:function _bindChildren(tree){var _this7=this;tree=Array.prototype.slice.call(tree);var directChildren=Array.prototype.filter.call(tree,function(child){return child.parentNode.localName==="slim-root-fragment"});directChildren.forEach(function(child,index){child.setAttribute("s:iterate",_this7.dataPath+" : "+index);Slim.selectRecursive(child,true).forEach(function(e){Slim._$(e).repeater[_this7.dataProp]=_this7.dataSource[index];if(e instanceof Slim){e[_this7.dataProp]=_this7.dataSource[index]}})})}},{key:"onRender",value:function onRender(){if(!this.boundParent)return;var tree=Slim.selectRecursive(this);this.boundParent&&this.boundParent._bindChildren(tree);this.boundParent._executeBindings()}},{key:"render",value:function render(){var _this8=this;if(!this.boundParent)return;Slim.qSelectAll(this,"*").forEach(function(e){Slim.unbind(_this8.boundParent,e)});if(!this.dataSource||!this.templateNode||!this.boundParent){_get(SlimRepeater.prototype.__proto__||Object.getPrototypeOf(SlimRepeater.prototype),"render",this).call(this,"")}else{var newTemplate=Array(this.dataSource.length).fill(this.templateNode.outerHTML).join("");this.innerHTML="";_get(SlimRepeater.prototype.__proto__||Object.getPrototypeOf(SlimRepeater.prototype),"render",this).call(this,newTemplate)}}},{key:"dataSource",get:function get(){return this._dataSource},set:function set(v){if(this._dataSource!==v){this._dataSource=v;this.render()}}},{key:"boundParent",get:function get(){return this[_$2].boundParent}}]);return SlimRepeater}(Slim);Slim.tag("slim-repeat",SlimRepeater);if(window){window["Slim"]=Slim}if(typeof module!=="undefined"){module.exports.Slim=Slim}})(window,document,HTMLElement); \ No newline at end of file +"use strict";var _get=function get(object,property,receiver){if(object===null)object=Function.prototype;var desc=Object.getOwnPropertyDescriptor(object,property);if(desc===undefined){var parent=Object.getPrototypeOf(object);if(parent===null){return undefined}else{return get(parent,property,receiver)}}else if("value"in desc){return desc.value}else{var getter=desc.get;if(getter===undefined){return undefined}return getter.call(receiver)}};var _slicedToArray=function(){function sliceIterator(arr,i){var _arr=[];var _n=true;var _d=false;var _e=undefined;try{for(var _i=arr[Symbol.iterator](),_s;!(_n=(_s=_i.next()).done);_n=true){_arr.push(_s.value);if(i&&_arr.length===i)break}}catch(err){_d=true;_e=err}finally{try{if(!_n&&_i["return"])_i["return"]()}finally{if(_d)throw _e}}return _arr}return function(arr,i){if(Array.isArray(arr)){return arr}else if(Symbol.iterator in Object(arr)){return sliceIterator(arr,i)}else{throw new TypeError("Invalid attempt to destructure non-iterable instance")}}}();var _createClass=function(){function defineProperties(target,props){for(var i=0;i=0},function(source,target,attribute){var eventName=attribute.nodeName;var delegate=attribute.value;Slim._$(target).eventHandlers=target[_$2].eventHandlers||{};var allHandlers=target[_$2].eventHandlers;allHandlers[eventName]=allHandlers[eventName]||[];var handler=function handler(e){try{source[delegate].call(source,e)}catch(err){err.message='Could not respond to event "'+eventName+'" on '+target.localName+' -> "'+delegate+'" on '+source.localName+" ... "+err.message;console.warn(err)}};allHandlers[eventName].push(handler);target.addEventListener(eventName,handler);handler=null});Slim.customDirective(function(attr){return/^s:if$/.exec(attr.nodeName)},function(source,target,attribute){var expression=attribute.value;var path=expression;var isNegative=false;if(path.charAt(0)==="!"){path=path.slice(1);isNegative=true}var anchor=document.createComment("if:"+expression);target.parentNode.insertBefore(anchor,target);var fn=function fn(){var value=Slim.lookup(source,expression,target);if(isNegative){value=!value}if(value){anchor.parentNode.insertBefore(target,anchor.nextSibling)}else{Slim.removeChild(target)}};Slim.bind(source,target,path,fn)},true);Slim.customDirective(function(attr){return/^bind$/.test(attr.nodeName)},function(source,target){Slim._$(target);target[_$2].sourceText=target.innerText;var updatedText="";var matches=target.innerText.match(/\{\{([^\}\}]+)+\}\}/g);var aggProps={};var textBinds={};if(matches){matches.forEach(function(expression){var oldValue=void 0;var rxM=/\{\{(.+)(\((.+)\)){1}\}\}/.exec(expression);if(rxM){var fnName=rxM[1];var pNames=rxM[3].split(" ").join("").split(",");pNames.map(function(path){return path.split(".")[0]}).forEach(function(p){return aggProps[p]=true});textBinds[expression]=function(target){var args=pNames.map(function(path){return Slim.lookup(source,path,target)});var value=source[fnName].apply(source,args);if(oldValue===value)return;updatedText=updatedText.split(expression).join(value||"")};return}var rxP=/\{\{(.+[^(\((.+)\))])\}\}/.exec(expression);if(rxP){var path=rxP[1];aggProps[path]=true;textBinds[expression]=function(target){var value=Slim.lookup(source,path,target);if(oldValue===value)return;updatedText=updatedText.split(expression).join(value||"")}}});var chainExecutor=function chainExecutor(){updatedText=target[_$2].sourceText;Object.keys(textBinds).forEach(function(expression){textBinds[expression](target)});target.innerText=updatedText};Object.keys(aggProps).forEach(function(prop){Slim.bind(source,target,prop,chainExecutor)})}});Slim.customDirective(function(attr){return/^s:id$/.test(attr.nodeName)},function(source,target,attribute){Slim._$(target).boundParent[attribute.value]=target});Slim.customDirective(function(attr){return/^(bind):(\S+)/.exec(attr.nodeName)},function(source,target,attribute,match){var tAttr=match[2];var tProp=Slim.dashToCamel(tAttr);var expression=attribute.value;var oldValue=void 0;var rxM=Slim.rxMethod.exec(expression);if(rxM){var pNames=rxM[3].split(" ").join("").split(",");pNames.forEach(function(pName){Slim.bind(source,target,pName,function(){var fn=Slim.lookup(source,rxM[1],target);var args=pNames.map(function(prop){return Slim.extract(source,prop,target)});var value=fn.apply(source,args);if(oldValue===value)return;target[tProp]=value;target.setAttribute(tAttr,value)})});return}var rxP=Slim.rxProp.exec(expression);if(rxP){var prop=rxP[1];Slim.bind(source,target,prop,function(){var value=Slim.lookup(source,expression,target);if(oldValue===value)return;target.setAttribute(tAttr,value);target[tProp]=value})}});__flags.isChrome&&Slim.customDirective(function(attr){return/^s:repeat$/.test(attr.nodeName)},function(source,templateNode,attribute){var path=attribute.value;var tProp="data";if(path.indexOf(" as")){tProp=path.split(" as ")[1]||tProp;path=path.split(" as ")[0]}var clones=[];var hook=document.createComment(templateNode.localName+' s:repeat="'+attribute.value+'"');Slim._$(hook);Slim.selectRecursive(templateNode,true).forEach(function(e){return Slim._$(e).excluded=true});templateNode.parentElement.insertBefore(hook,templateNode);templateNode.remove();Slim.unbind(source,templateNode);Slim.asap(function(){templateNode.setAttribute("s:iterate","");templateNode.removeAttribute("s:repeat")});var oldDataSource=[];Slim.bind(source,hook,path,function(){var dataSource=Slim.lookup(source,path)||[];var offset=0;var restOfData=[];var diff=Array(dataSource.length);dataSource.forEach(function(d,i){if(oldDataSource[i]!==d){diff[i]=true}});oldDataSource=dataSource.concat();var indices=Object.keys(diff);if(dataSource.length { search(childNode, force) @@ -287,6 +293,7 @@ constructor () { super() + this.__isSlim = true Slim.debug('ctor', this.localName) if (Slim.checkCreationBlocking(this)) { return @@ -497,117 +504,11 @@ Slim.customDirective(attr => /^s:iterate$/.test(attr.nodeName), () => {}, true) - Slim.customDirective(attr => /^s:repeat$/.test(attr.nodeName), (source, templateNode, attribute) => { - let path = attribute.nodeValue - let tProp = 'data' - if (path.indexOf(' as' )) { - tProp = path.split(' as ')[1] || tProp - path = path.split(' as ')[0] - } - - let clones = [] - const hook = document.createComment(`${templateNode.localName} s:repeat="${attribute.nodeValue}"`) - Slim._$(hook) - Slim.selectRecursive(templateNode, true).forEach(e => Slim._$(e).excluded = true) - templateNode.parentElement.insertBefore(hook, templateNode) - templateNode.remove() - Slim.unbind(source, templateNode) - Slim.asap( () => { - templateNode.setAttribute('s:iterate', '') - templateNode.removeAttribute('s:repeat') - }) - let oldDataSource = [] - Slim.bind(source, hook, path, () => { - const dataSource = Slim.lookup(source, path) || [] - let offset = 0 - let restOfData = [] - // get the diff - const diff = Array(dataSource.length) - dataSource.forEach((d, i) => { - if (oldDataSource[i] !== d) { - diff[i] = true - } - }) - oldDataSource = dataSource.concat() - let indices = Object.keys(diff) - if (dataSource.length < clones.length) { - const disposables = clones.slice(dataSource.length) - clones = clones.slice(0, dataSource.length) - disposables.forEach(clone => clone.remove()) - // unbind disposables? - indices.forEach(index => { - const clone = clones[index] - ;[clone].concat(Slim.qSelectAll(clone, '*')).forEach(t => { - t[_$].repeater[tProp] = dataSource[index] - Slim.commit(t, tProp) - }) - }) - } else { - // recycle - clones.length && indices.forEach(index => { - const clone = clones[index] - if (!clone) return - [clone].concat(Slim.qSelectAll(clone, '*')).forEach(t => { - t[_$].repeater[tProp] = dataSource[index] - Slim.commit(t, tProp) - }) - }) - restOfData = dataSource.slice(clones.length) - offset = clones.length - } - if (!restOfData.length) return - // new clones - const range = document.createRange() - range.setStartBefore(hook) - let html = Array(restOfData.length).fill(templateNode.outerHTML).join('') - const frag = range.createContextualFragment(html) - let all = [] - let i = 0; - while (i < frag.children.length) { - const e = frag.children.item(i) - clones.push(e) - all.push(e) - Slim._$(e).repeater[tProp] = dataSource[i + offset] - const subTree = Slim.qSelectAll(e, '*') - subTree.forEach(t => { - all.push(t) - Slim._$(t).repeater[tProp] = dataSource[i + offset] - Slim.commit(t, tProp) - }) - i++ - } - source._bindChildren(all) - all.forEach(t => { - if (t instanceof Slim) { - t.createdCallback() - Slim.asap( () => { - Slim.commit(t, tProp) - t[tProp] = t[_$].repeater[tProp] - }) - } else { - Slim.commit(t, tProp) - t[tProp] = t[_$].repeater[tProp] - } - }) - hook.parentElement.insertBefore(frag, hook) - }) - source[_$].reversed[tProp] = true - }, true) - - - - - - - - - - // supported events (i.e. click, mouseover, change...) Slim.customDirective((attr) => Slim[_$].supportedNativeEvents.indexOf(attr.nodeName) >= 0, (source, target, attribute) => { const eventName = attribute.nodeName - const delegate = attribute.nodeValue + const delegate = attribute.value Slim._$(target).eventHandlers = target[_$].eventHandlers || {} const allHandlers = target[_$].eventHandlers allHandlers[eventName] = allHandlers[eventName] || [] @@ -667,7 +568,7 @@ Slim.customDirective(attr => { return /^s:if$/.exec(attr.nodeName) }, (source, target, attribute) => { - let expression = attribute.nodeValue + let expression = attribute.value let path = expression let isNegative = false if (path.charAt(0) === '!') { @@ -739,14 +640,14 @@ }) Slim.customDirective(attr => /^s:id$/.test(attr.nodeName), (source, target, attribute) => { - Slim._$(target).boundParent[attribute.nodeValue] = target + Slim._$(target).boundParent[attribute.value] = target }) // bind:property Slim.customDirective(attr => /^(bind):(\S+)/.exec(attr.nodeName), (source, target, attribute, match) => { const tAttr = match[2] const tProp = Slim.dashToCamel(tAttr) - const expression = attribute.nodeValue + const expression = attribute.value let oldValue const rxM = Slim.rxMethod.exec(expression) if (rxM) { @@ -778,8 +679,129 @@ + __flags.isChrome && Slim.customDirective(attr => /^s:repeat$/.test(attr.nodeName), (source, templateNode, attribute) => { + let path = attribute.value + let tProp = 'data' + if (path.indexOf(' as' )) { + tProp = path.split(' as ')[1] || tProp + path = path.split(' as ')[0] + } + + let clones = [] + const hook = document.createComment(`${templateNode.localName} s:repeat="${attribute.value}"`) + Slim._$(hook) + Slim.selectRecursive(templateNode, true).forEach(e => Slim._$(e).excluded = true) + templateNode.parentElement.insertBefore(hook, templateNode) + templateNode.remove() + Slim.unbind(source, templateNode) + Slim.asap( () => { + templateNode.setAttribute('s:iterate', '') + templateNode.removeAttribute('s:repeat') + }) + let oldDataSource = [] + Slim.bind(source, hook, path, () => { + const dataSource = Slim.lookup(source, path) || [] + let offset = 0 + let restOfData = [] + // get the diff + const diff = Array(dataSource.length) + dataSource.forEach((d, i) => { + if (oldDataSource[i] !== d) { + diff[i] = true + } + }) + oldDataSource = dataSource.concat() + let indices = Object.keys(diff) + if (dataSource.length < clones.length) { + const disposables = clones.slice(dataSource.length) + clones = clones.slice(0, dataSource.length) + disposables.forEach(clone => clone.remove()) + // unbind disposables? + indices.forEach(index => { + const clone = clones[index] + ;[clone].concat(Slim.qSelectAll(clone, '*')).forEach(t => { + t[_$].repeater[tProp] = dataSource[index] + Slim.commit(t, tProp) + }) + }) + } else { + // recycle + clones.length && indices.forEach(index => { + const clone = clones[index] + if (!clone) return + [clone].concat(Slim.qSelectAll(clone, '*')).forEach(t => { + t[_$].repeater[tProp] = dataSource[index] + Slim.commit(t, tProp) + }) + }) + restOfData = dataSource.slice(clones.length) + offset = clones.length + } + if (!restOfData.length) return + // new clones + const range = document.createRange() + range.setStartBefore(hook) + let html = Array(restOfData.length).fill(templateNode.outerHTML).join('') + const frag = range.createContextualFragment(html) + let all = [] + let i = 0; + while (i < frag.children.length) { + const e = frag.children.item(i) + clones.push(e) + all.push(e) + Slim._$(e).repeater[tProp] = dataSource[i + offset] + const subTree = Slim.qSelectAll(e, '*') + subTree.forEach(t => { + all.push(t) + Slim._$(t).repeater[tProp] = dataSource[i + offset] + Slim.commit(t, tProp) + }) + i++ + } + source._bindChildren(all) + all.forEach(t => { + if (t.__isSlim) { + t.createdCallback() + Slim.asap( () => { + Slim.commit(t, tProp) + t[tProp] = t[_$].repeater[tProp] + }) + } else { + Slim.commit(t, tProp) + t[tProp] = t[_$].repeater[tProp] + } + }) + hook.parentElement.insertBefore(frag, hook) + }) + source[_$].reversed[tProp] = true + }, true) + + + + !__flags.isChrome && Slim.customDirective(attr => /^s:repeat$/.test(attr.nodeName), (source, templateNode, attribute) => { + let path = attribute.nodeValue + let tProp = 'data' + if (path.indexOf(' as' )) { + tProp = path.split(' as ')[1] || tProp + path = path.split(' as ')[0] + } + const repeater = document.createElement('slim-repeat') + repeater[_$].boundParent = source + repeater.dataProp = tProp + repeater.dataPath = attribute.nodeValue + repeater.templateNode = templateNode.cloneNode(true) + repeater.templateNode.removeAttribute('s:repeat') + templateNode.parentNode.insertBefore(repeater, templateNode) + Slim.removeChild(templateNode) + Slim.bind(source, repeater, path, () => { + const dataSource = Slim.lookup(source, path) + repeater.dataSource = dataSource || [] + }) + + // source._executeBindings() + }, true) class SlimRepeater extends Slim { get dataSource () { return this._dataSource } @@ -793,10 +815,10 @@ _bindChildren(tree) { tree = Array.prototype.slice.call(tree) const directChildren = Array.prototype - .filter.call(tree, child => child.parentNode.localName === 'slim-root-fragment') + .filter.call(tree, child => child.parentNode.localName === 'slim-root-fragment') directChildren.forEach((child, index) => { child.setAttribute('s:iterate', `${this.dataPath} : ${index}`) - Slim.selectRecursive(child, true).forEach(e => { + Slim.selectRecursive(child).forEach(e => { Slim._$(e).repeater[this.dataProp] = this.dataSource[index] if (e instanceof Slim) { e[this.dataProp] = this.dataSource[index] @@ -806,25 +828,23 @@ } onRender() { if (!this.boundParent) return - const tree = Slim.selectRecursive(this) + const tree = Slim.selectRecursive(this) this.boundParent && this.boundParent._bindChildren(tree) this.boundParent._executeBindings() } - render() { + render(...args) { if (!this.boundParent) return - Slim.qSelectAll(this, '*').forEach(e => { - Slim.unbind(this.boundParent, e) - }) + Slim.qSelectAll(this, '*').forEach(e => { + Slim.unbind(this.boundParent, e) + }) if (!this.dataSource || !this.templateNode || !this.boundParent) { - super.render('') - } else { - const newTemplate = Array(this.dataSource.length).fill(this.templateNode.outerHTML).join('') - this.innerHTML = ''; - super.render(newTemplate) + return super.render('') } + const newTemplate = Array(this.dataSource.length).fill(this.templateNode.outerHTML).join('') + this.innerHTML = ''; + super.render(newTemplate) } } - Slim.tag('slim-repeat', SlimRepeater) @@ -833,9 +853,6 @@ - - - if (window) { window['Slim'] = Slim }