diff --git a/README.md b/README.md index 3a4f052..f166291 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,11 @@ sf.loader.onFinish(function(){ ``` +Model and controller will be start after content loader was finished. But if you don't use this feature, you need to turn it off with +```js +sf.loader.off(); +``` + ### Router This currently unfinished yet, but you can still use it. diff --git a/dist/scarletsframe.min.js b/dist/scarletsframe.min.js index 9283d92..aee59ad 100644 --- a/dist/scarletsframe.min.js +++ b/dist/scarletsframe.min.js @@ -6,5 +6,5 @@ https://github.com/ScarletsFiction/ScarletsFrame */ -if(sf=function(e){function t(){return e.apply(this,arguments)}return t.toString=function(){return e.toString()},t}(function(){if(arguments[0].constructor===Function)return sf.loader.onFinish.apply(null,arguments)}),sf.internal={},sf.regex={avoidQuotes:"(?=(?:[^\"']*(?:'|\")[^\"']*(?:'|\"))*[^\"']*$)",strictVar:"(?=\\b[^.]|^|\\n| +|\\t|\\W )"},"undefined"==typeof $||!$.fn)if("undefined"!=typeof jQuery)$=jQuery;else{if("undefined"==typeof Dom7)throw"Please load jQuery before ScarletsFrame";$=Dom7}$.fn.extend||($.fn.extend=function(e){for(var t in e)$.fn[t]=e[t]}),$.fn.extend({animateCSS:function(e,t,r){var n=this,o={animation:"animationend",OAnimation:"oAnimationEnd",MozAnimation:"mozAnimationEnd",WebkitAnimation:"webkitAnimationEnd"};for(var i in o)if(void 0!==n[0].style[i]){o=o[i];break}return r&&n.css("-webkit-animation-duration",r+"s").css("animation-duration",r+"s"),n.addClass("animated "+e).one(o,function(){setTimeout(function(){$(n).removeClass("animated "+e)},1),r&&$(n).css("-webkit-animation-duration","").css("animation-duration",""),"function"==typeof t&&t()}),n}}),sf.controller=new function(){var self=this;self.pending={},self.active={},self.for=function(e,t){self.pending[e]=t},self.modelScope=function(e,t){var r=$(e),n=sf.controller.modelName(e);if(!n)throw"model or controller was not found";var o=r.attr("[sf-bind-list]");if(o||(o=r.parents("[sf-bind-list]").attr("sf-bind-list")),!o)return t?t(sf.model.root[n],-1):sf.model.root[n];var i=0;return o&&(i=r.parents("[sf-bind-list]").prevAll("[sf-bind-list]").length),t?t(sf.model.root[n][o],i):sf.model.root[n][o][i]},self.modelName=function(e){var t=void 0;return void 0===(t=e.attributes["sf-controller"]?e.attributes["sf-controller"].value:$(e).parents("[sf-controller]").attr("sf-controller"))||self.active[t]||self.run(t),t};var listenSFClick=function listenSFClick(e){var element=$(e.target),script=element.attr("sf-click");script||(element=element.parents("[sf-click]").eq(0),script=element.attr("sf-click"));var model=element.parents("[sf-controller]").attr("sf-controller");if(!sf.model.root[model])throw"Couldn't find model for "+model+" that was called from sf-click";var _modelScope=sf.model.root[model],modelKeys=sf.model.modelKeys(_modelScope),scopeMask=RegExp(sf.regex.strictVar+"("+modelKeys+")"+sf.regex.avoidQuotes+"\\b","g");script=script.replace(scopeMask,function(e,t){return"_modelScope."+t}),script=script.split("(");var method=script[0],method_=method;try{method=eval(method)}catch(e){method=!1}if(method){script.shift(),script=script.join("("),script=script.split(")"),script.pop(),script=script.join("("),0!==script.length&&(script=eval("["+script+"]")),script||(script=[]);try{method.apply(element[0],script)}catch(e){console.error("Error on sf-click for model: "+model+"\n",e.target,"\n",e)}}else console.error("Error on sf-click for model: "+model+" [Cannot find "+method_+"]\n",e.target)},root_=function(e){return sf.model.root[e]||(sf.model.root[e]={}),sf.model.root[e]||sf.controller.run(e),sf.model.root[e]};self.run=function(e,t){if(!sf.loader.DOMWasLoaded)return sf(function(){self.run(e,t)});self.pending[e]&&(sf.model.root[e]||(sf.model.root[e]={}),self.pending[e](sf.model.root[e],root_),self.active[e]=!0,delete self.pending[e]),t&&t(sf.model.root[e],root_)},self.init=function(e){if(!sf.loader.DOMWasLoaded)return sf(function(){self.init(name)});$("[sf-controller]",e?$(e)[0]:document.body).each(function(){self.run(this.attributes["sf-controller"].value)})},$(document).one("DOMContentLoaded",function(){$(document.body).on("click","[sf-click]",listenSFClick)})},sf.loader=new function(){var e=this;e.loadedContent=0,e.totalContent=0,e.DOMWasLoaded=!1;var t=[],r=[];e.onFinish=function(r){if(e.DOMWasLoaded)return r();-1===t.indexOf(r)&&t.push(r)},e.onProgress=function(t){if(e.DOMWasLoaded)return t(e.loadedContent,e.totalContent);-1===r.indexOf(t)&&r.push(t)},e.f=function(t){e.loadedContent++;for(var n=0;n=0;r--)0!==$('link[href*="'+t[r]+'"]').length&&t.splice(r,1);if(0===t.length)return}e.totalContent=e.totalContent+t.length;var n="";for(r=0;r';$(function(){document.getElementsByTagName("body")[0].innerHTML+=n})},e.js=function(t){if(e.DOMWasLoaded){for(var r=t.length-1;r>=0;r--)0!==$('script[src*="'+t[r]+'"]').length&&t.splice(r,1);if(0===t.length)return}e.totalContent=e.totalContent+t.length;for(r=0;r=0;r--)-1!==t[r].indexOf("$")&&t.splice(r,1);return t.join("|")};var clearElementData=function(e){$&&$.cleanData&&$.cleanData(e.getElementsByTagName("*")),e.innerHTML="";for(var t=0;t=0;a--)i[l[a]]instanceof Function&&l.splice(a,1);var s=RegExp(sf.regex.strictVar+"("+l+")"+sf.regex.avoidQuotes+"\\b","g");if(r)var f=RegExp(sf.regex.strictVar+r+"\\."+sf.regex.avoidQuotes+"\\b","g");return bindingEnabled=!0,e.replace(/{{([^@][\s\S]*?)}}/g,function(e,n){return n=n.split('\\"').join("\\$%*").split("\\'").join("\\%$*"),r&&(n=n.replace(f,function(e){return"_model_."+e[0].slice(1)})),n=(n=n.replace(s,function(e,t){return"_modelScope."+t})).split("\\$%*").join('\\"').split("\\%$*").join("\\'"),(n=""+localEval.apply(self.root,[o+n,t,i])).replace(/[\u00A0-\u9999<>\&]/gim,function(e){return"&#"+e.charCodeAt(0)+";"})})},uniqueDataParser=function(e,t,r,n){var o={length:0,take:function(e,o){if(!e)return dataParser(this[o],t,r,n);var i='"use strict";var ',l=!0;for(var a in e)"string"==typeof e[a]?e[a]='"'+e[a].split('"').join('\\"')+'"':"object"==typeof e[a]&&(e[a]=JSON.stringify(e[a])),l||(i+=","),i+=a+" = "+e[a],l=!1;return i=i.split("(").join("").split(")").join(""),dataParser(this[o],t,r,n,i+";")}};e=e.replace(/{\[([\s\S]*?)\]}/g,function(e,t){return o[o.length]=t,o.length++,"_result_ += _content_.take(&VarPass&, "+(o.length-1)+");"});var i=self.root[n],l=RegExp(sf.regex.strictVar+"("+self.modelKeys(i)+")"+sf.regex.avoidQuotes+"\\b","g");if(r)var a=RegExp(sf.regex.strictVar+r+"\\."+sf.regex.avoidQuotes+"\\b","g");return e.replace(/{{(@[\s\S]*?)}}/g,function(e,n){n=n.split('\\"').join("\\$%*").split("\\'").join("\\%$*"),r&&(n=n.replace(a,function(e){return"_model_."+e[0].slice(1)}));var s=!1;if(1!=(s=(n=(n=n.replace(l,function(e,t){return"_modelScope."+t})).split("\\$%*").join('\\"').split("\\%$*").join("\\'")).split("@if ")).length&&(s=s[1].split(":"),localEval.apply(self.root,[s[0],t,i,o])))return s.shift(),s.join(":");for(var f=/(var|let)([\w,\s]+)(?=\s(?==|in|of))/g,c=[],d=null;null!==(d=f.exec(n));)c.push(d[2]);if(c.length){for(var u=[],p=0;p").split("&").join("&"),n=localEval.apply(self.root,[s,t,i,o])):""})},bindArray=function(e,t,r,n,o,i,l,a){var s=t.slice(0),f=["pop","push","splice","shift","unshift","softRefresh","hardRefresh"],c=-1,d=function(l,a){if(0===(s=$("[sf-controller='"+n+"']",i)).length){if(i.getAttribute("sf-controller")!==n)return;s=i}if(t.$virtual){var s=$(t.$virtual.elements());clearTimeout(c),c=setTimeout(function(){t.$virtual.refresh(!0)},100)}else s=$("[sf-bind-list='"+o+"']",s);var f=!1;if(self.root[n]["on$"+o]&&(f=self.root[n]["on$"+o]),-1===l){for(var d=self.root[n][o],u="",p=0;p=0;i--)d(n+i,"remove");if(arguments.length>=3){o=arguments.length-2;for(i=0;ithis.length)for(i=s.length-1;i>=this.length;i--)-1===this.indexOf(s[i])&&(l=!0,d(i,"remove"));if(s.lengthe.length&&s.splice(e.length),s}}),bindArray(t,s,a,e,l[1],n,o,i)}return i},bindInput=function(e){$("input[sf-bound]",e).each(function(){var e=$(this),t=e.parents("[sf-controller]").attr("sf-controller");if(t){var r=e.attr("sf-bound");void 0!==typeof self.root[t][r]?(e.attr("sf-bounded",r),e.removeAttr("sf-bound"),e.keyup(function(n){self.root[t][r]=e.val()}),e.attr("value","{{"+r+"}}"),bindObject(e,self.root[t],r,"attr")):console.error('Cannot get reference for self.root["'+t+'"]["'+r+'"]')}})},alreadyInitialized=!1;function DOMNodeRemoved(e){var t=sf.controller.modelName(e);$("[sf-bind-id], [sf-bind-list], [sf-bounded], [sf-repeat-this]",e).each(function(){removeBinding(this,t)}),removeBinding(e)}self.init=function(e){alreadyInitialized&&!e||(alreadyInitialized=!0,setTimeout(function(){alreadyInitialized=!1},50),e?e instanceof Node||(e=$(e)[0]):e=document.body,self.parsePreprocess(self.queuePreprocess(e)),bindInput(e),$("[sf-repeat-this]",e).each(function(){var t=$(this),r=t.parent();if(this.parentNode.classList.contains("sf-virtual-list")){var n=$(this.parentNode).children("[sf-repeat-this]")[0].tagName,o=document.createElement(n);o.classList.add("virtual-spacer"),o.classList.add("ceiling"),this.parentNode.prepend(o);var i=document.createElement(n);i.classList.add("virtual-spacer"),i.classList.add("floor"),this.parentNode.append(i);var l=window.getComputedStyle(this),a=parseFloat(l.marginTop)+parseFloat(l.marginBottom);l=null,a=Math.ceil(this.offsetHeight+a)}var s=t.next();s.length&&t[0]!==s[0]||(s=!1);var f=t.prev();f.length&&t[0]!==f[0]||(f=!1);var c=t.attr("sf-repeat-this");t.removeAttr("sf-repeat-this");var d=sf.controller.modelName(this),u=this.outerHTML;if(/sf-bind-id|sf-bind-list/.test(u))throw"Can't parse element that already bound";if(this.parentNode.classList.contains("sf-virtual-list"))loopParser(d,u,c,e,[this.parentNode,a])?t.remove():(t.attr("sf-bind-list",c.split(" in ")[1]),clearElementData(this));else{var p=loopParser(d,u,c,e);p?(t.remove(),p=$(p),s?p.insertBefore(s):f?p.insertAfter(f):r.append(p)):(t.attr("sf-bind-list",c.split(" in ")[1]),clearElementData(this))}}))},$(function(){"function"==typeof MutationObserver&&MutationObserver.prototype.observe?new MutationObserver(function(e){if(bindingEnabled)for(var t in e)for(var r in e[t].removedNodes){var n=e[t].removedNodes[r].nodeName;"TEXT"===n&&"#comment"===n&&DOMNodeRemoved(e[t].removedNodes[r])}}).observe(document.body,{childList:!0,subtree:!0}):document.body.addEventListener("DOMNodeRemoved",function(e){if(bindingEnabled){var t=e.target.nodeName;if("TEXT"!==t||"#comment"!==t)return;DOMNodeRemoved(e.target)}})});var removeBinding=function(e,t){if(e.attributes){var r=e.attributes;if(r["sf-bind-id"]){var n=r["sf-bind-id"].value;if(!bindRef[n])return;for(var o=bindRef[n],i=0;i=0;a--)n[l[a]]instanceof Function&&l.splice(a,1);for(var s,f=RegExp(sf.regex.strictVar+"("+l+")"+sf.regex.avoidQuotes+"\\b","g"),c=null;null!==(s=i.exec(o));)for(;null!==(c=f.exec(s[1]));)bindObject(e,n,c[1],t)},self.queuePreprocess=function(e){for(var t=(e||document.body).childNodes,r=["html","head","style","link","meta","script","object","iframe"],n=0;n").join("--\x3e"),d=JSON.parse(d),!$.isEmptyObject(d)))for(var u=0;u=n.length-n.$virtual.preparedLength)r.floor=n.$virtual.dCursor.floor.offsetTop+2*n.$virtual.scrollHeight;else if(r.floor=o.children[e.prepareCount+3].offsetTop,o.hasAttribute("scroll-reduce-floor")){var l=r.floor-o.getAttribute("scroll-reduce-floor");l>r.ceiling&&(r.floor=l)}}function n(e,t,n,o,i,l){var a=t.$virtual,s=0;if(e>=t.length-a.preparedLength&&(s-=n,e=t.length-a.preparedLength),!(e-a.DOMCursor==0||e>=t.length)){if(updating=!0,0===a.DOMCursor&&ee&&a.DOMCursor+n=n?e0&&(f-=1)}if(e||i.childElementCount-2>t.$virtual.preparedLength){t.$virtual.DOMCursor=t.length;var u=f;e||(u=f<=o?f:f+o),n(u,t,o,i,l,s)}s&&s(f),a&&a(),r(f,t.$virtual.bounding,t,i)}e.prepareCount=4,e.handle=function(a,s,f){t||(!function(){var e=document.getElementById("sf-styles");e||((e=document.createElement("style")).id="sf-styles",document.head.appendChild(e));e.sheet.insertRule(".sf-virtual-list .virtual-spacer{visibility: hidden;position: relative;height: 1px;transform-origin: 0 0;width: 1px;margin: 0;padding: 0;background: none;border: none;box-shadow: none;}")}(),t=!0),a.$virtual.elements=function(){return function(e,t){for(var r=[],n=void 0,o=e.$virtual.DOMCursor,i=0;i0&&(h-=i(r)),f.DOMCursorb.floor&&(!function(){var r=null;g(),null===u.ceiling&&(u.ceiling=u.floor.previousElementSibling);for(var n=0;n0&&(m-=i(r));(m<0||null===r)&&(m=0);for(var o=a.childElementCount-2-t.$virtual.preparedLength,n=0;n=e.prepareCount)c.style.height=(r-e.prepareCount)*f.scrollHeight+"px",d.style.height=(t.length-f.preparedLength-r)*f.scrollHeight+"px";else{c.style.height=r*f.scrollHeight+"px";var n=t.length-f.preparedLength;d.style.height=(n||0)*f.scrollHeight+"px"}}var h=f.bounding;v(0),r(e.prepareCount,h,t,a),h.ceiling=-1,f.offsetTo=function(e){return e*f.scrollHeight+c.offsetTop},f.vCursor.floor=f.dom.firstElementChild,f.scrollTo=function(r){n(r,t,e.prepareCount,a,s,v)},f.refresh=function(r){l(r,t,e.prepareCount,a,s,y,v)};var m=!1,g=!0,b=!1;function y(){if(m||s.scrollTop>=h.ceiling&&s.scrollTop<=h.floor)b&&(0!==s.scrollTop&&s.scrollTop!==s.scrollHeight-s.clientHeight||(o(s),b=!1));else{var n=Math.floor(s.scrollTop/f.scrollHeight);n+f.preparedLength>t.length&&(n=t.length-f.preparedLength),g&&(n<2*e.prepareCount&&(n-=e.prepareCount),b&&(o(s),b=!1),g=!1),n=t.length&&(i=n+i-t.length),0!==i?(f.DOMCursor=n,function(e,t){var r=t.$virtual.dom,n=t.$virtual.vCursor,o=t.$virtual.dCursor;if(e>0){for(var i=0,l=0;l0;l--)null===n.ceiling?(n.ceiling=o.ceiling.nextElementSibling,r.insertAdjacentElement("afterBegin",n.ceiling)):(i=o.ceiling.nextElementSibling,n.ceiling.insertAdjacentElement("afterEnd",i),n.ceiling=i);n.floor=n.ceiling.nextElementSibling}else if(e<0){var i=0;e=-e;for(var l=0;l=0;r--)0!==$('link[href*="'+t[r]+'"]').length&&t.splice(r,1);if(0===t.length)return}e.totalContent=e.totalContent+t.length;var n="";for(r=0;r';$(function(){document.getElementsByTagName("body")[0].innerHTML+=n})},e.js=function(t){if(e.DOMWasLoaded){for(var r=t.length-1;r>=0;r--)0!==$('script[src*="'+t[r]+'"]').length&&t.splice(r,1);if(0===t.length)return}e.totalContent=e.totalContent+t.length;for(r=0;r=0;r--)-1!==t[r].indexOf("$")&&t.splice(r,1);return t.join("|")};var clearElementData=function(e){$&&$.cleanData&&$.cleanData(e.getElementsByTagName("*")),e.innerHTML="";for(var t=0;t=0;a--)i[l[a]]instanceof Function&&l.splice(a,1);var s=RegExp(sf.regex.strictVar+"("+l+")"+sf.regex.avoidQuotes+"\\b","g");if(r)var f=RegExp(sf.regex.strictVar+r+"\\."+sf.regex.avoidQuotes+"\\b","g");return bindingEnabled=!0,e.replace(/{{([^@][\s\S]*?)}}/g,function(e,n){return n=n.split('\\"').join("\\$%*").split("\\'").join("\\%$*"),r&&(n=n.replace(f,function(e){return"_model_."+e[0].slice(1)})),n=(n=n.replace(s,function(e,t){return"_modelScope."+t})).split("\\$%*").join('\\"').split("\\%$*").join("\\'"),(n=""+localEval.apply(self.root,[o+n,t,i])).replace(/[\u00A0-\u9999<>\&]/gim,function(e){return"&#"+e.charCodeAt(0)+";"})})},uniqueDataParser=function(e,t,r,n){var o={length:0,take:function(e,o){if(!e)return dataParser(this[o],t,r,n);var i='"use strict";var ',l=!0;for(var a in e)"string"==typeof e[a]?e[a]='"'+e[a].split('"').join('\\"')+'"':"object"==typeof e[a]&&(e[a]=JSON.stringify(e[a])),l||(i+=","),i+=a+" = "+e[a],l=!1;return i=i.split("(").join("").split(")").join(""),dataParser(this[o],t,r,n,i+";")}};e=e.replace(/{\[([\s\S]*?)\]}/g,function(e,t){return o[o.length]=t,o.length++,"_result_ += _content_.take(&VarPass&, "+(o.length-1)+");"});var i=self.root[n],l=RegExp(sf.regex.strictVar+"("+self.modelKeys(i)+")"+sf.regex.avoidQuotes+"\\b","g");if(r)var a=RegExp(sf.regex.strictVar+r+"\\."+sf.regex.avoidQuotes+"\\b","g");return e.replace(/{{(@[\s\S]*?)}}/g,function(e,n){n=n.split('\\"').join("\\$%*").split("\\'").join("\\%$*"),r&&(n=n.replace(a,function(e){return"_model_."+e[0].slice(1)}));var s=!1;if(1!=(s=(n=(n=n.replace(l,function(e,t){return"_modelScope."+t})).split("\\$%*").join('\\"').split("\\%$*").join("\\'")).split("@if ")).length&&(s=s[1].split(":"),localEval.apply(self.root,[s[0],t,i,o])))return s.shift(),s.join(":");for(var f=/(var|let)([\w,\s]+)(?=\s(?==|in|of))/g,c=[],d=null;null!==(d=f.exec(n));)c.push(d[2]);if(c.length){for(var u=[],p=0;p").split("&").join("&"),n=localEval.apply(self.root,[s,t,i,o])):""})},bindArray=function(e,t,r,n,o,i,l,a){var s=t.slice(0),f=["pop","push","splice","shift","unshift","softRefresh","hardRefresh"],c=-1,d=function(l,a){if(0===(s=$("[sf-controller='"+n+"']",i)).length){if(i.getAttribute("sf-controller")!==n)return;s=i}if(t.$virtual){var s=$(t.$virtual.elements());clearTimeout(c),c=setTimeout(function(){t.$virtual.refresh(!0)},100)}else s=$("[sf-bind-list='"+o+"']",s);var f=!1;if(self.root[n]["on$"+o]&&(f=self.root[n]["on$"+o]),-1===l){for(var d=self.root[n][o],u="",p=0;p=0;i--)d(n+i,"remove");if(arguments.length>=3){o=arguments.length-2;for(i=0;ithis.length)for(i=s.length-1;i>=this.length;i--)-1===this.indexOf(s[i])&&(l=!0,d(i,"remove"));if(s.lengthe.length&&s.splice(e.length),s}}),bindArray(t,s,a,e,l[1],n,o,i)}return i},bindInput=function(e){$("input[sf-bound]",e).each(function(){var e=$(this),t=e.parents("[sf-controller]").attr("sf-controller");if(t){var r=e.attr("sf-bound");void 0!==typeof self.root[t][r]?(e.attr("sf-bounded",r),e.removeAttr("sf-bound"),e.keyup(function(n){self.root[t][r]=e.val()}),e.attr("value","{{"+r+"}}"),bindObject(e,self.root[t],r,"attr")):console.error('Cannot get reference for self.root["'+t+'"]["'+r+'"]')}})},alreadyInitialized=!1;function DOMNodeRemoved(e){var t=sf.controller.modelName(e);$("[sf-bind-id], [sf-bind-list], [sf-bounded], [sf-repeat-this]",e).each(function(){removeBinding(this,t)}),removeBinding(e)}self.init=function(e){alreadyInitialized&&!e||(alreadyInitialized=!0,setTimeout(function(){alreadyInitialized=!1},50),e?e instanceof Node||(e=$(e)[0]):e=document.body,self.parsePreprocess(self.queuePreprocess(e)),bindInput(e),$("[sf-repeat-this]",e).each(function(){var t=$(this),r=t.parent();if(this.parentNode.classList.contains("sf-virtual-list")){var n=$(this.parentNode).children("[sf-repeat-this]")[0].tagName,o=document.createElement(n);o.classList.add("virtual-spacer"),o.classList.add("ceiling"),this.parentNode.prepend(o);var i=document.createElement(n);i.classList.add("virtual-spacer"),i.classList.add("floor"),this.parentNode.append(i);var l=window.getComputedStyle(this),a=parseFloat(l.marginTop)+parseFloat(l.marginBottom);l=null,a=Math.ceil(this.offsetHeight+a)}var s=t.next();s.length&&t[0]!==s[0]||(s=!1);var f=t.prev();f.length&&t[0]!==f[0]||(f=!1);var c=t.attr("sf-repeat-this");t.removeAttr("sf-repeat-this");var d=sf.controller.modelName(this),u=this.outerHTML;if(/sf-bind-id|sf-bind-list/.test(u))throw"Can't parse element that already bound";if(this.parentNode.classList.contains("sf-virtual-list"))loopParser(d,u,c,e,[this.parentNode,a])?t.remove():(t.attr("sf-bind-list",c.split(" in ")[1]),clearElementData(this));else{var p=loopParser(d,u,c,e);p?(t.remove(),p=$(p),s?p.insertBefore(s):f?p.insertAfter(f):r.append(p)):(t.attr("sf-bind-list",c.split(" in ")[1]),clearElementData(this))}}))},$(function(){"function"==typeof MutationObserver&&MutationObserver.prototype.observe?new MutationObserver(function(e){if(bindingEnabled)for(var t in e)for(var r in e[t].removedNodes){var n=e[t].removedNodes[r].nodeName;"TEXT"===n&&"#comment"===n&&DOMNodeRemoved(e[t].removedNodes[r])}}).observe(document.body,{childList:!0,subtree:!0}):document.body.addEventListener("DOMNodeRemoved",function(e){if(bindingEnabled){var t=e.target.nodeName;if("TEXT"!==t||"#comment"!==t)return;DOMNodeRemoved(e.target)}})});var removeBinding=function(e,t){if(e.attributes){var r=e.attributes;if(r["sf-bind-id"]){var n=r["sf-bind-id"].value;if(!bindRef[n])return;for(var o=bindRef[n],i=0;i=0;a--)n[l[a]]instanceof Function&&l.splice(a,1);for(var s,f=RegExp(sf.regex.strictVar+"("+l+")"+sf.regex.avoidQuotes+"\\b","g"),c=null;null!==(s=i.exec(o));)for(;null!==(c=f.exec(s[1]));)bindObject(e,n,c[1],t)},self.queuePreprocess=function(e){for(var t=(e||document.body).childNodes,r=["html","head","style","link","meta","script","object","iframe"],n=0;n").join("--\x3e"),d=JSON.parse(d),!$.isEmptyObject(d)))for(var u=0;u=n.length-n.$virtual.preparedLength)r.floor=n.$virtual.dCursor.floor.offsetTop+2*n.$virtual.scrollHeight;else if(r.floor=o.children[e.prepareCount+3].offsetTop,o.hasAttribute("scroll-reduce-floor")){var l=r.floor-o.getAttribute("scroll-reduce-floor");l>r.ceiling&&(r.floor=l)}}function n(e,t,n,o,i,l){var a=t.$virtual,s=0;if(e>=t.length-a.preparedLength&&(s-=n,e=t.length-a.preparedLength),!(e-a.DOMCursor==0||e>=t.length)){if(updating=!0,0===a.DOMCursor&&ee&&a.DOMCursor+n=n?e0&&(f-=1)}if(e||i.childElementCount-2>t.$virtual.preparedLength){t.$virtual.DOMCursor=t.length;var u=f;e||(u=f<=o?f:f+o),n(u,t,o,i,l,s)}s&&s(f),a&&a(),r(f,t.$virtual.bounding,t,i)}e.prepareCount=4,e.handle=function(a,s,f){t||(!function(){var e=document.getElementById("sf-styles");e||((e=document.createElement("style")).id="sf-styles",document.head.appendChild(e));e.sheet.insertRule(".sf-virtual-list .virtual-spacer{visibility: hidden;position: relative;height: 1px;transform-origin: 0 0;width: 1px;margin: 0;padding: 0;background: none;border: none;box-shadow: none;}")}(),t=!0),a.$virtual.elements=function(){return function(e,t){for(var r=[],n=void 0,o=e.$virtual.DOMCursor,i=0;i0&&(h-=i(r)),f.DOMCursorb.floor&&(!function(){var r=null;g(),null===u.ceiling&&(u.ceiling=u.floor.previousElementSibling);for(var n=0;n0&&(m-=i(r));(m<0||null===r)&&(m=0);for(var o=a.childElementCount-2-t.$virtual.preparedLength,n=0;n=e.prepareCount)c.style.height=(r-e.prepareCount)*f.scrollHeight+"px",d.style.height=(t.length-f.preparedLength-r)*f.scrollHeight+"px";else{c.style.height=r*f.scrollHeight+"px";var n=t.length-f.preparedLength;d.style.height=(n||0)*f.scrollHeight+"px"}}var h=f.bounding;v(0),r(e.prepareCount,h,t,a),h.ceiling=-1,f.offsetTo=function(e){return e*f.scrollHeight+c.offsetTop},f.vCursor.floor=f.dom.firstElementChild,f.scrollTo=function(r){n(r,t,e.prepareCount,a,s,v)},f.refresh=function(r){l(r,t,e.prepareCount,a,s,y,v)};var m=!1,g=!0,b=!1;function y(){if(m||s.scrollTop>=h.ceiling&&s.scrollTop<=h.floor)b&&(0!==s.scrollTop&&s.scrollTop!==s.scrollHeight-s.clientHeight||(o(s),b=!1));else{var n=Math.floor(s.scrollTop/f.scrollHeight);n+f.preparedLength>t.length&&(n=t.length-f.preparedLength),g&&(n<2*e.prepareCount&&(n-=e.prepareCount),b&&(o(s),b=!1),g=!1),n=t.length&&(i=n+i-t.length),0!==i?(f.DOMCursor=n,function(e,t){var r=t.$virtual.dom,n=t.$virtual.vCursor,o=t.$virtual.dCursor;if(e>0){for(var i=0,l=0;l0;l--)null===n.ceiling?(n.ceiling=o.ceiling.nextElementSibling,r.insertAdjacentElement("afterBegin",n.ceiling)):(i=o.ceiling.nextElementSibling,n.ceiling.insertAdjacentElement("afterEnd",i),n.ceiling=i);n.floor=n.ceiling.nextElementSibling}else if(e<0){var i=0;e=-e;for(var l=0;l= 0; i--) {\r\n\t\t\t\tif($('link[href*=\"'+list[i]+'\"]').length!==0)\r\n\t\t\t\t\tlist.splice(i, 1);\r\n\t\t\t}\r\n\t\t\tif(list.length === 0) return;\r\n\t\t}\r\n\t\tself.totalContent = self.totalContent + list.length;\r\n\t\tvar temp = '';\r\n\t\tfor(var i = 0; i < list.length; i++){\r\n\t\t\ttemp += '';\r\n\t\t}\r\n\r\n\t\t$(function(){\r\n\t\t\tdocument.getElementsByTagName('body')[0].innerHTML += temp;\r\n\t\t});\r\n\t}\r\n\r\n\tself.js = function(list){\r\n\t\tif(self.DOMWasLoaded){\r\n\t\t\t// check if some list was loaded\r\n\t\t\tfor (var i = list.length - 1; i >= 0; i--) {\r\n\t\t\t\tif($('script[src*=\"'+list[i]+'\"]').length!==0)\r\n\t\t\t\t\tlist.splice(i, 1);\r\n\t\t\t}\r\n\t\t\tif(list.length === 0) return;\r\n\t\t}\r\n\t\tself.totalContent = self.totalContent + list.length;\r\n\t\tfor(var i = 0; i < list.length; i++){\r\n\t\t\t$.ajax({\r\n\t\t\t url: list[i],\r\n\t\t\t dataType: \"script\",\r\n\t\t\t cache: true,\r\n\t\t\t complete: sf.loader.f\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\tsetTimeout(function(){\r\n\t\tif(self.totalContent === 0)\r\n\t\t\tself.loadedContent = self.totalContent = 1;\r\n\t}, 10000);\r\n\tvar everythingLoaded = setInterval(function() {\r\n\tif (/loaded|complete/.test(document.readyState)) {\r\n\t\tif(self.loadedContent < self.totalContent || self.loadedContent === 0)\r\n\t\t\treturn;\r\n\r\n\t\tclearInterval(everythingLoaded);\r\n\t\tself.DOMWasLoaded = true;\r\n\t\tfor (var i = 0; i < whenDOMLoaded.length; i++) {\r\n\t\t\ttry{\r\n\t\t\t\twhenDOMLoaded[i]();\r\n\t\t\t} catch(e){\r\n\t\t\t\tconsole.error(e);\r\n\t\t\t}\r\n\t\t}\r\n\t\twhenProgress.splice(0);\r\n\t\twhenDOMLoaded.splice(0);\r\n\r\n\t\t// Last init\r\n\t\tsf.controller.init();\r\n\t\tsf.model.init();\r\n\t\tsf.router.init();\r\n\t}\r\n\t}, 100);\r\n};\r\nsf.prototype.constructor = sf.loader.onFinish;\r\n\r\n// Find images\r\n$(function(){\r\n\t$('img:not(onload)[src]').each(function(){\r\n\t\tsf.loader.totalContent++;\r\n\t\tthis.setAttribute('onload', \"sf.loader.f(this)\");\r\n\t});\r\n});","// Data save and HTML content binding\r\nsf.model = function(scope){\r\n\tif(!sf.model.root[scope])\r\n\t\tsf.model.root[scope] = {};\r\n\r\n\tif(sf.controller.pending[scope])\r\n\t\tsf.controller.run(scope);\r\n\r\n\treturn sf.model.root[scope];\r\n};\r\n\r\n(function(){\r\n\tvar self = sf.model;\r\n\tvar bindingEnabled = false;\r\n\tself.root = {};\r\n\r\n\tvar processingElement = null;\r\n\r\n\tvar bracketMatch = RegExp('([\\\\w.]*?[\\\\S\\\\s])\\\\('+sf.regex.avoidQuotes, 'g');\r\n\tvar chackValidFunctionCall = /[a-zA-Z0-9 \\]\\$\\)]/;\r\n\tvar allowedFunction = [':', 'for', 'if', 'while', '_content_.take', 'console.log'];\r\n\tvar localEval = function(script_, _model_, _modelScope, _content_){\r\n\t\tvar script = script_;\r\n\t\tscript_ = script_.split('\\\\\"').join('\\\\$%*').split(\"\\\\'\").join('\\\\%$*'); // ToDo: Escape\r\n\t\tscript_ = script_.split('._modelScope').join('');\r\n\t\tscript_ = script_.split('._model_').join('');\r\n\r\n\t\t// Prevent vulnerability by remove bracket to avoid a function call\r\n\t\tvar preventExecution = false;\r\n\t\tvar check = null;\r\n\t\twhile((check = bracketMatch.exec(script_)) !== null){\r\n\t\t\tcheck[1] = check[1].trim();\r\n\r\n\t\t\tif(allowedFunction.indexOf(check[1]) === -1 &&\r\n\t\t\t\tcheck[1].split('.')[0] !== '_modelScope' &&\r\n\t\t\t\tchackValidFunctionCall.test(check[1][check[1].length-1])\r\n\t\t\t){\r\n\t\t\t\tpreventExecution = check[1];\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\tvar _result_ = '';\r\n\t\tscript_ = script_.split('\\\\$%*').join('\\\\\"').split('\\\\%$*').join(\"\\\\'\"); // ToDo: Unescape\r\n\t\tif(preventExecution){\r\n\t\t\tconsole.error(\"Trying to executing unrecognized function (\"+preventExecution+\")\");\r\n\t\t\tconsole.log($(processingElement.outerHTML)[0]);\r\n\t\t\tconsole.log(script_);\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\ttry{\r\n\t\t\tvar _evaled_ = eval(script_);\r\n\t\t} catch(e){\r\n\t\t\tconsole.error(e);\r\n\t\t\tconsole.log(script_);\r\n\t\t\tconsole.log($(processingElement.outerHTML)[0]);\r\n\t\t\treturn '';\r\n\t\t}\r\n\r\n\t\tif(_result_ !== '') return _result_;\r\n\t\treturn _evaled_;\r\n\t}\r\n\r\n\tself.index = function(element){\r\n\t\tvar i = $(element).prevAll(element.tagName).length;\r\n\t\tvar list = element.getAttribute('sf-bind-list');\r\n\t\tif(!list) return i;\r\n\r\n\t\tvar ref = sf.controller.modelScope(element)[list];\r\n\t\tif(!ref.$virtual) return i;\r\n\r\n\t\treturn i + ref.$virtual.DOMCursor - 1;\r\n\t}\r\n\r\n\tself.for = function(name, func){\r\n\t\tif(!sf.loader.DOMWasLoaded)\r\n\t\t\treturn sf(function(){\r\n\t\t\t\tself.for(name, func);\r\n\t\t\t});\r\n\t\t\r\n\t\tfunc(self(name), self);\r\n\t}\r\n\r\n\tself.modelKeys = function(modelRef){\r\n\t\tvar keys = Object.keys(modelRef);\r\n\t\tfor (var i = keys.length - 1; i >= 0; i--) {\r\n\t\t\tif(keys[i].indexOf('$') !== -1)\r\n\t\t\t\tkeys.splice(i, 1);\r\n\t\t}\r\n\t\treturn keys.join('|');\r\n\t}\r\n\r\n\tvar clearElementData = function(current){\r\n\t\t// Clean associated data on jQuery\r\n\t\tif($ && $.cleanData)\r\n\t\t\t$.cleanData(current.getElementsByTagName(\"*\"));\r\n\r\n\t\tcurrent.innerHTML = '';\r\n\t\tfor (var i = 0; i < current.attributes.length; i++) {\r\n\t\t\tvar name = current.attributes[i].name;\r\n\t\t\tif(name !== 'sf-bind-list')\r\n\t\t\t\tcurrent.removeAttribute(name);\r\n\t\t}\r\n\t\tcurrent.setAttribute('style', 'display:none');\r\n\t}\r\n\r\n\t// For contributor of this library\r\n\t// Please be careful when you're passing the eval argument\r\n\tvar dataParser = function(html, _model_, mask, scope, runEval){\r\n\t\tvar _modelScope = self.root[scope];\r\n\t\tif(!runEval) runEval = '';\r\n\t\t\r\n\t\t// Unmatch any function\r\n\t\tvar variableList = self.modelKeys(_modelScope);\r\n\t\tfor(var i = variableList.length - 1; i >= 0; i--){\r\n\t\t\tif(_modelScope[variableList[i]] instanceof Function)\r\n\t\t\t\tvariableList.splice(i, 1);\r\n\t\t}\r\n\r\n\t\t// Don't match text inside quote, or object keys\r\n\t\tvar scopeMask = RegExp(sf.regex.strictVar+'('+variableList+')'+sf.regex.avoidQuotes+'\\\\b', 'g');\r\n\r\n\t\tif(mask)\r\n\t\t\tvar itemMask = RegExp(sf.regex.strictVar+mask+'\\\\.'+sf.regex.avoidQuotes+'\\\\b', 'g');\r\n\r\n\t\tbindingEnabled = true;\r\n\r\n\t\treturn html.replace(/{{([^@][\\s\\S]*?)}}/g, function(actual, temp){\r\n\t\t\t// ToDo: The regex should be optimized to avoid match in a quote (but not escaped quote)\r\n\t\t\ttemp = temp.split('\\\\\"').join('\\\\$%*').split(\"\\\\'\").join('\\\\%$*'); // ToDo: Escape\r\n\r\n\t\t\t// Mask item variable\r\n\t\t\tif(mask)\r\n\t\t\t\ttemp = temp.replace(itemMask, function(matched){\r\n\t\t\t\t\treturn '_model_.'+matched[0].slice(1);\r\n\t\t\t\t});\r\n\r\n\t\t\t// Mask model for variable\r\n\t\t\ttemp = temp.replace(scopeMask, function(full, matched){\r\n\t\t\t\treturn '_modelScope.'+matched;\r\n\t\t\t});\r\n\r\n\t\t\ttemp = temp.split('\\\\$%*').join('\\\\\"').split('\\\\%$*').join(\"\\\\'\"); // ToDo: Unescape\r\n\r\n\t\t\t// Evaluate\r\n\t\t\ttemp = '' + localEval.apply(self.root, [runEval + temp, _model_, _modelScope]);\r\n\r\n\t\t\treturn temp.replace(/[\\u00A0-\\u9999<>\\&]/gim, function(i) {\r\n\t\t return '&#'+i.charCodeAt(0)+';';\r\n\t\t });\r\n\t\t});\r\n\t}\r\n\r\n\tvar uniqueDataParser = function(html, _model_, mask, scope){\r\n\t\t// Get prepared html content\r\n\t\tvar _content_ = {\r\n\t\t\tlength:0,\r\n\t\t\ttake:function(passVar, currentIndex){\r\n\t\t\t\tif(!passVar)\r\n\t\t\t\t\treturn dataParser(this[currentIndex], _model_, mask, scope);\r\n\r\n\t\t\t\tvar strDeclare = '\"use strict\";var ';\r\n\t\t\t\tvar firstTime = true;\r\n\r\n\t\t\t\tfor(var key in passVar){\r\n\t\t\t\t\tif(typeof passVar[key] === 'string')\r\n\t\t\t\t\t\tpassVar[key] = '\"'+passVar[key].split('\"').join('\\\\\"')+'\"';\r\n\t\t\t\t\telse if(typeof passVar[key] === 'object')\r\n\t\t\t\t\t\tpassVar[key] = JSON.stringify(passVar[key]);\r\n\r\n\t\t\t\t\tif(!firstTime)\r\n\t\t\t\t\t\tstrDeclare += ',';\r\n\r\n\t\t\t\t\tstrDeclare += key + ' = ' + passVar[key];\r\n\t\t\t\t\tfirstTime = false;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Disable function call for addional security eval protection\r\n\t\t\t\tstrDeclare = strDeclare.split('(').join('').split(')').join('');\r\n\r\n\t\t\t\treturn dataParser(this[currentIndex], _model_, mask, scope, strDeclare + ';');\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\thtml = html.replace(/{\\[([\\s\\S]*?)\\]}/g, function(full, matched){\r\n\t\t\t_content_[_content_.length] = matched;\r\n\t\t\t_content_.length++;\r\n\t\t\treturn '_result_ += _content_.take(&VarPass&, '+(_content_.length - 1)+');';\r\n\t\t});\r\n\r\n\t\tvar _modelScope = self.root[scope];\r\n\r\n\t\t// Don't match text inside quote, or object keys\r\n\t\tvar scopeMask = RegExp(sf.regex.strictVar+'('+self.modelKeys(_modelScope)+')'+sf.regex.avoidQuotes+'\\\\b', 'g');\r\n\r\n\t\tif(mask)\r\n\t\t\tvar itemMask = RegExp(sf.regex.strictVar+mask+'\\\\.'+sf.regex.avoidQuotes+'\\\\b', 'g');\r\n\r\n\t\treturn html.replace(/{{(@[\\s\\S]*?)}}/g, function(actual, temp){\r\n\t\t\t// ToDo: The regex should be optimized to avoid match in a quote (but not escaped quote)\r\n\t\t\ttemp = temp.split('\\\\\"').join('\\\\$%*').split(\"\\\\'\").join('\\\\%$*'); // ToDo: Escape\r\n\r\n\t\t\t// Mask item variable\r\n\t\t\tif(mask)\r\n\t\t\t\ttemp = temp.replace(itemMask, function(matched){\r\n\t\t\t\t\treturn '_model_.'+matched[0].slice(1);\r\n\t\t\t\t});\r\n\r\n\t\t\t// Mask model for variable\r\n\t\t\ttemp = temp.replace(scopeMask, function(full, matched){\r\n\t\t\t\treturn '_modelScope.'+matched;\r\n\t\t\t});\r\n\t\t\ttemp = temp.split('\\\\$%*').join('\\\\\"').split('\\\\%$*').join(\"\\\\'\"); // ToDo: Unescape\r\n\r\n\t\t\tvar result = '';\r\n\t\t\tvar check = false;\r\n\r\n\t\t\tcheck = temp.split('@if ');\r\n\t\t\tif(check.length != 1){\r\n\t\t\t\tcheck = check[1].split(':');\r\n\t\t\t\r\n\t\t\t\t// If condition was meet\r\n\t\t\t\tif(localEval.apply(self.root, [check[0], _model_, _modelScope, _content_])){\r\n\t\t\t\t\tcheck.shift();\r\n\t\t\t\t\treturn check.join(':');\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// Get defined variables\r\n\t\t\tvar VarPass_ = /(var|let)([\\w,\\s]+)(?=\\s(?==|in|of))/g;\r\n\t\t\tvar VarPass = [];\r\n\t\t\tvar s1 = null;\r\n\t\t\twhile((s1 = VarPass_.exec(temp)) !== null){\r\n\t\t\t\tVarPass.push(s1[2]);\r\n\t\t\t}\r\n\t\t\tif(VarPass.length){\r\n\t\t\t\tvar obtained = [];\r\n\t\t\t\tfor (var i = 0; i < VarPass.length; i++) {\r\n\t\t\t\t\tVarPass[i].replace(/([\\n\\t\\r]| )+/g, '').split(',').forEach(function(val){\r\n\t\t\t\t\t\tobtained.push(val);\r\n\t\t\t\t\t});\r\n\t\t\t\t};\r\n\t\t\t\tVarPass = obtained;\r\n\t\t\t\tfor (var i = 0; i < VarPass.length; i++) {\r\n\t\t\t\t\tVarPass[i] += ':(typeof '+VarPass[i]+'!=\"undefined\"?'+VarPass[i]+':undefined)';\r\n\t\t\t\t}\r\n\t\t\t\tVarPass = '{'+VarPass.join(',')+'}';\r\n\t\t\t\ttemp = temp.split('&VarPass&').join(VarPass);\r\n\t\t\t}\r\n\t\t\ttemp = temp.split('&VarPass&').join('{}'); \r\n\r\n\t\t\t// Warning! Avoid unencoded user inputted content\r\n\t\t\t// And always check/remove closing ']}' in user content\r\n\t\t\t// Any function call will be removed for addional security\r\n\t\t\tcheck = temp.split('@exec');\r\n\t\t\tif(check.length != 1){\r\n\t\t\t\tcheck = check[1].split('<').join('<').split('>').join('>').split('&').join('&');\r\n\r\n\t\t\t\ttemp = localEval.apply(self.root, [check, _model_, _modelScope, _content_]);\r\n\t\t\t\treturn temp;\r\n\t\t\t}\r\n\t\t\treturn '';\r\n\t\t});\r\n\t}\r\n\r\n\tvar bindArray = function(html, list, mask, modelName, propertyName, targetNode, parentNode, htmlParsedData){\r\n\t\tvar oldArray = list.slice(0);\r\n\t\tvar editProperty = ['pop', 'push', 'splice', 'shift', 'unshift', 'softRefresh', 'hardRefresh'];\r\n\t\tvar refreshTimer = -1;\r\n\t\tvar processElement = function(index, options){\r\n\t\t\tvar exist = $(\"[sf-controller='\"+modelName+\"']\", targetNode);\r\n\t\t\tif(exist.length === 0){\r\n\t\t\t\tif(targetNode.getAttribute('sf-controller') === modelName)\r\n\t\t\t\t\texist = targetNode;\r\n\t\t\t\telse return;\r\n\t\t\t}\r\n\r\n\t\t\tif(list.$virtual){\r\n\t\t\t\tvar exist = $(list.$virtual.elements());\r\n\r\n\t\t\t\tclearTimeout(refreshTimer);\r\n\t\t\t\trefreshTimer = setTimeout(function(){\r\n\t\t\t\t\tlist.$virtual.refresh(true);\r\n\t\t\t\t}, 100);\r\n\t\t\t}\r\n\t\t\telse exist = $(\"[sf-bind-list='\"+propertyName+\"']\", exist);\r\n\r\n\t\t\tvar callback = false;\r\n\t\t\tif(self.root[modelName]['on$'+propertyName])\r\n\t\t\t\tcallback = self.root[modelName]['on$'+propertyName];\r\n\r\n\t\t\t// Hard refresh\r\n\t\t\tif(index === -1){\r\n\t\t\t\tvar item = self.root[modelName][propertyName];\r\n\t\t\t\tvar all = '';\r\n\t\t\t\tfor (var i = 0; i < item.length; i++) {\r\n\t\t\t\t\tvar temp = uniqueDataParser(html, item[i], mask, modelName);\r\n\t\t\t\t\tall += dataParser(temp, item[i], mask, modelName);\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Get first element\r\n\t\t\t\tvar first = exist.eq(0).prev();\r\n\t\t\t\tif(first[0] === exist[0])\r\n\t\t\t\t\texist.parent().prepend(all);\r\n\t\t\t\telse\r\n\t\t\t\t\t$(all).insertAfter(first);\r\n\t\t\t\texist.remove();\r\n\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\t// Remove\r\n\t\t\tif(options === 'remove'){\r\n\t\t\t\tif(exist[index]){\r\n\t\t\t\t\tvar currentRemoved = false;\r\n\t\t\t\t\tvar startRemove = function(){\r\n\t\t\t\t\t\tif(currentRemoved) return;\r\n\t\t\t\t\t\tcurrentRemoved = true;\r\n\r\n\t\t\t\t\t\tif(exist.length <= 1)\r\n\t\t\t\t\t\t\treturn clearElementData(exist[index]);\r\n\r\n\t\t\t\t\t\texist[index].remove();\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif(callback.remove){\r\n\t\t\t\t\t\t// Auto remove if return false\r\n\t\t\t\t\t\tif(!callback.remove(exist[index], startRemove))\r\n\t\t\t\t\t\t\tsetTimeout(startRemove, 800);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t// Auto remove if no callback\r\n\t\t\t\t\telse startRemove();\r\n\t\t\t\t}\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\t// Create or update\r\n\t\t\tvar item = self.root[modelName][propertyName][index];\r\n\r\n\t\t\tvar temp = uniqueDataParser(html, item, mask, modelName);\r\n\t\t\ttemp = dataParser(temp, item, mask, modelName);\r\n\t\t\ttemp = $(temp);\r\n\r\n\t\t\t// Create\r\n\t\t\tif(!exist[index] || options === 'insertAfter'){\r\n\t\t\t\tif(callback.create)\r\n\t\t\t\t\tcallback.create(temp[0]);\r\n\r\n\t\t\t\ttemp.insertAfter(exist[index !== 0 ? index - 1 : (exist.length - 1)]);\r\n\t\t\t}\r\n\r\n\t\t\telse{\r\n\t\t\t\t// Create\r\n\t\t\t\tif(options === 'insertBefore'){\r\n\t\t\t\t\tif(callback.create)\r\n\t\t\t\t\t\tcallback.create(temp[0]);\r\n\r\n\t\t\t\t\ttemp.insertBefore(exist[0]);\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Update\r\n\t\t\t\telse{\r\n\t\t\t\t\tif(callback.update)\r\n\t\t\t\t\t\tcallback.update(temp[0]);\r\n\r\n\t\t\t\t\t// Clean associated data on jQuery\r\n\t\t\t\t\tif($ && $.cleanData){\r\n\t\t\t\t\t\t$.cleanData(exist[index].getElementsByTagName(\"*\"));\r\n\t\t\t\t\t\t$.cleanData(exist[index]);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\texist[index].outerHTML = temp[0].outerHTML;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tvar propertyProxy = function(subject, name){\r\n\t\t\tObject.defineProperty(subject, name, {\r\n\t\t\t\tenumerable: false,\r\n\t\t\t\tconfigurable: true,\r\n\t\t\t\tvalue: function(){\r\n\t\t\t\t\tvar temp = undefined;\r\n\t\t\t\t\tvar lastLength = this.length;\r\n\r\n\t\t\t\t\tif(Array.prototype[name])\r\n\t\t\t\t\t\ttemp = Array.prototype[name].apply(this, arguments);\r\n\r\n\t\t\t\t\tif(name === 'pop')\r\n\t\t\t\t\t\tprocessElement(lastLength - 1, 'remove');\r\n\r\n\t\t\t\t\telse if(name === 'push')\r\n\t\t\t\t\t\tprocessElement(lastLength, 'add');\r\n\r\n\t\t\t\t\telse if(name === 'shift')\r\n\t\t\t\t\t\tprocessElement(0, 'remove');\r\n\r\n\t\t\t\t\telse if(name === 'splice'){\r\n\t\t\t\t\t\t// Removing data\r\n\t\t\t\t\t\tvar real = arguments[0];\r\n\t\t\t\t\t\tif(real < 0) real = lastLength + real;\r\n\r\n\t\t\t\t\t\tvar limit = arguments[1];\r\n\t\t\t\t\t\tif(!limit && limit !== 0) limit = oldArray.length;\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\tfor (var i = limit - 1; i >= 0; i--) {\r\n\t\t\t\t\t\t\tprocessElement(real + i, 'remove');\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tif(arguments.length >= 3){ // Inserting data\r\n\t\t\t\t\t\t\tlimit = arguments.length - 2;\r\n\t\t\t\t\t\t\tfor (var i = 0; i < limit; i++) {\r\n\t\t\t\t\t\t\t\tprocessElement(real + i, 'insertAfter');\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\telse if(name === 'unshift')\r\n\t\t\t\t\t\tprocessElement(0, 'insertBefore');\r\n\r\n\t\t\t\t\telse if(name === 'softRefresh'){\r\n\t\t\t\t\t\tif(arguments[0] || arguments[0] === 0)\r\n\t\t\t\t\t\t\tprocessElement(arguments[0], !!oldArray[arguments[0]] ? 'add':'remove');\r\n\t\t\t\t\t\telse {\r\n\t\t\t\t\t\t\tvar foundChanges = false;\r\n\r\n\t\t\t\t\t\t\t// Removal\r\n\t\t\t\t\t\t\tif(oldArray.length > this.length){\r\n\t\t\t\t\t\t\t\tfor (var i = oldArray.length - 1; i >= this.length; i--) {\r\n\t\t\t\t\t\t\t\t\tif(this.indexOf(oldArray[i]) === -1){\r\n\t\t\t\t\t\t\t\t\t\tfoundChanges = true;\r\n\t\t\t\t\t\t\t\t\t\tprocessElement(i, 'remove');\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t// Creates\r\n\t\t\t\t\t\t\tif(oldArray.length < this.length){\r\n\t\t\t\t\t\t\t\tfor (var i = oldArray.length - 1; i < this.length; i++) {\r\n\t\t\t\t\t\t\t\t\tfoundChanges = true;\r\n\t\t\t\t\t\t\t\t\tprocessElement(i, 'insertBefore');\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t// Update\r\n\t\t\t\t\t\t\tfor (var i = 0; i < this.length; i++) {\r\n\t\t\t\t\t\t\t\tif(compareObject(oldArray[i], this[i]) === false){\r\n\t\t\t\t\t\t\t\t\tfoundChanges = true;\r\n\t\t\t\t\t\t\t\t\tprocessElement(i, 'add');\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tif(foundChanges)\r\n\t\t\t\t\t\t\t\toldArray = this.slice(0);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse if(name === 'hardRefresh')\r\n\t\t\t\t\t\tprocessElement(-1, 'remove');\r\n\r\n\t\t\t\t\tif(Array.prototype[name])\r\n\t\t\t\t\t\toldArray = this.slice(0);\r\n\r\n\t\t\t\t\treturn temp;\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\t// parentNode[0] = element, [1] = child scroll height\r\n\t\tif(parentNode && parentNode[0].classList.contains('sf-virtual-list')){\r\n\t\t\tObject.defineProperty(list, '$virtual', {\r\n\t\t\t\tenumerable: false,\r\n\t\t\t\tconfigurable: true,\r\n\t\t\t\tvalue:{}\r\n\t\t\t});\r\n\r\n\t\t\t// Parse in virtual DOM\r\n\t\t\tlist.$virtual.dom = document.createElement('div');\r\n\t\t\tlist.$virtual.dom.innerHTML = htmlParsedData;\r\n\r\n\t\t\tsf.internal.virtual_scroll.handle(list, targetNode, parentNode[0]);\r\n\t\t}\r\n\r\n\t\tfor (var i = 0; i < editProperty.length; i++) {\r\n\t\t\tpropertyProxy(list, editProperty[i]);\r\n\t\t}\r\n\t}\r\n\r\n\tfunction compareObject(obj1, obj2){\r\n\t\tif(!obj1 || !obj2)\r\n\t\t\treturn false;\r\n\r\n\t\tfor(var i in obj1){\r\n\t\t\tif(typeof obj1[i] !== 'object' && obj1[i] !== obj2[i])\r\n\t\t\t\treturn false;\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\tvar loopParser = function(name, content, script, targetNode, parentNode){\r\n\t\tvar returns = '';\r\n\t\tvar method = script.split(' in ');\r\n\t\tvar mask = method[0];\r\n\r\n\t\tif(!self.root[name])\r\n\t\t\treturn console.error(\"Can't parse element because model for '\"+name+\"' was not found\", $(content)[0]);\r\n\r\n\t\tvar items = self.root[name][method[1]];\r\n\r\n\t\t// Get reference for debugging\r\n\t\tprocessingElement = $(content).attr('sf-bind-list', method[1])[0];\r\n\r\n\t\tcontent = processingElement.outerHTML;\r\n\t\tcontent = content.replace(/ +|\\t+/g, '');\r\n\r\n\t\tif(method.length === 2){\r\n\t\t\tfor(var i in items){\r\n\t\t\t\tvar item = items[i];\r\n\r\n\t\t\t\ttemp = uniqueDataParser(content, item, mask, name);\r\n\t\t\t\ttemp = dataParser(temp, item, mask, name);\r\n\t\t\t\treturns += temp;\r\n\t\t\t}\r\n\t\t\tObject.defineProperty(self.root[name], method[1], {\r\n\t\t\t\tenumerable: true,\r\n\t\t\t\tconfigurable: true,\r\n\t\t\t\tget:function(){\r\n\t\t\t\t\treturn items;\r\n\t\t\t\t},\r\n\t\t\t\tset:function(val){\r\n\t\t\t\t\tfor (var i = 0; i < val.length; i++) {\r\n\t\t\t\t\t\tif(items[i]){\r\n\t\t\t\t\t\t\titems[i] = val[i];\r\n\t\t\t\t\t\t\titems.softRefresh(i);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse items.push(val[i]);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif(items.length > val.length)\r\n\t\t\t\t\t\titems.splice(val.length);\r\n\r\n\t\t\t\t\treturn items;\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t\tbindArray(content, items, mask, name, method[1], targetNode, parentNode, returns);\r\n\t\t}\r\n\t\treturn returns;\r\n\t}\r\n\r\n\tvar bindInput = function(targetNode){\r\n\t\t$('input[sf-bound]', targetNode).each(function(){\r\n\t\t\tvar element = $(this);\r\n\t\t\tvar model = element.parents('[sf-controller]').attr('sf-controller');\r\n\t\t\tif(!model) return;\r\n\r\n\t\t\tvar whichVar = element.attr('sf-bound');\r\n\r\n\t\t\t// Get reference\r\n\t\t\tif(typeof self.root[model][whichVar] === undefined){\r\n\t\t\t\tconsole.error('Cannot get reference for self.root[\"' + model + '\"][\"' + whichVar+'\"]');\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\telement.attr('sf-bounded', whichVar);\r\n\t\t\telement.removeAttr('sf-bound');\r\n\r\n\t\t\t// Bound key up\r\n\t\t\telement.keyup(function(e){\r\n\t\t\t\tself.root[model][whichVar] = element.val();\r\n\t\t\t});\r\n\r\n\t\t\t// Bind value\r\n\t\t\telement.attr('value', '{{'+whichVar+'}}');\r\n\t\t\tbindObject(element, self.root[model], whichVar, 'attr');\r\n\t\t});\r\n\t}\r\n\r\n\tvar alreadyInitialized = false;\r\n\tself.init = function(targetNode){\r\n\t\tif(alreadyInitialized && !targetNode) return;\r\n\t\talreadyInitialized = true;\r\n\t\tsetTimeout(function(){\r\n\t\t\talreadyInitialized = false;\r\n\t\t}, 50);\r\n\r\n\t\tif(targetNode){\r\n\t\t\tif(!(targetNode instanceof Node))\r\n\t\t\t\ttargetNode = $(targetNode)[0];\r\n\t\t}\r\n\t\telse targetNode = document.body;\r\n\r\n\t\tself.parsePreprocess(self.queuePreprocess(targetNode));\r\n\t\tbindInput(targetNode);\r\n\r\n\t\t$('[sf-repeat-this]', targetNode).each(function(){\r\n\t\t\tvar self = $(this);\r\n\t\t\tvar parent = self.parent();\r\n\r\n\t\t\tif(this.parentNode.classList.contains('sf-virtual-list')){\r\n\t\t\t\tvar tagName = $(this.parentNode).children('[sf-repeat-this]')[0].tagName;\r\n\t\t\t\tvar ceiling = document.createElement(tagName);\r\n\t\t\t\tceiling.classList.add('virtual-spacer');\r\n\t\t\t\tceiling.classList.add('ceiling');\r\n\t\t\t\t//ceiling.style.transform = 'scaleY(0)';\r\n\t\t\t\tthis.parentNode.prepend(ceiling);\r\n\r\n\t\t\t\tvar floor = document.createElement(tagName);\r\n\t\t\t\tfloor.classList.add('virtual-spacer');\r\n\t\t\t\tfloor.classList.add('floor');\r\n\t\t\t\t//floor.style.transform = 'scaleY(0)';\r\n\t\t\t\tthis.parentNode.append(floor);\r\n\r\n\t\t\t\t// His total scrollHeight\r\n\t\t\t\tvar styles = window.getComputedStyle(this);\r\n\t\t\t\tvar absHeight = parseFloat(styles['marginTop']) + parseFloat(styles['marginBottom']);\r\n\t\t\t\tstyles = null;\r\n\r\n\t\t\t\t// Element height + margin\r\n\t\t\t\tabsHeight = Math.ceil(this.offsetHeight + absHeight);\r\n\t\t\t}\r\n\r\n\t\t\tvar after = self.next();\r\n\t\t\tif(!after.length || self[0] === after[0])\r\n\t\t\t\tafter = false;\r\n\r\n\t\t\tvar before = self.prev();\r\n\t\t\tif(!before.length || self[0] === before[0])\r\n\t\t\t\tbefore = false;\r\n\r\n\t\t\tvar script = self.attr('sf-repeat-this');\r\n\t\t\tself.removeAttr('sf-repeat-this');\r\n\t\t\tvar controller = sf.controller.modelName(this);\r\n\r\n\t\t\tvar content = this.outerHTML;\r\n\r\n\t\t\t// Check if the element was already bound to prevent vulnerability\r\n\t\t\tif(/sf-bind-id|sf-bind-list/.test(content))\r\n\t\t\t\tthrow \"Can't parse element that already bound\";\r\n\r\n\t\t\tif(this.parentNode.classList.contains('sf-virtual-list')){\r\n\t\t\t\tif(loopParser(controller, content, script, targetNode, [this.parentNode, absHeight]))\r\n\t\t\t\t\tself.remove();\r\n\t\t\t\telse {\r\n\t\t\t\t\tself.attr('sf-bind-list', script.split(' in ')[1]);\r\n\t\t\t\t\tclearElementData(this);\r\n\t\t\t\t}\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tvar data = loopParser(controller, content, script, targetNode);\r\n\t\t\tif(data){\r\n\t\t\t\tself.remove();\r\n\t\t\t\t\r\n\t\t\t\tdata = $(data);\r\n\t\t\t\tif(after)\r\n\t\t\t\t\tdata.insertBefore(after);\r\n\t\t\t\telse if(before)\r\n\t\t\t\t\tdata.insertAfter(before);\r\n\t\t\t\telse\r\n\t\t\t\t\tparent.append(data);\r\n\t\t\t}\r\n\t\t\telse{\r\n\t\t\t\tself.attr('sf-bind-list', script.split(' in ')[1]);\r\n\t\t\t\tclearElementData(this);\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\t// Reset model properties\r\n\t// Don't call if the removed element is TEXT or #comment\r\n\tfunction DOMNodeRemoved(element){\r\n\t\tvar model = sf.controller.modelName(element);\r\n\r\n\t\t$('[sf-bind-id], [sf-bind-list], [sf-bounded], [sf-repeat-this]', element).each(function(){\r\n\t\t\tremoveBinding(this, model);\r\n\t\t});\r\n\r\n\t\tremoveBinding(element);\r\n\t}\r\n\r\n\t$(function(){\r\n\t\tif(typeof MutationObserver === 'function' && MutationObserver.prototype.observe){\r\n\t\t\tvar observer = new MutationObserver(function(records){\r\n\t\t\t\tif(!bindingEnabled) return;\r\n\r\n\t\t\t\tfor(var i in records){\r\n\t\t\t\t\tfor(var a in records[i].removedNodes){\r\n\t\t\t\t\t\tvar tagName = records[i].removedNodes[a].nodeName;\r\n\t\t\t\t\t\tif(tagName !== 'TEXT' || tagName !== '#comment') continue;\r\n\t\t\t\t\t\tDOMNodeRemoved(records[i].removedNodes[a]);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t\tobserver.observe(document.body, { childList: true, subtree: true });\r\n\t\t}\r\n\t\telse {\r\n\t\t\tdocument.body.addEventListener('DOMNodeRemoved', function(e){\r\n\t\t\t\tif(bindingEnabled){\r\n\t\t\t\t\tvar tagName = e.target.nodeName;\r\n\t\t\t\t\tif(tagName !== 'TEXT' || tagName !== '#comment') return;\r\n\t\t\t\t\tDOMNodeRemoved(e.target);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\t});\r\n\r\n\tvar removeBinding = function(element, modelNames){\r\n\t\tif(!element.attributes) return;\r\n\r\n\t\tvar attrs = element.attributes;\r\n\t\tif(attrs['sf-bind-id']){\r\n\t\t\tvar id = attrs['sf-bind-id'].value;\r\n\r\n\t\t\tif(!bindRef[id]) return;\r\n\t\t\tvar ref = bindRef[id];\r\n\r\n\t\t\tfor (var i = 0; i < ref.propertyName.length; i++) {\r\n\t\t\t\tvar value = ref.object[ref.propertyName[i]];\r\n\t\t\t\tObject.defineProperty(ref.object, ref.propertyName[i], {\r\n\t\t\t\t\tconfigurable: true,\r\n\t\t\t\t\tenumerable:true,\r\n\t\t\t\t\twritable:true,\r\n\t\t\t\t\tvalue:value\r\n\t\t\t\t});\r\n\t\t\t}\r\n\r\n\t\t\tdelete bindRef[id];\r\n\r\n\t\t\t// Remove callback left\r\n\t\t\tvar cache = bindRef.cache\r\n\t\t\tfor(var i in cache){\r\n\t\t\t\tif(cache[i].callback && cache[i].callback[id])\r\n\t\t\t\t\tdelete cache[i].callback[id];\r\n\t\t\t\tif($.isEmptyObject(cache[i].callback))\r\n\t\t\t\t\tdelete cache[i];\r\n\t\t\t}\r\n\r\n\t\t\tif(cache[id]){\r\n\t\t\t\tdelete cache[id].attrs;\r\n\t\t\t\tdelete cache[id].innerHTML;\r\n\t\t\t\tdelete cache[id].modelName;\r\n\t\t\t\tdelete cache[id].model;\r\n\t\t\t\tdelete cache[id].created;\r\n\t\t\t\tdelete cache[id].element;\r\n\t\t\t}\r\n\r\n\t\t\tbindRef.length--;\r\n\t\t\tif(bindRef.length === 0)\r\n\t\t\t\tbindRef.index = 0;\r\n\t\t}\r\n\r\n\t\tif(!modelNames) return;\r\n\r\n\t\tvar propertyName = false;\r\n\t\tif(attrs['sf-bind-list']){\r\n\t\t\tpropertyName = attrs['sf-bind-list'].value;\r\n\t\t}\r\n\r\n\t\tif(attrs['sf-repeat-this'])\r\n\t\t\tpropertyName = attrs['sf-repeat-this'].value.split(' in ')[1];\r\n\r\n\t\tif(attrs['sf-bounded'])\r\n\t\t\tpropertyName = attrs['sf-bounded'].value;\r\n\r\n\t\tfor (var i = 0; i < modelNames.length; i++) {\r\n\t\t\tvar modelRef = self.root[modelNames[i]];\r\n\t\t\tif(!modelRef[propertyName]) continue;\r\n\r\n\t\t\tvar value = modelRef[propertyName].slice(0);\r\n\t\t\tObject.defineProperty(modelRef, propertyName, {\r\n\t\t\t\tconfigurable: true,\r\n\t\t\t\tenumerable:true,\r\n\t\t\t\twritable:true,\r\n\t\t\t\tvalue:value\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\t/*{\r\n\t\tid:{\r\n\t\t\tobject,\r\n\t\t\t[propertyName]\r\n\t\t}\r\n\t}*/\r\n\t// For resetting object property it the element was removed from DOM\r\n\tvar bindRef = {length:0, index:0, cache:{}};\r\n\tself.bindRef = bindRef;\r\n\tvar dcBracket = /{{[\\s\\S]*?}}/;\r\n\tvar bindObject = function(element, object, propertyName, which){\r\n\t\tif(!(element instanceof Node))\r\n\t\t\telement = element[0];\r\n\r\n\t\t// Get reference for debugging\r\n\t\tprocessingElement = element;\r\n\r\n\t\t// First initialization\r\n\t\tvar id = bindRef.index;\r\n\t\t$(element).attr('sf-bind-id', id);\r\n\r\n\t\tbindRef.index++;\r\n\t\tbindRef.length++;\r\n\t\tbindRef.cache[id] = {};\r\n\t\tvar cache = bindRef.cache[id];\r\n\r\n\t\tcache.attrs = {};\r\n\t\tcache.innerHTML = '';\r\n\t\tcache.modelName = sf.controller.modelName(element);\r\n\t\tcache.model = self.root[cache.modelName];\r\n\t\tcache.created = Date.now();\r\n\r\n\t\tif(which === 'attr' || !which){\r\n\t\t\tfor(var i in element.attributes){\r\n\t\t\t\t// Check if it has a bracket\r\n\t\t\t\tif(!dcBracket.test(element.attributes[i].value))\r\n\t\t\t\t\tcontinue;\r\n\r\n\t\t\t\tvar attrName = element.attributes[i].name;\r\n\t\t\t\tcache.attrs[attrName] = element.attributes[i].value;\r\n\r\n\t\t\t\tif(attrName === 'value')\r\n\t\t\t\t\telement.removeAttribute(attrName);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif(which === 'html' || !which)\r\n\t\t\tcache.innerHTML = element.innerHTML;\r\n\r\n\t\t// Get current object reference\r\n\t\tif(!bindRef[id]) bindRef[id] = {object:object, propertyName:[]};\r\n\t\tbindRef[id].propertyName.push(propertyName);\r\n\r\n\t\tcache.element = $(element);\r\n\t\tvar callbackFunction = function(){\r\n\t\t\tif(which === 'attr' || !which){\r\n\t\t\t\tfor(var name in cache.attrs){\r\n\t\t\t\t\tif(cache.attrs[name].indexOf(propertyName) === -1)\r\n\t\t\t\t\t\tcontinue;\r\n\r\n\t\t\t\t\tvar temp = dataParser(cache.attrs[name], cache.model, false, cache.modelName);\r\n\t\t\t\t\tif(name === 'value')\r\n\t\t\t\t\t\tcache.element.val(temp);\r\n\t\t\t\t\telse\r\n\t\t\t\t\t\tcache.element.attr(name, temp);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif(which === 'html' || !which){\r\n\t\t\t\tvar temp = uniqueDataParser(cache.innerHTML, cache.model, false, cache.modelName);\r\n\t\t\t\ttemp = dataParser(temp, cache.model, false, cache.modelName);\r\n\t\t\t\tcache.element.html(temp);\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tif(cache.model[propertyName] === undefined) throw \"Property '\"+propertyName+\"' was not found on '\"+cache.modelName+\"' model\";\r\n\t\tif(Object.getOwnPropertyDescriptor(cache.model, propertyName)['set']){\r\n\t\t\tfor(var i in bindRef){\r\n\t\t\t\tif(cache.model === bindRef[i].object && bindRef[i].propertyName.indexOf(propertyName) !== -1){\r\n\t\t\t\t\tbindRef.cache[i].callback[id] = callbackFunction;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tcache.callback = {};\r\n\t\tcache.callback[id] = callbackFunction;\r\n\r\n\t\tvar objValue = object[propertyName]; // Object value\r\n\t\tObject.defineProperty(object, propertyName, {\r\n\t\t\tenumerable: true,\r\n\t\t\tconfigurable: true,\r\n\t\t\tget:function(){\r\n\t\t\t\treturn objValue;\r\n\t\t\t},\r\n\t\t\tset:function(val){\r\n\t\t\t\tobjValue = val;\r\n\r\n\t\t\t\tfor(var i in cache.callback){\r\n\t\t\t\t\tcache.callback[i]();\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn objValue;\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tself.bindElement = function(element, which){\r\n\t\tvar modelName = sf.controller.modelName(element);\r\n\t\tvar model = self.root[modelName];\r\n\t\tif(!model) return console.error(\"Model for \"+modelName+\" was not found while binding:\", element);\r\n\r\n\t\tvar html = element.outerHTML;\r\n\r\n\t\t// Check if the child element was already bound to prevent vulnerability\r\n\t\tif(/sf-bind-id|sf-bind-list/.test(html))\r\n\t\t\tthrow \"Can't parse element that already bound\";\r\n\r\n\t\tif(which === 'attr')\r\n\t\t\thtml = html.replace(element.innerHTML, '');\r\n\r\n\t\tvar brackets = /{{([\\s\\S]*?)}}/g;\r\n\r\n\t\t// Unmatch any function\r\n\t\tvar variableList = self.modelKeys(model);\r\n\t\tfor(var i = variableList.length - 1; i >= 0; i--){\r\n\t\t\tif(model[variableList[i]] instanceof Function)\r\n\t\t\t\tvariableList.splice(i, 1);\r\n\t\t}\r\n\r\n\t\tvar scopeMask = RegExp(sf.regex.strictVar+'('+variableList+')'+sf.regex.avoidQuotes+'\\\\b', 'g');\r\n\t\tvar s1, s2 = null;\r\n\t\twhile((s1 = brackets.exec(html)) !== null){\r\n\t\t\twhile ((s2 = scopeMask.exec(s1[1])) !== null) {\r\n\t\t\t\tbindObject(element, model, s2[1], which);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tself.queuePreprocess = function(targetNode){\r\n\t\tvar childNodes = (targetNode || document.body).childNodes;\r\n\r\n\t\tvar excludes = ['html','head','style','link','meta','script','object','iframe'];\r\n\t\tfor (var i = 0; i < excludes.length; i++) {\r\n\t\t\texcludes[i] = excludes[i].toUpperCase();\r\n\t\t}\r\n\r\n\t\tvar temp = [];\r\n\t\tfor (var i = 0; i < childNodes.length; i++) {\r\n\t\t\tvar currentNode = childNodes[i];\r\n\t\t\tif(excludes.indexOf(currentNode.nodeName) !== -1)\r\n\t\t\t\tcontinue;\r\n\r\n\t\t\tif(currentNode.nodeType === 1){ // Tag\r\n\t\t\t\tvar attrs = currentNode.attributes;\r\n\r\n\t\t\t\t// Skip element and it's childs that already bound to prevent vulnerability\r\n\t\t\t\tif(attrs['sf-bind-id'] || attrs['sf-repeat-this'] || attrs['sf-bind-list']) continue;\r\n\r\n\t\t\t\tfor (var a = 0; a < attrs.length; a++) {\r\n\t\t\t\t\tif(attrs[a].value.indexOf('{{') !== -1){\r\n\t\t\t\t\t\tcurrentNode.setAttribute('sf-preprocess', 'attronly');\r\n\t\t\t\t\t\ttemp.push(currentNode);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\ttemp = temp.concat(self.queuePreprocess(currentNode));\r\n\t\t\t}\r\n\r\n\t\t\telse if(currentNode.nodeType === 3){ // Text\r\n\t\t\t\tif(currentNode.nodeValue.indexOf('{{') !== -1){\r\n\t\t\t\t\tcurrentNode.parentNode.setAttribute('sf-preprocess', '');\r\n\r\n\t\t\t\t\t// Reset Siblings\r\n\t\t\t\t\tfor (var a = 0; a < temp.length; a++) {\r\n\t\t\t\t\t\ttemp[a].removeAttribute('sf-preprocess');\r\n\t\t\t\t\t}\r\n\t\t\t\t\ttemp.push(currentNode.parentNode);\r\n\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn temp;\r\n\t}\r\n\r\n\tself.parsePreprocess = function(nodes){\r\n\t\tfor (var a = 0; a < nodes.length; a++) {\r\n\t\t\tvar model = sf.controller.modelName(nodes[a]);\r\n\t\t\tnodes[a].removeAttribute('sf-preprocess');\r\n\r\n\t\t\tif(!self.root[model])\r\n\t\t\t\treturn console.error(\"Can't parse element because model for '\"+model+\"' was not found\", nodes[a]);\r\n\r\n\t\t\t// Get reference for debugging\r\n\t\t\tprocessingElement = nodes[a];\r\n\r\n\t\t\t// Double check if the child element already bound to prevent vulnerability\r\n\t\t\tif(/sf-bind-id|sf-bind-list/.test(nodes[a].innerHTML)){\r\n\t\t\t\tconsole.error(\"Can't parse element that already bound\");\r\n\t\t\t\tconsole.log($(processingElement.outerHTML)[0]);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif($(nodes[a]).attr('sf-bind'))\r\n\t\t\t\tself.bindElement(nodes[a], $(nodes[a]).attr('sf-bind'));\r\n\r\n\t\t\t// Avoid editing the outerHTML because it will remove the bind\r\n\t\t\tvar temp = uniqueDataParser(nodes[a].innerHTML, self.root[model], false, model);\r\n\t\t\tnodes[a].innerHTML = dataParser(temp, self.root[model], false, model);\r\n\t\t\tfor (var i = 0; i < nodes[a].attributes.length; i++) {\r\n\t\t\t\tif(nodes[a].attributes[i].value.indexOf('{{') !== -1){\r\n\t\t\t\t\tnodes[a].attributes[i].value = dataParser(nodes[a].attributes[i].value, self.root[model], false, model);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n})();","sf.router = new function(){\r\n\tvar self = this;\r\n\tself.loading = false;\r\n\tself.enabled = false;\r\n\tself.pauseRenderOnTransition = false;\r\n\tself.currentPage = [];\r\n\tvar initialized = false;\r\n\tvar lazyRouting = false;\r\n\tvar currentRouterURL = '';\r\n\r\n\t// Should be called if not using lazy page load\r\n\tself.init = function(targetNode){\r\n\t\tif(!sf.loader.DOMWasLoaded)\r\n\t\t\treturn sf(function(){\r\n\t\t\t\tself.init();\r\n\t\t\t});\r\n\r\n\t\t// Reinit lazy router\r\n\t\tself.lazy();\r\n\r\n\t\t// Run 'before' event for new page view\r\n\t\t$('[sf-controller], [sf-page]', $(targetNode)[0]).each(function(){\r\n\t\t\tif(this.attributes['sf-controller'])\r\n\t\t\t\tsf.controller.run(this.attributes['sf-controller'].value);\r\n\t\t\t\r\n\t\t\tif(this.attributes['sf-page']){\r\n\t\t\t\tvar name = this.attributes['sf-page'].value;\r\n\t\t\t\tbeforeEvent(name);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tinitialized = true;\r\n\t\tcurrentRouterURL = window.location.pathname;\r\n\t}\r\n\r\n\tself.enable = function(status){\r\n\t\tif(status === undefined) status = true;\r\n\t\tif(self.enabled === status) return;\r\n\t\tself.enabled = status;\r\n\r\n\t\tif(status)\r\n\t\t\tself.lazy();\r\n\t\telse{\r\n\t\t\t$('a[href][onclick]').each(function(){\r\n\t\t\t\tvar current = $(this);\r\n\t\t\t\tif(current.attr('onclick') === 'return sf.router.load(this)')\r\n\t\t\t\t\tcurrent.removeAttr('onclick');\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\twindow.addEventListener('popstate', function(event) {\r\n\t\t\t// Don't continue if the last routing was error\r\n\t\t\tif(routingError){\r\n\t\t\t\troutingError = false;\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\troutingBack = true;\r\n\t\t\tself.goto(window.location.pathname);\r\n\t\t}, false);\r\n\t}\r\n\r\n\tvar before = {};\r\n\t// Set index with number if you want to replace old function\r\n\tself.before = function(name, func, index){\r\n\t\tif(!before[name])\r\n\t\t\tbefore[name] = [];\r\n\r\n\t\tif(index === undefined){\r\n\t\t\tif(before[name].indexOf(func) === -1)\r\n\t\t\t\tbefore[name].push(func);\r\n\t\t}\r\n\t\telse\r\n\t\t\tbefore[name][index] = func;\r\n\t}\r\n\r\n\tvar after = {};\r\n\t// Set index with number if you want to replace old function\r\n\tself.after = function(name, func, index){\r\n\t\tif(!after[name])\r\n\t\t\tafter[name] = [];\r\n\r\n\t\tif(index === undefined){\r\n\t\t\tif(after[name].indexOf(func) === -1)\r\n\t\t\t\tafter[name].push(func);\r\n\t\t}\r\n\t\telse\r\n\t\t\tafter[name][index] = func;\r\n\t}\r\n\r\n\tvar root_ = function(scope){\r\n\t\tif(!sf.model.root[scope])\r\n\t\t\tsf.model.root[scope] = {};\r\n\r\n\t\tif(!sf.model.root[scope])\r\n\t\t\tsf.controller.run(scope);\r\n\t\t\r\n\t\treturn sf.model.root[scope];\r\n\t}\r\n\r\n\t// Running 'before' new page going to be displayed\r\n\tvar beforeEvent = function(name){\r\n\t\tif(self.currentPage.indexOf(name) === -1)\r\n\t\t\tself.currentPage.push(name);\r\n\r\n\t\tif(before[name]){\r\n\t\t\tfor (var i = 0; i < before[name].length; i++) {\r\n\t\t\t\tbefore[name][i](root_);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t// Running 'after' old page going to be removed\r\n\tvar afterEvent = function(name){\r\n\t\tif(self.currentPage.indexOf(name) === -1)\r\n\t\t\tself.currentPage.splice(self.currentPage.indexOf(name), 1);\r\n\r\n\t\tif(after[name]){\r\n\t\t\tfor (var i = 0; i < after[name].length; i++) {\r\n\t\t\t\tafter[name][i](root_);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tvar onEvent = {\r\n\t\t'loading':[],\r\n\t\t'loaded':[],\r\n\t\t'special':[],\r\n\t\t'error':[]\r\n\t};\r\n\tself.on = function(event, func){\r\n\t\tif(onEvent[event].indexOf(func) === -1)\r\n\t\t\tonEvent[event].push(func);\r\n\t}\r\n\r\n\tself.lazyViewPoint = {};\r\n\t/*\r\n\t\t{\r\n\t\t\toldURlPattern:{\r\n\t\t\t\tnewURLPattern:'.viewPoint'\r\n\t\t\t}\r\n\t\t}\r\n\t*/\r\n\tself.lazy = function(){\r\n\t\tif(!self.enabled) return;\r\n\r\n\t\t$('a[href]:not([onclick])').each(function(){\r\n\t\t\tvar url = this.href;\r\n\t\t\tif(url.indexOf('#') !== -1)\r\n\t\t\t\treturn;\r\n\r\n\t\t\tif(url.indexOf(window.location.origin) !== 0 && url.charAt(0) !== '/')\r\n\t\t\t\treturn; //Not current domain origin\r\n\r\n\t\t\t$(this).attr('onclick', 'return sf.router.load(this)');\r\n\t\t});\r\n\t}\r\n\r\n\tself.load = function(elem){\r\n\t\tif(!history.pushState || $(elem).attr('sf-router') == 'ignore')\r\n\t\t\treturn true;\r\n\r\n\t\treturn !self.goto(elem.href.replace(window.location.origin, ''));\r\n\t}\r\n\r\n\tvar RouterLoading = false;\r\n\tvar routingBack = false;\r\n\tvar routingError = false;\r\n\tself.goto = function(path, data, method){\r\n\t\tif(!method) method = 'GET';\r\n else method = method.toUpperCase();\r\n\r\n\t\tfor (var i = 0; i < onEvent['loading'].length; i++) {\r\n\t\t\tif(onEvent['loading'][i](path)) return;\r\n\t\t}\r\n\t\tvar oldPath = window.location.pathname;\r\n\t\tinitialized = false;\r\n\r\n\t\tif(RouterLoading) RouterLoading.abort();\r\n\t\tRouterLoading = $.ajax({\r\n\t\t\turl:window.location.origin + path,\r\n\t\t\tmethod:method,\r\n data:Object.assign(data, {\r\n _scarlets:'.dynamic.'\r\n }),\r\n\t\t\tsuccess:function(data){\r\n\t\t\t\tif(initialized) return;\r\n\t\t\t\tlazyRouting = true;\r\n\r\n\t\t\t\t// Run 'loaded' event\r\n\t\t\t\tRouterLoading = false;\r\n\r\n\t\t\t\t// Find special data\r\n\t\t\t\tvar regex = RegExp(''+sf.regex.avoidQuotes, 'gm');\r\n\t\t\t\tvar special = regex.exec(data);\r\n\t\t\t\tif(special && special.length !== 1){\r\n\t\t\t\t\tspecial = special[1].split('--|&>').join('-->');\r\n\t\t\t\t\tspecial = JSON.parse(special);\r\n\r\n\t\t\t\t\tif(!$.isEmptyObject(special)){\r\n\t\t\t\t\t\tfor (var i = 0; i < onEvent['special'].length; i++) {\r\n\t\t\t\t\t\t\tif(onEvent['special'][i](special)) return;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvar DOMReference = false;\r\n\t\t\t\tvar foundAction = function(ref){\r\n\t\t\t\t\tDOMReference = $(ref);\r\n\r\n\t\t\t\t\t// Run 'after' event for old page view\r\n\t\t\t\t\tafterEvent($('[sf-page]', DOMReference[0]).attr('sf-page'));\r\n\r\n\t\t\t\t\t// Redefine title if exist\r\n\t\t\t\t\tif(special && special.title)\r\n\t\t\t\t\t\t$('head title').html(special.title);\r\n\r\n\t\t\t\t\tfound = true;\r\n\t\t\t\t};\r\n\r\n\t\t\t\tvar found = false;\r\n\t\t\t\tfor(var oldURL in self.lazyViewPoint){\r\n\t\t\t\t\tif(currentRouterURL.indexOf(oldURL) !== -1){\r\n\t\t\t\t\t\tfor(var newURL in self.lazyViewPoint[oldURL]){\r\n\t\t\t\t\t\t\tif(currentRouterURL.indexOf(oldURL) !== -1){\r\n\t\t\t\t\t\t\t\tfoundAction(self.lazyViewPoint[oldURL][newURL]);\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif(found) break;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// When the view point was not found\r\n\t\t\t\tif(!found){\r\n\t\t\t\t\t// Use fallback if exist\r\n\t\t\t\t\tif(sf.router.lazyViewPoint[\"@default\"])\r\n\t\t\t\t\t\tfoundAction(sf.router.lazyViewPoint[\"@default\"]);\r\n\r\n\t\t\t\t\tif(!found){\r\n\t\t\t\t\t\tfor (var i = 0; i < onEvent['error'].length; i++) {\r\n\t\t\t\t\t\t\tonEvent['error'][i]('sf.router.lazyViewPoint[\"'+oldURL+'\"][\"'+newURL+'\"] was not found');\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Reinit lazy router\r\n\t\t\t\tself.lazy();\r\n\r\n\t\t\t\t// Run 'before' event for new page view\r\n\t\t\t\tif(!DOMReference) DOMReference = $(document.body);\r\n\t\t\t\tif(self.pauseRenderOnTransition)\r\n\t\t\t\t\tself.pauseRenderOnTransition.css('display', 'none');\r\n\r\n\t\t\t\t// Let page script running first, then update the data binding\r\n\t\t\t\tDOMReference.html(data);\r\n\r\n\t\t\t\t// Parse the DOM data binding\r\n\t\t\t\tsf.model.init(DOMReference);\r\n\r\n\t\t\t\t// Init template to model binding\r\n\t\t\t\t$('[sf-page]', DOMReference[0]).each(function(){\r\n\t\t\t\t\tif(this.attributes['sf-page'])\r\n\t\t\t\t\t\tbeforeEvent(this.attributes['sf-page'].value);\r\n\t\t\t\t});\r\n\r\n\t\t\t\tif(self.pauseRenderOnTransition)\r\n\t\t\t\t\tself.pauseRenderOnTransition.css('display', '');\r\n\r\n\t\t\t\trouterLoaded(currentRouterURL, path, DOMReference);\r\n\r\n\t\t\t\tinitialized = true;\r\n\t\t\t\tlazyRouting = false;\r\n\r\n\t\t\t\tcurrentRouterURL = path;\r\n\t\t\t\troutingError = false;\r\n\t\t\t},\r\n\t\t\terror:function(xhr, data){\r\n\t\t\t\troutingError = true;\r\n\t\t\t\tif(xhr.aborted) return;\r\n\r\n\t\t\t\tRouterLoading = false;\r\n\t\t\t\tfor (var i = 0; i < onEvent['error'].length; i++) {\r\n\t\t\t\t\tonEvent['error'][i](xhr.status, data);\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Back on error\r\n\t\t\t\twindow.history.back();\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tif(!routingBack)\r\n\t\t\twindow.history.pushState(null, \"\", path);\r\n\r\n\t\troutingBack = false;\r\n\t\treturn true;\r\n\t}\r\n\r\n\t// Trigger loaded event\r\n\tfunction routerLoaded(currentRouterURL, path, data){\r\n\t\tfor (var i = 0; i < onEvent['loaded'].length; i++) {\r\n\t\t\tonEvent['loaded'][i](currentRouterURL, path, data);\r\n\t\t}\r\n\t}\r\n};","sf.internal.virtual_scroll = new function(){\r\n\tvar self = this;\r\n\tvar styleInitialized = false;\r\n\r\n\t// before and after\r\n\tself.prepareCount = 4; // 4, 8, 12, 16, ...\r\n\r\n\tself.handle = function(list, targetNode, parentNode){\r\n\t\tif(!styleInitialized){\r\n\t\t\tinitStyles();\r\n\t\t\tstyleInitialized = true;\r\n\t\t}\r\n\r\n\t\tlist.$virtual.elements = function(){\r\n\t\t\treturn obtainElements(list, parentNode);\r\n\t\t}\r\n\r\n\t\tlist.$virtual.dCursor = { // DOM Cursor\r\n\t\t\tceiling:parentNode.querySelector('.virtual-spacer.ceiling'),\r\n\t\t\tfloor:parentNode.querySelector('.virtual-spacer.floor')\r\n\t\t};\r\n\r\n\t\tlist.$virtual.bounding = {\r\n\t\t\tceiling:-1,\r\n\t\t\tfloor:0\r\n\t\t}\r\n\r\n\t\tlist.$virtual.vCursor = { // Virtual Cursor\r\n\t\t\tceiling:null, // for forward direction\r\n\t\t\tfloor:null // for backward direction\r\n\t\t}\r\n\r\n\t\tlist.$virtual.targetNode = parentNode;\r\n\t\tlist.$virtual.DOMCursor = 0; // cursor of first element in DOM tree as a cursor\r\n\r\n\t\tlist.$virtual.scrollHeight = \r\n\t\t\tlist.$virtual.dCursor.floor.offsetTop - \r\n\t\t\tlist.$virtual.dCursor.ceiling.offsetTop;\r\n\r\n\t\tvar scroller = null;\r\n\t\tlist.$virtual.destroy = function(){\r\n\t\t\t$(scroller).off();\r\n\t\t\t$(parentNode).off();\r\n\t\t\tlist.$virtual.dom.innerHTML = '';\r\n\t\t\tdelete list.$virtual;\r\n\t\t}\r\n\r\n\t\tlist.$virtual.resetViewport = function(){\r\n\t\t\tlist.$virtual.visibleLength = Math.floor(scroller.clientHeight / list.$virtual.scrollHeight);\r\n\t\t\tlist.$virtual.preparedLength = list.$virtual.visibleLength + self.prepareCount * 2;\r\n\t\t}\r\n\r\n\t\tsetTimeout(function(){\r\n\t\t\tscroller = parentNode;\r\n\r\n\t\t\tvar length = parentNode.getAttribute('scroll-parent-index') || 0;\r\n\t\t\tfor (var i = 0; i < length; i++) {\r\n\t\t\t\tscroller = scroller.parentElement;\r\n\t\t\t}\r\n\r\n\t\t\tlist.$virtual.resetViewport();\r\n\r\n\t\t\tif(parentNode.classList.contains('sf-list-dynamic'))\r\n\t\t\t\tdynamicHeight(list, targetNode, parentNode, scroller);\r\n\t\t\telse\r\n\t\t\t\tstaticHeight(list, targetNode, parentNode, scroller);\r\n\t\t}, 500);\r\n\t}\r\n\r\n\t// Recommended for a list that have different element height\r\n\tfunction dynamicHeight(list, targetNode, parentNode, scroller){\r\n\t\tvar virtual = list.$virtual;\r\n\t\tvar ceiling = virtual.dCursor.ceiling;\r\n\t\tvar floor = virtual.dCursor.floor;\r\n\t\tvar vCursor = virtual.vCursor;\r\n\t\tvCursor.floor = virtual.dom.firstElementChild;\r\n\t\t\r\n\t\tvirtual.scrollTo = function(index){\r\n\t\t\tscrollTo(index, list, self.prepareCount, parentNode, scroller);\r\n\t\t}\r\n\r\n\t\tvirtual.refresh = function(force){\r\n\t\t\trefresh(force, list, self.prepareCount, parentNode, scroller);\r\n\t\t}\r\n\r\n\t\t// Insert some element until reach visible height\r\n\t\tfillViewport();\r\n\r\n\t\tvirtual.visibleLength = parentNode.childElementCount - 2;\r\n\t\tvirtual.preparedLength = virtual.visibleLength + self.prepareCount * 2;\r\n\r\n\t\tfor (var i = 0; i < self.prepareCount; i++) {\r\n\t\t\tvar temp = vCursor.floor;\r\n\t\t\tif(temp === null) break;\r\n\r\n\t\t\tvCursor.floor = temp.nextElementSibling;\r\n\t\t\tfloor.insertAdjacentElement('beforeBegin', temp);\r\n\t\t}\r\n\t\tvirtual.DOMCursor = 0;\r\n\r\n\t\tvar ceilingHeight = 0;\r\n\t\tvar floorHeight = 0;\r\n\t\tfunction previousCeiling(){\r\n\t\t\tvar temp = null;\r\n\t\t\tvar resetCeiling = false;\r\n\r\n\t\t\t// Add some element on the ceiling\r\n\t\t\tfor (var i = 0; i < self.prepareCount; i++) {\r\n\t\t\t\tif(vCursor.floor === null)\r\n\t\t\t\t\ttemp = virtual.dom.lastElementChild;\r\n\t\t\t\telse\r\n\t\t\t\t\ttemp = vCursor.floor.previousElementSibling;\r\n\r\n\t\t\t\tif(temp === null) break;\r\n\t\t\t\tvCursor.ceiling = temp.previousElementSibling;\r\n\t\t\t\tvirtual.DOMCursor--;\r\n\r\n\t\t\t\tceiling.insertAdjacentElement('afterEnd', temp);\r\n\r\n\t\t\t\tif(ceilingHeight > 0)\r\n\t\t\t\t\tceilingHeight -= getAbsoluteHeight(temp);\r\n\r\n\t\t\t\tif(virtual.DOMCursor < self.prepareCount && !resetCeiling){\r\n\t\t\t\t\ti = 0;\r\n\t\t\t\t\tresetCeiling = true;\r\n\t\t\t\t\ttemp = null;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif(ceilingHeight < 0 || temp === null)\r\n\t\t\t\tceilingHeight = 0;\r\n\r\n\t\t\tvar length = parentNode.childElementCount - 2 - list.$virtual.preparedLength;\r\n\t\t\t// Remove some element on the floor\r\n\t\t\tfor (var i = 0; i < length; i++) {\r\n\t\t\t\ttemp = floor.previousElementSibling;\r\n\t\t\t\tfloorHeight += getAbsoluteHeight(temp);\r\n\r\n\t\t\t\tif(vCursor.floor === null)\r\n\t\t\t\t\tvirtual.dom.insertAdjacentElement('beforeEnd', temp);\r\n\t\t\t\telse vCursor.floor.insertAdjacentElement('beforeBegin', temp);\r\n\r\n\t\t\t\tvCursor.floor = temp;\r\n\t\t\t}\r\n\r\n\t\t\tif(vCursor.floor === null)\r\n\t\t\t\tvCursor.ceiling = virtual.dom.lastElementChild;\r\n\t\t\telse \r\n\t\t\t\tvCursor.ceiling = vCursor.floor.previousElementSibling;\r\n\r\n\t\t\tceiling.style.height = ceilingHeight+'px';\r\n\t\t\tfloor.style.height = floorHeight+'px';\r\n\t\t}\r\n\r\n\t\tfunction fillViewport(){\r\n\t\t\t// Insert some element depend on prepared length\r\n\t\t\tvar length = virtual.preparedLength - (parentNode.childElementCount - 2);\r\n\t\t\tfor (var i = 0; i < length; i++) {\r\n\t\t\t\tif(vCursor.ceiling === null)\r\n\t\t\t\t\ttemp = virtual.dom.firstElementChild;\r\n\t\t\t\telse\r\n\t\t\t\t\ttemp = vCursor.ceiling.nextElementSibling;\r\n\r\n\t\t\t\tif(temp === null) break;\r\n\t\t\t\tvCursor.floor = temp.nextElementSibling;\r\n\r\n\t\t\t\tfloor.insertAdjacentElement('beforeBegin', temp);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tfunction nextFloor(){\r\n\t\t\tvar temp = null;\r\n\t\t\tfillViewport();\r\n\r\n\t\t\tif(vCursor.ceiling === null)\r\n\t\t\t\tvCursor.ceiling = vCursor.floor.previousElementSibling;\r\n\r\n\t\t\t// Add extra element based on prepare count\r\n\t\t\tfor (var i = 0; i < self.prepareCount; i++) {\r\n\t\t\t\ttemp = vCursor.floor;\r\n\t\t\t\tif(temp === null) break;\r\n\r\n\t\t\t\tvCursor.floor = temp.nextElementSibling;\r\n\t\t\t\tfloor.insertAdjacentElement('beforeBegin', temp);\r\n\r\n\t\t\t\tif(floorHeight > 0)\r\n\t\t\t\t\tfloorHeight -= getAbsoluteHeight(temp);\r\n\t\t\t}\r\n\r\n\t\t\tif(floorHeight < 0 || temp === null)\r\n\t\t\t\tfloorHeight = 0;\r\n\r\n\t\t\t// Remove some element on the ceiling\r\n\t\t\tvar length = parentNode.childElementCount - 2 - list.$virtual.preparedLength;\r\n\t\t\tfor (var i = 0; i < length; i++) {\r\n\t\t\t\ttemp = ceiling.nextElementSibling;\r\n\t\t\t\tceilingHeight += getAbsoluteHeight(temp);\r\n\t\t\t\tvirtual.DOMCursor++;\r\n\r\n\t\t\t\tif(vCursor.ceiling === null)\r\n\t\t\t\t\tvirtual.dom.insertAdjacentElement('afterBegin', temp);\r\n\t\t\t\telse vCursor.ceiling.insertAdjacentElement('afterEnd', temp);\r\n\r\n\t\t\t\tvCursor.ceiling = temp;\r\n\t\t\t}\r\n\r\n\t\t\tif(vCursor.ceiling === null)\r\n\t\t\t\tvCursor.floor = virtual.dom.firstElementChild;\r\n\t\t\telse \r\n\t\t\t\tvCursor.floor = vCursor.ceiling.nextElementSibling;\r\n\r\n\t\t\tceiling.style.height = ceilingHeight+'px';\r\n\t\t\tfloor.style.height = floorHeight+'px';\r\n\t\t}\r\n\r\n\t\tvar bounding = virtual.bounding;\r\n\t\trefreshScrollBounding(0, bounding, list, parentNode);\r\n\r\n\t\tvar updating = false;\r\n\t\tfunction checkCursorPosition(){\r\n\t\t\tif(updating) return;\r\n\t\t\tupdating = true;\r\n\r\n\t\t\tif(scroller.scrollTop < bounding.ceiling){\r\n\t\t\t\t// console.log('back', bounding, scroller.scrollTop, virtual.DOMCursor);\r\n\t\t\t\tpreviousCeiling();\r\n\t\t\t\trefreshScrollBounding(virtual.DOMCursor, bounding, list, parentNode);\r\n\t\t\t\t// console.warn('back', bounding, scroller.scrollTop, virtual.DOMCursor);\r\n\t\t\t}\r\n\r\n\t\t\telse if(scroller.scrollTop > bounding.floor){\r\n\t\t\t\t// console.log('front', bounding, scroller.scrollTop, virtual.DOMCursor);\r\n\t\t\t\tnextFloor();\r\n\t\t\t\trefreshScrollBounding(virtual.DOMCursor, bounding, list, parentNode);\r\n\t\t\t\t// console.warn('front', bounding, scroller.scrollTop, virtual.DOMCursor);\r\n\t\t\t}\r\n\r\n\t\t\tupdating = false;\r\n\t\t}\r\n\r\n\t\t$(scroller).on('scroll', checkCursorPosition);\r\n\t\t$(scroller).on('resize', function(){\r\n\t\t\tfillViewport();\r\n\t\t\trefreshScrollBounding(virtual.DOMCursor, bounding, list, parentNode);\r\n\t\t});\r\n\t}\r\n\r\n\t// Recommended for a list that have similar element height\r\n\tfunction staticHeight(list, targetNode, parentNode, scroller){\r\n\t\tvar virtual = list.$virtual;\r\n\t\tvar ceiling = virtual.dCursor.ceiling;\r\n\t\tvar floor = virtual.dCursor.floor;\r\n\r\n\t\t// Insert visible element to dom tree\r\n\t\tvar insertCount = virtual.preparedLength <= list.length ? virtual.preparedLength : list.length;\r\n\t\tfor (var i = 0; i < insertCount; i++) {\r\n\t\t\tif(virtual.dom.firstElementChild === null)\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tfloor.insertAdjacentElement('beforeBegin', virtual.dom.firstElementChild);\r\n\t\t}\r\n\r\n\t\tfunction refreshVirtualSpacer(cursor){\r\n\t\t\tif(cursor >= self.prepareCount){\r\n\t\t\t\tceiling.style.height = (cursor - self.prepareCount) * virtual.scrollHeight + 'px';\r\n\t\t\t\tfloor.style.height = (list.length - virtual.preparedLength - cursor) * virtual.scrollHeight + 'px';\r\n\t\t\t}\r\n\t\t\telse{\r\n\t\t\t\tceiling.style.height = cursor * virtual.scrollHeight + 'px'; //'0px';\r\n\t\t\t\tvar count = (list.length - virtual.preparedLength);\r\n\t\t\t\tfloor.style.height = (count || 0) * virtual.scrollHeight + 'px';\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tvar bounding = virtual.bounding;\r\n\r\n\t\trefreshVirtualSpacer(0);\r\n\t\trefreshScrollBounding(self.prepareCount, bounding, list, parentNode);\r\n\t\tbounding.ceiling = -1;\r\n\r\n\t\tvirtual.offsetTo = function(index){\r\n\t\t\treturn index * virtual.scrollHeight + ceiling.offsetTop;\r\n\t\t}\r\n\r\n\t\tvar vCursor = virtual.vCursor;\r\n\t\tvCursor.floor = virtual.dom.firstElementChild;\r\n\t\tvirtual.scrollTo = function(index){\r\n\t\t\tscrollTo(index, list, self.prepareCount, parentNode, scroller, refreshVirtualSpacer);\r\n\t\t}\r\n\r\n\t\tvirtual.refresh = function(force){\r\n\t\t\trefresh(force, list, self.prepareCount, parentNode, scroller, checkCursorPosition, refreshVirtualSpacer);\r\n\t\t}\r\n\r\n\t\tvar updating = false;\r\n\t\tvar fromCeiling = true;\r\n\t\tvar scrollFocused = false;\r\n\t\tfunction checkCursorPosition(){\r\n\t\t\tif(updating || scroller.scrollTop >= bounding.ceiling && scroller.scrollTop <= bounding.floor){\r\n\t\t\t\t// Fix chrome scroll anchoring bugs when scrolling at corner\r\n\t\t\t\tif(scrollFocused){\r\n\t\t\t\t\tif(scroller.scrollTop === 0 || scroller.scrollTop === scroller.scrollHeight - scroller.clientHeight){\r\n\t\t\t\t\t\tremoveUserScrollFocus(scroller);\r\n\t\t\t\t\t\tscrollFocused = false;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tvar cursor = Math.floor(scroller.scrollTop / virtual.scrollHeight);\r\n\t\t\tif(cursor + virtual.preparedLength > list.length)\r\n\t\t\t\tcursor = list.length - virtual.preparedLength;\r\n\r\n\t\t\tif(fromCeiling){\r\n\t\t\t\tif(cursor < self.prepareCount*2)\r\n\t\t\t\t\tcursor -= self.prepareCount;\r\n\r\n\t\t\t\t// Fix chrome scroll anchoring bugs\r\n\t\t\t\tif(scrollFocused){\r\n\t\t\t\t\tremoveUserScrollFocus(scroller);\r\n\t\t\t\t\tscrollFocused = false;\r\n\t\t\t\t}\r\n\t\t\t\tfromCeiling = false;\r\n\t\t\t}\r\n\r\n\t\t\tif(cursor < self.prepareCount){\r\n\t\t\t\tcursor = 0;\r\n\t\t\t\tfromCeiling = true;\r\n\t\t\t}\r\n\r\n\t\t\tupdating = true;\r\n\r\n\t\t\tvar changes = cursor - virtual.DOMCursor;\r\n\t\t\tif(cursor + changes >= list.length)\r\n\t\t\t\tchanges = cursor + changes - list.length;\r\n\r\n\t\t\tif(changes === 0){ // This should be fixed to improve performance and future bugs\r\n\t\t\t\t//console.warn(\"No changes (The scroll bounding is not correct)\");\r\n\t\t\t\tupdating = false;\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tvirtual.DOMCursor = cursor;\r\n\r\n\t\t\t//console.log(cursor, changes);\r\n\r\n\t\t\t//console.log(cursor, changes, bounding.ceiling, bounding.floor, scroller.scrollTop);\r\n\t\t\tmoveElementCursor(changes, list);\r\n\t\t\trefreshVirtualSpacer(cursor);\r\n\t\t\trefreshScrollBounding(cursor, bounding, list, parentNode);\r\n\t\t\t//console.log('a', bounding.ceiling, bounding.floor, scroller.scrollTop);\r\n\r\n\t\t\tupdating = false;\r\n\t\t}\r\n\r\n\t\t$(scroller).on('scroll', checkCursorPosition);\r\n\r\n\t\t// For preventing scroll jump if scrolling over than viewport\r\n\t\tif(scroller === parentNode && navigator.userAgent.indexOf('Chrom') !== -1){\r\n\t\t\t$(parentNode).on('mousedown', function(){\r\n\t\t\t\tscrollFocused = true;\r\n\t\t\t});\r\n\t\t\t$(parentNode).on('mouseup', function(){\r\n\t\t\t\tscrollFocused = false;\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\tfunction refreshScrollBounding(cursor, bounding, list, parentNode){\r\n\t\tvar temp = Math.floor(self.prepareCount / 2); // half of element preparation\r\n\t\tif(cursor < self.prepareCount){\r\n\t\t\tbounding.ceiling = -1;\r\n\t\t\tbounding.floor = parentNode.children[self.prepareCount * 2 + 1];\r\n\r\n\t\t\tif(bounding.floor !== undefined)\r\n\t\t\t\tbounding.floor = bounding.floor.offsetTop;\r\n\t\t\telse bounding.floor = parentNode.lastElementChild.offsetTop + 1000;\r\n\r\n\t\t\treturn;\r\n\t\t}\r\n\t\telse if(parentNode.children[temp + 1] !== undefined)\r\n\t\t\t\tbounding.ceiling = parentNode.children[temp + 1].offsetTop; // -2 element\r\n\r\n\t\tif(list.$virtual.preparedLength !== undefined && cursor >= list.length - list.$virtual.preparedLength)\r\n\t\t\tbounding.floor = list.$virtual.dCursor.floor.offsetTop + list.$virtual.scrollHeight*2;\r\n\t\telse{\r\n\t\t\tbounding.floor = parentNode.children[self.prepareCount + 3].offsetTop; // +2 element\r\n\r\n\t\t\tif(parentNode.hasAttribute('scroll-reduce-floor')){\r\n\t\t\t\tvar currentFloor = bounding.floor - parentNode.getAttribute('scroll-reduce-floor');\r\n\t\t\t\tif(currentFloor > bounding.ceiling)\r\n\t\t\t\t\tbounding.floor = currentFloor;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tfunction moveElementCursor(changes, list){\r\n\t\tvar vDOM = list.$virtual.dom;\r\n\t\tvar vCursor = list.$virtual.vCursor;\r\n\t\tvar dCursor = list.$virtual.dCursor;\r\n\r\n\t\tif(changes > 0){ // forward\r\n\t\t\tvar ref = 0;\r\n\r\n\t\t\t// Select from virtual ceiling cursor to Dom tree\r\n\t\t\tfor (var i = 0; i < changes; i++) { // vDom -> Dom tree\r\n\t\t\t\tif(vCursor.ceiling === null)\r\n\t\t\t\t\tref = vDOM.firstElementChild;\r\n\r\n\t\t\t\telse ref = vCursor.ceiling.nextElementSibling;\r\n\t\t\t\tdCursor.floor.insertAdjacentElement('beforeBegin', ref);\r\n\t\t\t}\r\n\r\n\t\t\t// Move element on the ceiling to vDom\r\n\t\t\tfor (var i = changes; i > 0; i--) { // Dom tree -> vDom\r\n\t\t\t\tif(vCursor.ceiling === null){\r\n\t\t\t\t\tvCursor.ceiling = dCursor.ceiling.nextElementSibling;\r\n\t\t\t\t\tvDOM.insertAdjacentElement('afterBegin', vCursor.ceiling);\r\n\t\t\t\t}\r\n\t\t\t\telse{\r\n\t\t\t\t\tref = dCursor.ceiling.nextElementSibling;\r\n\t\t\t\t\tvCursor.ceiling.insertAdjacentElement('afterEnd', ref);\r\n\t\t\t\t\tvCursor.ceiling = ref;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tvCursor.floor = vCursor.ceiling.nextElementSibling;\r\n\t\t}\r\n\t\telse if(changes < 0){ // backward\r\n\t\t\tvar ref = 0;\r\n\t\t\tchanges = -changes;\r\n\r\n\t\t\t// Select from virtual floor cursor to Dom tree\r\n\t\t\tfor (var i = 0; i < changes; i++) { // vDom -> Dom tree\r\n\t\t\t\tif(vCursor.floor === null)\r\n\t\t\t\t\tref = vDOM.lastElementChild;\r\n\r\n\t\t\t\telse ref = vCursor.floor.previousElementSibling;\r\n\t\t\t\tdCursor.ceiling.insertAdjacentElement('afterEnd', ref);\r\n\t\t\t}\r\n\r\n\t\t\t// Move element on the floor to vDom\r\n\t\t\tfor (var i = 0; i < changes; i++) { // Dom tree -> vDom\r\n\t\t\t\tif(vCursor.floor === null){\r\n\t\t\t\t\tvCursor.floor = dCursor.floor.previousElementSibling;\r\n\t\t\t\t\tvDOM.insertAdjacentElement('beforeEnd', vCursor.floor);\r\n\t\t\t\t}\r\n\r\n\t\t\t\telse{\r\n\t\t\t\t\tref = dCursor.floor.previousElementSibling;\r\n\t\t\t\t\tvCursor.floor.insertAdjacentElement('beforeBegin', ref);\r\n\t\t\t\t\tvCursor.floor = ref;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tvCursor.ceiling = vCursor.floor.previousElementSibling;\r\n\t\t}\r\n\t}\r\n\r\n\tfunction scrollTo(index, list, prepareCount, parentNode, scroller, refreshVirtualSpacer){\r\n\t\tvar virtual = list.$virtual;\r\n\t\tvar reduce = 0;\r\n\r\n\t\tif(index >= list.length - virtual.preparedLength){\r\n\t\t\treduce -= prepareCount;\r\n\t\t\tindex = list.length - virtual.preparedLength;\r\n\t\t}\r\n\r\n\t\tif(index - virtual.DOMCursor === 0 || index >= list.length) return;\r\n\r\n\t\tupdating = true;\r\n\r\n\t\t// Already on DOM tree\r\n\t\tif((virtual.DOMCursor === 0 && index < prepareCount + prepareCount/2) ||\r\n\t\t\t(virtual.DOMCursor + prepareCount/2 > index\r\n\t\t\t&& virtual.DOMCursor + prepareCount < index))\r\n\t\t\tscroller.scrollTop = parentNode.children[index - virtual.DOMCursor + 1].offsetTop;\r\n\r\n\t\t// Move cursor\r\n\t\telse {\r\n\t\t\tvar temp = null;\r\n\t\t\tvar ceiling = virtual.dCursor.ceiling;\r\n\t\t\tvar floor = virtual.dCursor.floor;\r\n\t\t\tvar vCursor = virtual.vCursor;\r\n\r\n\t\t\t// DOM tree to virtual DOM\r\n\t\t\tvar length = parentNode.childElementCount - 2;\r\n\t\t\tfor (var i = 0; i < length; i++) {\r\n\t\t\t\ttemp = ceiling.nextElementSibling;\r\n\r\n\t\t\t\tif(vCursor.floor === null){\r\n\t\t\t\t\tvirtual.dom.insertAdjacentElement('beforeEnd', temp);\r\n\r\n\t\t\t\t\tif(i === length-1)\r\n\t\t\t\t\t\tvCursor.floor = temp;\r\n\t\t\t\t}\r\n\t\t\t\telse vCursor.floor.insertAdjacentElement('beforeBegin', temp);\r\n\t\t\t}\r\n\r\n\t\t\tif(index >= prepareCount){\r\n\t\t\t\tif(index < list.length - virtual.preparedLength)\r\n\t\t\t\t\tindex -= prepareCount;\r\n\t\t\t}\r\n\t\t\telse{\r\n\t\t\t\treduce = prepareCount - index;\r\n\t\t\t\tvirtual.DOMCursor = index = 0;\r\n\t\t\t}\r\n\r\n\t\t\tvar insertCount = virtual.preparedLength <= list.length ? virtual.preparedLength : list.length;\r\n\r\n\t\t\t// Virtual DOM to DOM tree\r\n\t\t\tfor (var i = 0; i < insertCount; i++) {\r\n\t\t\t\ttemp = virtual.dom.children[index];\r\n\t\t\t\tif(temp === undefined) break;\r\n\r\n\t\t\t\tfloor.insertAdjacentElement('beforeBegin', temp);\r\n\t\t\t}\r\n\t\t\tvirtual.DOMCursor = index;\r\n\r\n\t\t\tvCursor.floor = virtual.dom.children[index] || null;\r\n\t\t\tvCursor.ceiling = vCursor.floor ? vCursor.floor.previousElementSibling : null;\r\n\r\n\t\t\tif(refreshVirtualSpacer)\r\n\t\t\t\trefreshVirtualSpacer(index);\r\n\r\n\t\t\trefreshScrollBounding(index, virtual.bounding, list, parentNode);\r\n\r\n\t\t\ttemp = parentNode.children[prepareCount - reduce + 1];\r\n\t\t\tif(temp !== undefined)\r\n\t\t\t\tscroller.scrollTop = temp.offsetTop;\r\n\t\t}\r\n\r\n\t\tupdating = false;\r\n\t}\r\n\r\n\tfunction removeUserScrollFocus(parentNode){\r\n\t\tparentNode.style.overflow = 'hidden';\r\n\t\tsetTimeout(function(){\r\n\t\t\tparentNode.style.overflow = '';\r\n\t\t}, 50);\r\n\t}\r\n\r\n\tfunction getAbsoluteHeight(el){\r\n\t var styles = window.getComputedStyle(el);\r\n\t var margin = parseInt(styles['marginTop']) + parseInt(styles['marginBottom']);\r\n\t return el.offsetHeight + margin || 0;\r\n\t}\r\n\r\n\tfunction obtainElements(list, parentNode){\r\n\t\tvar exist = [];\r\n\t\tvar temp = undefined;\r\n\r\n\t\tvar length = list.$virtual.DOMCursor;\r\n\t\tfor (var i = 0; i < length; i++) {\r\n\t\t\ttemp = list.$virtual.dom.children[i];\r\n\t\t\tif(temp === undefined) break;\r\n\t\t\texist.push(temp);\r\n\t\t}\r\n\r\n\t\tlength = parentNode.childElementCount - 2;\r\n\t\tfor (var i = 1; i <= length; i++) {\r\n\t\t\ttemp = parentNode.children[i];\r\n\t\t\tif(temp === undefined) break;\r\n\t\t\texist.push(temp);\r\n\t\t}\r\n\r\n\t\tlength = list.length - length - list.$virtual.DOMCursor;\r\n\t\tfor (var i = 0; i < length; i++) {\r\n\t\t\ttemp = list.$virtual.dom.children[list.$virtual.DOMCursor + i];\r\n\t\t\tif(temp === undefined) break;\r\n\t\t\texist.push(temp);\r\n\t\t}\r\n\r\n\t\treturn exist;\r\n\t}\r\n\r\n\tfunction refresh(force, list, prepareCount, parentNode, scroller, checkCursorPosition, refreshVirtualSpacer){\r\n\t\tvar cursor = list.$virtual.DOMCursor;\r\n\r\n\t\t// Find nearest cursor for current view position\r\n\t\tif(force){\r\n\t\t\tvar i = -1;\r\n\t\t\tvar length = list.$virtual.preparedLength;\r\n\r\n\t\t\tdo{\r\n\t\t\t\ti++;\r\n\t\t\t} while(i < length && parentNode.children[i].offsetTop < scroller.scrollTop);\r\n\r\n\t\t\tcursor = cursor + i;\r\n\t\t\tif(cursor > 0) cursor -= 1;\r\n\t\t}\r\n\r\n\t\t// Force move cursor if element in the DOM tree was overloaded\r\n\t\tif(force || parentNode.childElementCount - 2 > list.$virtual.preparedLength){\r\n\t\t\tlist.$virtual.DOMCursor = list.length;\r\n\t\t\tvar moveTo = cursor;\r\n\t\t\tif(!force)\r\n\t\t\t\tmoveTo = cursor <= prepareCount ? cursor : (cursor + prepareCount);\r\n\r\n\t\t\tscrollTo(moveTo,\r\n\t\t\t\tlist,\r\n\t\t\t\tprepareCount,\r\n\t\t\t\tparentNode,\r\n\t\t\t\tscroller,\r\n\t\t\t\trefreshVirtualSpacer\r\n\t\t\t);\r\n\t\t}\r\n\r\n\t\tif(refreshVirtualSpacer)\r\n\t\t\trefreshVirtualSpacer(cursor);\r\n\r\n\t\tif(checkCursorPosition)\r\n\t\t\tcheckCursorPosition();\r\n\r\n\t\trefreshScrollBounding(cursor, list.$virtual.bounding, list, parentNode);\r\n\t}\r\n\r\n\tfunction initStyles(){\r\n\t\tvar style = document.getElementById('sf-styles');\r\n\r\n\t\tif(!style){\r\n\t\t\tstyle = document.createElement('style');\r\n\t\t\tstyle.id = 'sf-styles';\r\n \tdocument.head.appendChild(style);\r\n\t\t}\r\n\r\n\t\tstyle.sheet.insertRule(\r\n\t\t'.sf-virtual-list .virtual-spacer{'+\r\n 'visibility: hidden;'+\r\n 'position: relative;'+\r\n 'height: 1px;'+\r\n 'transform-origin: 0 0;'+\r\n 'width: 1px;'+\r\n 'margin: 0;'+\r\n 'padding: 0;'+\r\n 'background: none;'+\r\n 'border: none;'+\r\n 'box-shadow: none;'+\r\n '}');\r\n\t}\r\n};"]} \ No newline at end of file +{"version":3,"sources":["sf-a_init.js","sf-controller.js","sf-loader.js","sf-model.js","sf-router.js","sf-virtual_scroll.js"],"names":["sf","_sf","apply","this","arguments","toString","constructor","Function","loader","onFinish","internal","regex","avoidQuotes","strictVar","$","fn","jQuery","Dom7","extend","obj","func","animateCSS","animationName","callback","duration","self","animationEnd","animation","OAnimation","MozAnimation","WebkitAnimation","t","undefined","style","css","addClass","one","setTimeout","removeClass","controller","pending","active","for","name","modelScope","element","elem","model","modelName","bindedList","attr","parents","root","bindedListIndex","prevAll","length","attributes","value","run","listenSFClick","e","target","script","eq","_modelScope","modelKeys","scopeMask","RegExp","replace","full","matched","split","method","method_","eval","shift","join","pop","console","error","root_","scope","DOMWasLoaded","init","parent","document","body","each","on","loadedContent","totalContent","turnedOff","whenDOMLoaded","whenProgress","off","indexOf","push","onProgress","f","i","removeAttribute","list","splice","temp","getElementsByTagName","innerHTML","js","ajax","url","dataType","cache","complete","warn","everythingLoaded","setInterval","test","readyState","clearInterval","router","prototype","setAttribute","bindingEnabled","processingElement","bracketMatch","chackValidFunctionCall","allowedFunction","localEval","script_","_model_","_content_","preventExecution","check","exec","trim","_result_","log","outerHTML","_evaled_","index","tagName","getAttribute","ref","$virtual","DOMCursor","modelRef","keys","Object","clearElementData","current","cleanData","dataParser","html","mask","runEval","variableList","itemMask","actual","slice","charCodeAt","uniqueDataParser","take","passVar","currentIndex","strDeclare","firstTime","key","JSON","stringify","VarPass_","VarPass","s1","obtained","forEach","val","bindArray","propertyName","targetNode","parentNode","htmlParsedData","oldArray","editProperty","refreshTimer","processElement","options","exist","elements","clearTimeout","refresh","item","all","first","prev","prepend","insertAfter","remove","create","insertBefore","update","currentRemoved","startRemove","propertyProxy","subject","defineProperty","enumerable","configurable","lastLength","Array","real","limit","foundChanges","compareObject","classList","contains","dom","createElement","virtual_scroll","handle","obj1","obj2","loopParser","content","returns","items","get","set","softRefresh","bindInput","whichVar","removeAttr","keyup","bindObject","alreadyInitialized","DOMNodeRemoved","removeBinding","Node","parsePreprocess","queuePreprocess","children","ceiling","add","floor","append","styles","window","getComputedStyle","absHeight","parseFloat","Math","ceil","offsetHeight","after","next","before","data","MutationObserver","observe","records","a","removedNodes","nodeName","childList","subtree","addEventListener","modelNames","attrs","id","bindRef","object","writable","isEmptyObject","created","dcBracket","which","Date","now","attrName","callbackFunction","getOwnPropertyDescriptor","objValue","bindElement","brackets","s2","childNodes","excludes","toUpperCase","currentNode","nodeType","concat","nodeValue","nodes","loading","enabled","pauseRenderOnTransition","currentPage","initialized","currentRouterURL","lazy","beforeEvent","location","pathname","enable","status","event","routingError","routingBack","goto","onEvent","loaded","special","lazyViewPoint","href","origin","charAt","load","history","pushState","RouterLoading","path","abort","assign","_scarlets","success","parse","DOMReference","foundAction","afterEvent","title","found","oldURL","newURL","routerLoaded","xhr","aborted","back","styleInitialized","refreshScrollBounding","cursor","bounding","prepareCount","offsetTop","lastElementChild","preparedLength","dCursor","scrollHeight","hasAttribute","currentFloor","scrollTo","scroller","refreshVirtualSpacer","virtual","reduce","updating","scrollTop","vCursor","childElementCount","nextElementSibling","insertAdjacentElement","insertCount","previousElementSibling","removeUserScrollFocus","overflow","getAbsoluteHeight","el","margin","parseInt","force","checkCursorPosition","moveTo","getElementById","head","appendChild","sheet","insertRule","initStyles","obtainElements","querySelector","destroy","resetViewport","visibleLength","clientHeight","parentElement","firstElementChild","fillViewport","ceilingHeight","floorHeight","resetCeiling","height","previousCeiling","nextFloor","dynamicHeight","count","offsetTo","fromCeiling","scrollFocused","changes","vDOM","moveElementCursor","navigator","userAgent","staticHeight"],"mappings":"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","file":"scarletsframe.min.js","sourcesContent":["sf = function(){\r\n\tif(arguments[0].constructor === Function){\r\n\t\treturn sf.loader.onFinish.apply(null, arguments);\r\n\t}\r\n};\r\n\r\nsf.internal = {};\r\nsf.regex = {\r\n\t// ToDo: Need help to skip escaped quote\r\n\tavoidQuotes:'(?=(?:[^\"\\']*(?:\\'|\")[^\"\\']*(?:\\'|\"))*[^\"\\']*$)',\r\n\tstrictVar:'(?=\\\\b[^.]|^|\\\\n| +|\\\\t|\\\\W )'\r\n};\r\n\r\nif(typeof $ === 'undefined' || !$.fn){\r\n\tif(typeof jQuery !== 'undefined')\r\n\t\t$ = jQuery;\r\n\telse if(typeof Dom7 !== 'undefined')\r\n\t\t$ = Dom7;\r\n\telse\r\n\t\tthrow \"Please load jQuery before ScarletsFrame\";\r\n}\r\n\r\nif(!$.fn.extend){\r\n\t$.fn.extend = function(obj){\r\n\t\tfor(var func in obj){\r\n\t\t\t$.fn[func] = obj[func];\r\n\t\t}\r\n\t}\r\n}\r\n\r\n// Add animate.css feature on jQuery\r\n$.fn.extend({\r\n animateCSS: function(animationName, callback, duration) {\r\n\tvar self = this;\r\n\tvar animationEnd = {\r\n\t\tanimation: 'animationend',\r\n\t\tOAnimation: 'oAnimationEnd',\r\n\t\tMozAnimation: 'mozAnimationEnd',\r\n\t\tWebkitAnimation: 'webkitAnimationEnd',\r\n\t};\r\n\r\n\tfor (var t in animationEnd)\r\n\t\tif (self[0].style[t] !== undefined){\r\n\t\t\tanimationEnd = animationEnd[t];\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\tif(duration)\r\n\t\tself.css('-webkit-animation-duration', duration+'s').css('animation-duration', duration+'s');\r\n\r\n\tself.addClass('animated ' + animationName).one(animationEnd, function(){\r\n\t\tsetTimeout(function(){\r\n\t\t\t$(self).removeClass('animated ' + animationName);\r\n\t\t}, 1);\r\n\r\n\t\tif(duration)\r\n\t\t\t$(self).css('-webkit-animation-duration', '').css('animation-duration', '');\r\n\r\n\t\tif (typeof callback === 'function') callback();\r\n\t});\r\n\r\n\treturn self;\r\n }\r\n});","// DOM Controller on loaded app\r\nsf.controller = new function(){\r\n\tvar self = this;\r\n\tself.pending = {};\r\n\tself.active = {};\r\n\r\n\tself.for = function(name, func){\r\n\t\tself.pending[name] = func;\r\n\t}\r\n\r\n\tself.modelScope = function(element, func){\r\n\t\tvar elem = $(element);\r\n\t\tvar model = sf.controller.modelName(element);\r\n\r\n\t\tif(!model)\r\n\t\t\tthrow 'model or controller was not found';\r\n\r\n\t\tvar bindedList = elem.attr('[sf-bind-list]');\r\n\t\tif(!bindedList)\r\n\t\t\tbindedList = elem.parents('[sf-bind-list]').attr('sf-bind-list');\r\n\r\n\t\tif(!bindedList){\r\n\t\t\tif(func) return func(sf.model.root[model], -1);\r\n\t\t\telse return sf.model.root[model];\r\n\t\t}\r\n\r\n\t\t// Find index\r\n\t\tvar bindedListIndex = 0;\r\n\t\tif(bindedList)\r\n\t\t\tbindedListIndex = elem.parents('[sf-bind-list]').prevAll('[sf-bind-list]').length;\r\n\r\n\t\tif(func) return func(sf.model.root[model][bindedList], bindedListIndex);\r\n\t\telse return sf.model.root[model][bindedList][bindedListIndex];\r\n\t}\r\n\r\n\tself.modelName = function(element){\r\n\t\tvar name = undefined;\r\n\t\tif(element.attributes['sf-controller'])\r\n\t\t\tname = element.attributes['sf-controller'].value;\r\n\t\telse\r\n\t\t\tname = $(element).parents('[sf-controller]').attr('sf-controller');\r\n\r\n\t\t// Initialize it first\r\n\t\tif(name !== undefined && !self.active[name])\r\n\t\t\tself.run(name);\r\n\r\n\t\treturn name;\r\n\t}\r\n\r\n\tvar listenSFClick = function(e){\r\n\t\tvar element = $(e.target);\r\n\t\tvar script = element.attr('sf-click');\r\n\r\n\t\tif(!script){\r\n\t\t\telement = element.parents('[sf-click]').eq(0);\r\n\t\t\tscript = element.attr('sf-click');\r\n\t\t}\r\n\r\n\t\tvar model = element.parents('[sf-controller]').attr('sf-controller');\r\n\r\n\t\tif(!sf.model.root[model])\r\n\t\t\tthrow \"Couldn't find model for \"+model+\" that was called from sf-click\";\r\n\r\n\t\tvar _modelScope = sf.model.root[model];\r\n\r\n\t\tvar modelKeys = sf.model.modelKeys(_modelScope);\r\n\t\tvar scopeMask = RegExp(sf.regex.strictVar+'('+modelKeys+')'+sf.regex.avoidQuotes+'\\\\b', 'g');\r\n\r\n\t\tscript = script.replace(scopeMask, function(full, matched){\r\n\t\t\treturn '_modelScope.'+matched;\r\n\t\t});\r\n\r\n\t\tscript = script.split('(');\r\n\r\n\t\tvar method = script[0];\r\n\t\tvar method_ = method;\r\n\r\n\t\t// Get method reference\r\n\t\ttry{\r\n\t\t\tmethod = eval(method);\r\n\t\t} catch(e) {\r\n\t\t\tmethod = false;\r\n\t\t}\r\n\r\n\t\tif(!method){\r\n\t\t\tconsole.error(\"Error on sf-click for model: \" + model + ' [Cannot find '+method_+']\\n', e.target);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// Take the argument list\r\n\t\tscript.shift();\r\n\t\tscript = script.join('(');\r\n\t\tscript = script.split(')');\r\n\t\tscript.pop();\r\n\t\tscript = script.join('(');\r\n\r\n\t\t// Turn argument as array\r\n\t\tif(script.length !== 0)\r\n\t\t\tscript = eval('['+script+']');\r\n\t\tif(!script)\r\n\t\t\tscript = [];\r\n\r\n\t\ttry{\r\n\t\t\tmethod.apply(element[0], script);\r\n\t\t} catch(e) {\r\n\t\t\tconsole.error(\"Error on sf-click for model: \" + model + '\\n', e.target, '\\n', e);\r\n\t\t}\r\n\t}\r\n\r\n\tvar root_ = function(scope){\r\n\t\tif(!sf.model.root[scope])\r\n\t\t\tsf.model.root[scope] = {};\r\n\r\n\t\tif(!sf.model.root[scope])\r\n\t\t\tsf.controller.run(scope);\r\n\t\t\r\n\t\treturn sf.model.root[scope];\r\n\t}\r\n\t// Deprecated\r\n\tself.run = function(name, func){\r\n\t\tif(!sf.loader.DOMWasLoaded)\r\n\t\t\treturn sf(function(){\r\n\t\t\t\tself.run(name, func);\r\n\t\t\t});\r\n\r\n\t\tif(self.pending[name]){\r\n\t\t\tif(!sf.model.root[name])\r\n\t\t\t\tsf.model.root[name] = {};\r\n\t\t\r\n\t\t\tself.pending[name](sf.model.root[name], root_);\r\n\t\t\tself.active[name] = true;\r\n\t\t\tdelete self.pending[name];\r\n\t\t}\r\n\r\n\t\tif(func)\r\n\t\t\tfunc(sf.model.root[name], root_);\r\n\t}\r\n\r\n\tself.init = function(parent){\r\n\t\tif(!sf.loader.DOMWasLoaded)\r\n\t\t\treturn sf(function(){\r\n\t\t\t\tself.init(name);\r\n\t\t\t});\r\n\r\n\t\t$('[sf-controller]', parent ? $(parent)[0] : document.body).each(function(){\r\n\t\t\tself.run(this.attributes['sf-controller'].value);\r\n\t\t});\r\n\t}\r\n\r\n\t// Create listener for sf-click\r\n\t$(document).one('DOMContentLoaded', function(){\r\n\t\t$(document.body).on('click', '[sf-click]', listenSFClick);\r\n\t});\r\n}","sf.loader = new function(){\r\n\tvar self = this;\r\n\tself.loadedContent = 0;\r\n\tself.totalContent = 0;\r\n\tself.DOMWasLoaded = false;\r\n\tself.turnedOff = false;\r\n\r\n\tvar whenDOMLoaded = [];\r\n\tvar whenProgress = [];\r\n\r\n\tself.off = function(){\r\n\t\tself.turnedOff = true;\r\n\t}\r\n\r\n\t// Make event listener\r\n\tself.onFinish = function(func){\r\n\t\tif(self.DOMWasLoaded) return func();\r\n\t\tif(whenDOMLoaded.indexOf(func) !== -1) return;\r\n\t\twhenDOMLoaded.push(func);\r\n\t}\r\n\tself.onProgress = function(func){\r\n\t\tif(self.DOMWasLoaded) return func(self.loadedContent, self.totalContent);\r\n\t\tif(whenProgress.indexOf(func) !== -1) return;\r\n\t\twhenProgress.push(func);\r\n\t}\r\n\r\n\tself.f = function(element){\r\n\t\tself.loadedContent++;\r\n\t\tfor (var i = 0; i < whenProgress.length; i++) {\r\n\t\t\twhenProgress[i](self.loadedContent, self.totalContent);\r\n\t\t}\r\n\t\tif(element && element.removeAttribute) element.removeAttribute('onload');\r\n\t}\r\n\r\n\tself.css = function(list){\r\n\t\tif(self.DOMWasLoaded){\r\n\t\t\t// check if some list was loaded\r\n\t\t\tfor (var i = list.length - 1; i >= 0; i--) {\r\n\t\t\t\tif($('link[href*=\"'+list[i]+'\"]').length!==0)\r\n\t\t\t\t\tlist.splice(i, 1);\r\n\t\t\t}\r\n\t\t\tif(list.length === 0) return;\r\n\t\t}\r\n\t\tself.totalContent = self.totalContent + list.length;\r\n\t\tvar temp = '';\r\n\t\tfor(var i = 0; i < list.length; i++){\r\n\t\t\ttemp += '';\r\n\t\t}\r\n\r\n\t\t$(function(){\r\n\t\t\tdocument.getElementsByTagName('body')[0].innerHTML += temp;\r\n\t\t});\r\n\t}\r\n\r\n\tself.js = function(list){\r\n\t\tif(self.DOMWasLoaded){\r\n\t\t\t// check if some list was loaded\r\n\t\t\tfor (var i = list.length - 1; i >= 0; i--) {\r\n\t\t\t\tif($('script[src*=\"'+list[i]+'\"]').length!==0)\r\n\t\t\t\t\tlist.splice(i, 1);\r\n\t\t\t}\r\n\t\t\tif(list.length === 0) return;\r\n\t\t}\r\n\t\tself.totalContent = self.totalContent + list.length;\r\n\t\tfor(var i = 0; i < list.length; i++){\r\n\t\t\t$.ajax({\r\n\t\t\t url: list[i],\r\n\t\t\t dataType: \"script\",\r\n\t\t\t cache: true,\r\n\t\t\t complete: sf.loader.f\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\tsetTimeout(function(){\r\n\t\tif(self.totalContent === 0){\r\n\t\t\tself.loadedContent = self.totalContent = 1;\r\n\t\t\tconsole.warn(\"If you don't use content loader feature, please turn it off with `sf.loader.off()`\");\r\n\t\t}\r\n\t}, 10000);\r\n\tvar everythingLoaded = setInterval(function() {\r\n\tif (/loaded|complete/.test(document.readyState)) {\r\n\t\tif(self.loadedContent < self.totalContent || self.loadedContent === 0){\r\n\t\t\tif(!self.turnedOff)\r\n\t\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tclearInterval(everythingLoaded);\r\n\t\tself.DOMWasLoaded = true;\r\n\t\tfor (var i = 0; i < whenDOMLoaded.length; i++) {\r\n\t\t\ttry{\r\n\t\t\t\twhenDOMLoaded[i]();\r\n\t\t\t} catch(e){\r\n\t\t\t\tconsole.error(e);\r\n\t\t\t}\r\n\t\t}\r\n\t\twhenProgress.splice(0);\r\n\t\twhenDOMLoaded.splice(0);\r\n\r\n\t\t// Last init\r\n\t\tsf.controller.init();\r\n\t\tsf.model.init();\r\n\t\tsf.router.init();\r\n\t}\r\n\t}, 100);\r\n};\r\nsf.prototype.constructor = sf.loader.onFinish;\r\n\r\n// Find images\r\n$(function(){\r\n\t$('img:not(onload)[src]').each(function(){\r\n\t\tsf.loader.totalContent++;\r\n\t\tthis.setAttribute('onload', \"sf.loader.f(this)\");\r\n\t});\r\n});","// Data save and HTML content binding\r\nsf.model = function(scope){\r\n\tif(!sf.model.root[scope])\r\n\t\tsf.model.root[scope] = {};\r\n\r\n\tif(sf.controller.pending[scope])\r\n\t\tsf.controller.run(scope);\r\n\r\n\treturn sf.model.root[scope];\r\n};\r\n\r\n(function(){\r\n\tvar self = sf.model;\r\n\tvar bindingEnabled = false;\r\n\tself.root = {};\r\n\r\n\tvar processingElement = null;\r\n\r\n\tvar bracketMatch = RegExp('([\\\\w.]*?[\\\\S\\\\s])\\\\('+sf.regex.avoidQuotes, 'g');\r\n\tvar chackValidFunctionCall = /[a-zA-Z0-9 \\]\\$\\)]/;\r\n\tvar allowedFunction = [':', 'for', 'if', 'while', '_content_.take', 'console.log'];\r\n\tvar localEval = function(script_, _model_, _modelScope, _content_){\r\n\t\tvar script = script_;\r\n\t\tscript_ = script_.split('\\\\\"').join('\\\\$%*').split(\"\\\\'\").join('\\\\%$*'); // ToDo: Escape\r\n\t\tscript_ = script_.split('._modelScope').join('');\r\n\t\tscript_ = script_.split('._model_').join('');\r\n\r\n\t\t// Prevent vulnerability by remove bracket to avoid a function call\r\n\t\tvar preventExecution = false;\r\n\t\tvar check = null;\r\n\t\twhile((check = bracketMatch.exec(script_)) !== null){\r\n\t\t\tcheck[1] = check[1].trim();\r\n\r\n\t\t\tif(allowedFunction.indexOf(check[1]) === -1 &&\r\n\t\t\t\tcheck[1].split('.')[0] !== '_modelScope' &&\r\n\t\t\t\tchackValidFunctionCall.test(check[1][check[1].length-1])\r\n\t\t\t){\r\n\t\t\t\tpreventExecution = check[1];\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\tvar _result_ = '';\r\n\t\tscript_ = script_.split('\\\\$%*').join('\\\\\"').split('\\\\%$*').join(\"\\\\'\"); // ToDo: Unescape\r\n\t\tif(preventExecution){\r\n\t\t\tconsole.error(\"Trying to executing unrecognized function (\"+preventExecution+\")\");\r\n\t\t\tconsole.log($(processingElement.outerHTML)[0]);\r\n\t\t\tconsole.log(script_);\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\ttry{\r\n\t\t\tvar _evaled_ = eval(script_);\r\n\t\t} catch(e){\r\n\t\t\tconsole.error(e);\r\n\t\t\tconsole.log(script_);\r\n\t\t\tconsole.log($(processingElement.outerHTML)[0]);\r\n\t\t\treturn '';\r\n\t\t}\r\n\r\n\t\tif(_result_ !== '') return _result_;\r\n\t\treturn _evaled_;\r\n\t}\r\n\r\n\tself.index = function(element){\r\n\t\tvar i = $(element).prevAll(element.tagName).length;\r\n\t\tvar list = element.getAttribute('sf-bind-list');\r\n\t\tif(!list) return i;\r\n\r\n\t\tvar ref = sf.controller.modelScope(element)[list];\r\n\t\tif(!ref.$virtual) return i;\r\n\r\n\t\treturn i + ref.$virtual.DOMCursor - 1;\r\n\t}\r\n\r\n\tself.for = function(name, func){\r\n\t\tif(!sf.loader.DOMWasLoaded)\r\n\t\t\treturn sf(function(){\r\n\t\t\t\tself.for(name, func);\r\n\t\t\t});\r\n\t\t\r\n\t\tfunc(self(name), self);\r\n\t}\r\n\r\n\tself.modelKeys = function(modelRef){\r\n\t\tvar keys = Object.keys(modelRef);\r\n\t\tfor (var i = keys.length - 1; i >= 0; i--) {\r\n\t\t\tif(keys[i].indexOf('$') !== -1)\r\n\t\t\t\tkeys.splice(i, 1);\r\n\t\t}\r\n\t\treturn keys.join('|');\r\n\t}\r\n\r\n\tvar clearElementData = function(current){\r\n\t\t// Clean associated data on jQuery\r\n\t\tif($ && $.cleanData)\r\n\t\t\t$.cleanData(current.getElementsByTagName(\"*\"));\r\n\r\n\t\tcurrent.innerHTML = '';\r\n\t\tfor (var i = 0; i < current.attributes.length; i++) {\r\n\t\t\tvar name = current.attributes[i].name;\r\n\t\t\tif(name !== 'sf-bind-list')\r\n\t\t\t\tcurrent.removeAttribute(name);\r\n\t\t}\r\n\t\tcurrent.setAttribute('style', 'display:none');\r\n\t}\r\n\r\n\t// For contributor of this library\r\n\t// Please be careful when you're passing the eval argument\r\n\tvar dataParser = function(html, _model_, mask, scope, runEval){\r\n\t\tvar _modelScope = self.root[scope];\r\n\t\tif(!runEval) runEval = '';\r\n\t\t\r\n\t\t// Unmatch any function\r\n\t\tvar variableList = self.modelKeys(_modelScope);\r\n\t\tfor(var i = variableList.length - 1; i >= 0; i--){\r\n\t\t\tif(_modelScope[variableList[i]] instanceof Function)\r\n\t\t\t\tvariableList.splice(i, 1);\r\n\t\t}\r\n\r\n\t\t// Don't match text inside quote, or object keys\r\n\t\tvar scopeMask = RegExp(sf.regex.strictVar+'('+variableList+')'+sf.regex.avoidQuotes+'\\\\b', 'g');\r\n\r\n\t\tif(mask)\r\n\t\t\tvar itemMask = RegExp(sf.regex.strictVar+mask+'\\\\.'+sf.regex.avoidQuotes+'\\\\b', 'g');\r\n\r\n\t\tbindingEnabled = true;\r\n\r\n\t\treturn html.replace(/{{([^@][\\s\\S]*?)}}/g, function(actual, temp){\r\n\t\t\t// ToDo: The regex should be optimized to avoid match in a quote (but not escaped quote)\r\n\t\t\ttemp = temp.split('\\\\\"').join('\\\\$%*').split(\"\\\\'\").join('\\\\%$*'); // ToDo: Escape\r\n\r\n\t\t\t// Mask item variable\r\n\t\t\tif(mask)\r\n\t\t\t\ttemp = temp.replace(itemMask, function(matched){\r\n\t\t\t\t\treturn '_model_.'+matched[0].slice(1);\r\n\t\t\t\t});\r\n\r\n\t\t\t// Mask model for variable\r\n\t\t\ttemp = temp.replace(scopeMask, function(full, matched){\r\n\t\t\t\treturn '_modelScope.'+matched;\r\n\t\t\t});\r\n\r\n\t\t\ttemp = temp.split('\\\\$%*').join('\\\\\"').split('\\\\%$*').join(\"\\\\'\"); // ToDo: Unescape\r\n\r\n\t\t\t// Evaluate\r\n\t\t\ttemp = '' + localEval.apply(self.root, [runEval + temp, _model_, _modelScope]);\r\n\r\n\t\t\treturn temp.replace(/[\\u00A0-\\u9999<>\\&]/gim, function(i) {\r\n\t\t return '&#'+i.charCodeAt(0)+';';\r\n\t\t });\r\n\t\t});\r\n\t}\r\n\r\n\tvar uniqueDataParser = function(html, _model_, mask, scope){\r\n\t\t// Get prepared html content\r\n\t\tvar _content_ = {\r\n\t\t\tlength:0,\r\n\t\t\ttake:function(passVar, currentIndex){\r\n\t\t\t\tif(!passVar)\r\n\t\t\t\t\treturn dataParser(this[currentIndex], _model_, mask, scope);\r\n\r\n\t\t\t\tvar strDeclare = '\"use strict\";var ';\r\n\t\t\t\tvar firstTime = true;\r\n\r\n\t\t\t\tfor(var key in passVar){\r\n\t\t\t\t\tif(typeof passVar[key] === 'string')\r\n\t\t\t\t\t\tpassVar[key] = '\"'+passVar[key].split('\"').join('\\\\\"')+'\"';\r\n\t\t\t\t\telse if(typeof passVar[key] === 'object')\r\n\t\t\t\t\t\tpassVar[key] = JSON.stringify(passVar[key]);\r\n\r\n\t\t\t\t\tif(!firstTime)\r\n\t\t\t\t\t\tstrDeclare += ',';\r\n\r\n\t\t\t\t\tstrDeclare += key + ' = ' + passVar[key];\r\n\t\t\t\t\tfirstTime = false;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Disable function call for addional security eval protection\r\n\t\t\t\tstrDeclare = strDeclare.split('(').join('').split(')').join('');\r\n\r\n\t\t\t\treturn dataParser(this[currentIndex], _model_, mask, scope, strDeclare + ';');\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\thtml = html.replace(/{\\[([\\s\\S]*?)\\]}/g, function(full, matched){\r\n\t\t\t_content_[_content_.length] = matched;\r\n\t\t\t_content_.length++;\r\n\t\t\treturn '_result_ += _content_.take(&VarPass&, '+(_content_.length - 1)+');';\r\n\t\t});\r\n\r\n\t\tvar _modelScope = self.root[scope];\r\n\r\n\t\t// Don't match text inside quote, or object keys\r\n\t\tvar scopeMask = RegExp(sf.regex.strictVar+'('+self.modelKeys(_modelScope)+')'+sf.regex.avoidQuotes+'\\\\b', 'g');\r\n\r\n\t\tif(mask)\r\n\t\t\tvar itemMask = RegExp(sf.regex.strictVar+mask+'\\\\.'+sf.regex.avoidQuotes+'\\\\b', 'g');\r\n\r\n\t\treturn html.replace(/{{(@[\\s\\S]*?)}}/g, function(actual, temp){\r\n\t\t\t// ToDo: The regex should be optimized to avoid match in a quote (but not escaped quote)\r\n\t\t\ttemp = temp.split('\\\\\"').join('\\\\$%*').split(\"\\\\'\").join('\\\\%$*'); // ToDo: Escape\r\n\r\n\t\t\t// Mask item variable\r\n\t\t\tif(mask)\r\n\t\t\t\ttemp = temp.replace(itemMask, function(matched){\r\n\t\t\t\t\treturn '_model_.'+matched[0].slice(1);\r\n\t\t\t\t});\r\n\r\n\t\t\t// Mask model for variable\r\n\t\t\ttemp = temp.replace(scopeMask, function(full, matched){\r\n\t\t\t\treturn '_modelScope.'+matched;\r\n\t\t\t});\r\n\t\t\ttemp = temp.split('\\\\$%*').join('\\\\\"').split('\\\\%$*').join(\"\\\\'\"); // ToDo: Unescape\r\n\r\n\t\t\tvar result = '';\r\n\t\t\tvar check = false;\r\n\r\n\t\t\tcheck = temp.split('@if ');\r\n\t\t\tif(check.length != 1){\r\n\t\t\t\tcheck = check[1].split(':');\r\n\t\t\t\r\n\t\t\t\t// If condition was meet\r\n\t\t\t\tif(localEval.apply(self.root, [check[0], _model_, _modelScope, _content_])){\r\n\t\t\t\t\tcheck.shift();\r\n\t\t\t\t\treturn check.join(':');\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// Get defined variables\r\n\t\t\tvar VarPass_ = /(var|let)([\\w,\\s]+)(?=\\s(?==|in|of))/g;\r\n\t\t\tvar VarPass = [];\r\n\t\t\tvar s1 = null;\r\n\t\t\twhile((s1 = VarPass_.exec(temp)) !== null){\r\n\t\t\t\tVarPass.push(s1[2]);\r\n\t\t\t}\r\n\t\t\tif(VarPass.length){\r\n\t\t\t\tvar obtained = [];\r\n\t\t\t\tfor (var i = 0; i < VarPass.length; i++) {\r\n\t\t\t\t\tVarPass[i].replace(/([\\n\\t\\r]| )+/g, '').split(',').forEach(function(val){\r\n\t\t\t\t\t\tobtained.push(val);\r\n\t\t\t\t\t});\r\n\t\t\t\t};\r\n\t\t\t\tVarPass = obtained;\r\n\t\t\t\tfor (var i = 0; i < VarPass.length; i++) {\r\n\t\t\t\t\tVarPass[i] += ':(typeof '+VarPass[i]+'!=\"undefined\"?'+VarPass[i]+':undefined)';\r\n\t\t\t\t}\r\n\t\t\t\tVarPass = '{'+VarPass.join(',')+'}';\r\n\t\t\t\ttemp = temp.split('&VarPass&').join(VarPass);\r\n\t\t\t}\r\n\t\t\ttemp = temp.split('&VarPass&').join('{}'); \r\n\r\n\t\t\t// Warning! Avoid unencoded user inputted content\r\n\t\t\t// And always check/remove closing ']}' in user content\r\n\t\t\t// Any function call will be removed for addional security\r\n\t\t\tcheck = temp.split('@exec');\r\n\t\t\tif(check.length != 1){\r\n\t\t\t\tcheck = check[1].split('<').join('<').split('>').join('>').split('&').join('&');\r\n\r\n\t\t\t\ttemp = localEval.apply(self.root, [check, _model_, _modelScope, _content_]);\r\n\t\t\t\treturn temp;\r\n\t\t\t}\r\n\t\t\treturn '';\r\n\t\t});\r\n\t}\r\n\r\n\tvar bindArray = function(html, list, mask, modelName, propertyName, targetNode, parentNode, htmlParsedData){\r\n\t\tvar oldArray = list.slice(0);\r\n\t\tvar editProperty = ['pop', 'push', 'splice', 'shift', 'unshift', 'softRefresh', 'hardRefresh'];\r\n\t\tvar refreshTimer = -1;\r\n\t\tvar processElement = function(index, options){\r\n\t\t\tvar exist = $(\"[sf-controller='\"+modelName+\"']\", targetNode);\r\n\t\t\tif(exist.length === 0){\r\n\t\t\t\tif(targetNode.getAttribute('sf-controller') === modelName)\r\n\t\t\t\t\texist = targetNode;\r\n\t\t\t\telse return;\r\n\t\t\t}\r\n\r\n\t\t\tif(list.$virtual){\r\n\t\t\t\tvar exist = $(list.$virtual.elements());\r\n\r\n\t\t\t\tclearTimeout(refreshTimer);\r\n\t\t\t\trefreshTimer = setTimeout(function(){\r\n\t\t\t\t\tlist.$virtual.refresh(true);\r\n\t\t\t\t}, 100);\r\n\t\t\t}\r\n\t\t\telse exist = $(\"[sf-bind-list='\"+propertyName+\"']\", exist);\r\n\r\n\t\t\tvar callback = false;\r\n\t\t\tif(self.root[modelName]['on$'+propertyName])\r\n\t\t\t\tcallback = self.root[modelName]['on$'+propertyName];\r\n\r\n\t\t\t// Hard refresh\r\n\t\t\tif(index === -1){\r\n\t\t\t\tvar item = self.root[modelName][propertyName];\r\n\t\t\t\tvar all = '';\r\n\t\t\t\tfor (var i = 0; i < item.length; i++) {\r\n\t\t\t\t\tvar temp = uniqueDataParser(html, item[i], mask, modelName);\r\n\t\t\t\t\tall += dataParser(temp, item[i], mask, modelName);\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Get first element\r\n\t\t\t\tvar first = exist.eq(0).prev();\r\n\t\t\t\tif(first[0] === exist[0])\r\n\t\t\t\t\texist.parent().prepend(all);\r\n\t\t\t\telse\r\n\t\t\t\t\t$(all).insertAfter(first);\r\n\t\t\t\texist.remove();\r\n\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\t// Remove\r\n\t\t\tif(options === 'remove'){\r\n\t\t\t\tif(exist[index]){\r\n\t\t\t\t\tvar currentRemoved = false;\r\n\t\t\t\t\tvar startRemove = function(){\r\n\t\t\t\t\t\tif(currentRemoved) return;\r\n\t\t\t\t\t\tcurrentRemoved = true;\r\n\r\n\t\t\t\t\t\tif(exist.length <= 1)\r\n\t\t\t\t\t\t\treturn clearElementData(exist[index]);\r\n\r\n\t\t\t\t\t\texist[index].remove();\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif(callback.remove){\r\n\t\t\t\t\t\t// Auto remove if return false\r\n\t\t\t\t\t\tif(!callback.remove(exist[index], startRemove))\r\n\t\t\t\t\t\t\tsetTimeout(startRemove, 800);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t// Auto remove if no callback\r\n\t\t\t\t\telse startRemove();\r\n\t\t\t\t}\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\t// Create or update\r\n\t\t\tvar item = self.root[modelName][propertyName][index];\r\n\r\n\t\t\tvar temp = uniqueDataParser(html, item, mask, modelName);\r\n\t\t\ttemp = dataParser(temp, item, mask, modelName);\r\n\t\t\ttemp = $(temp);\r\n\r\n\t\t\t// Create\r\n\t\t\tif(!exist[index] || options === 'insertAfter'){\r\n\t\t\t\tif(callback.create)\r\n\t\t\t\t\tcallback.create(temp[0]);\r\n\r\n\t\t\t\ttemp.insertAfter(exist[index !== 0 ? index - 1 : (exist.length - 1)]);\r\n\t\t\t}\r\n\r\n\t\t\telse{\r\n\t\t\t\t// Create\r\n\t\t\t\tif(options === 'insertBefore'){\r\n\t\t\t\t\tif(callback.create)\r\n\t\t\t\t\t\tcallback.create(temp[0]);\r\n\r\n\t\t\t\t\ttemp.insertBefore(exist[0]);\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Update\r\n\t\t\t\telse{\r\n\t\t\t\t\tif(callback.update)\r\n\t\t\t\t\t\tcallback.update(temp[0]);\r\n\r\n\t\t\t\t\t// Clean associated data on jQuery\r\n\t\t\t\t\tif($ && $.cleanData){\r\n\t\t\t\t\t\t$.cleanData(exist[index].getElementsByTagName(\"*\"));\r\n\t\t\t\t\t\t$.cleanData(exist[index]);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\texist[index].outerHTML = temp[0].outerHTML;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tvar propertyProxy = function(subject, name){\r\n\t\t\tObject.defineProperty(subject, name, {\r\n\t\t\t\tenumerable: false,\r\n\t\t\t\tconfigurable: true,\r\n\t\t\t\tvalue: function(){\r\n\t\t\t\t\tvar temp = undefined;\r\n\t\t\t\t\tvar lastLength = this.length;\r\n\r\n\t\t\t\t\tif(Array.prototype[name])\r\n\t\t\t\t\t\ttemp = Array.prototype[name].apply(this, arguments);\r\n\r\n\t\t\t\t\tif(name === 'pop')\r\n\t\t\t\t\t\tprocessElement(lastLength - 1, 'remove');\r\n\r\n\t\t\t\t\telse if(name === 'push')\r\n\t\t\t\t\t\tprocessElement(lastLength, 'add');\r\n\r\n\t\t\t\t\telse if(name === 'shift')\r\n\t\t\t\t\t\tprocessElement(0, 'remove');\r\n\r\n\t\t\t\t\telse if(name === 'splice'){\r\n\t\t\t\t\t\t// Removing data\r\n\t\t\t\t\t\tvar real = arguments[0];\r\n\t\t\t\t\t\tif(real < 0) real = lastLength + real;\r\n\r\n\t\t\t\t\t\tvar limit = arguments[1];\r\n\t\t\t\t\t\tif(!limit && limit !== 0) limit = oldArray.length;\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\tfor (var i = limit - 1; i >= 0; i--) {\r\n\t\t\t\t\t\t\tprocessElement(real + i, 'remove');\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tif(arguments.length >= 3){ // Inserting data\r\n\t\t\t\t\t\t\tlimit = arguments.length - 2;\r\n\t\t\t\t\t\t\tfor (var i = 0; i < limit; i++) {\r\n\t\t\t\t\t\t\t\tprocessElement(real + i, 'insertAfter');\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\telse if(name === 'unshift')\r\n\t\t\t\t\t\tprocessElement(0, 'insertBefore');\r\n\r\n\t\t\t\t\telse if(name === 'softRefresh'){\r\n\t\t\t\t\t\tif(arguments[0] || arguments[0] === 0)\r\n\t\t\t\t\t\t\tprocessElement(arguments[0], !!oldArray[arguments[0]] ? 'add':'remove');\r\n\t\t\t\t\t\telse {\r\n\t\t\t\t\t\t\tvar foundChanges = false;\r\n\r\n\t\t\t\t\t\t\t// Removal\r\n\t\t\t\t\t\t\tif(oldArray.length > this.length){\r\n\t\t\t\t\t\t\t\tfor (var i = oldArray.length - 1; i >= this.length; i--) {\r\n\t\t\t\t\t\t\t\t\tif(this.indexOf(oldArray[i]) === -1){\r\n\t\t\t\t\t\t\t\t\t\tfoundChanges = true;\r\n\t\t\t\t\t\t\t\t\t\tprocessElement(i, 'remove');\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t// Creates\r\n\t\t\t\t\t\t\tif(oldArray.length < this.length){\r\n\t\t\t\t\t\t\t\tfor (var i = oldArray.length - 1; i < this.length; i++) {\r\n\t\t\t\t\t\t\t\t\tfoundChanges = true;\r\n\t\t\t\t\t\t\t\t\tprocessElement(i, 'insertBefore');\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t// Update\r\n\t\t\t\t\t\t\tfor (var i = 0; i < this.length; i++) {\r\n\t\t\t\t\t\t\t\tif(compareObject(oldArray[i], this[i]) === false){\r\n\t\t\t\t\t\t\t\t\tfoundChanges = true;\r\n\t\t\t\t\t\t\t\t\tprocessElement(i, 'add');\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tif(foundChanges)\r\n\t\t\t\t\t\t\t\toldArray = this.slice(0);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse if(name === 'hardRefresh')\r\n\t\t\t\t\t\tprocessElement(-1, 'remove');\r\n\r\n\t\t\t\t\tif(Array.prototype[name])\r\n\t\t\t\t\t\toldArray = this.slice(0);\r\n\r\n\t\t\t\t\treturn temp;\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\t// parentNode[0] = element, [1] = child scroll height\r\n\t\tif(parentNode && parentNode[0].classList.contains('sf-virtual-list')){\r\n\t\t\tObject.defineProperty(list, '$virtual', {\r\n\t\t\t\tenumerable: false,\r\n\t\t\t\tconfigurable: true,\r\n\t\t\t\tvalue:{}\r\n\t\t\t});\r\n\r\n\t\t\t// Parse in virtual DOM\r\n\t\t\tlist.$virtual.dom = document.createElement('div');\r\n\t\t\tlist.$virtual.dom.innerHTML = htmlParsedData;\r\n\r\n\t\t\tsf.internal.virtual_scroll.handle(list, targetNode, parentNode[0]);\r\n\t\t}\r\n\r\n\t\tfor (var i = 0; i < editProperty.length; i++) {\r\n\t\t\tpropertyProxy(list, editProperty[i]);\r\n\t\t}\r\n\t}\r\n\r\n\tfunction compareObject(obj1, obj2){\r\n\t\tif(!obj1 || !obj2)\r\n\t\t\treturn false;\r\n\r\n\t\tfor(var i in obj1){\r\n\t\t\tif(typeof obj1[i] !== 'object' && obj1[i] !== obj2[i])\r\n\t\t\t\treturn false;\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\tvar loopParser = function(name, content, script, targetNode, parentNode){\r\n\t\tvar returns = '';\r\n\t\tvar method = script.split(' in ');\r\n\t\tvar mask = method[0];\r\n\r\n\t\tif(!self.root[name])\r\n\t\t\treturn console.error(\"Can't parse element because model for '\"+name+\"' was not found\", $(content)[0]);\r\n\r\n\t\tvar items = self.root[name][method[1]];\r\n\r\n\t\t// Get reference for debugging\r\n\t\tprocessingElement = $(content).attr('sf-bind-list', method[1])[0];\r\n\r\n\t\tcontent = processingElement.outerHTML;\r\n\t\tcontent = content.replace(/ +|\\t+/g, '');\r\n\r\n\t\tif(method.length === 2){\r\n\t\t\tfor(var i in items){\r\n\t\t\t\tvar item = items[i];\r\n\r\n\t\t\t\ttemp = uniqueDataParser(content, item, mask, name);\r\n\t\t\t\ttemp = dataParser(temp, item, mask, name);\r\n\t\t\t\treturns += temp;\r\n\t\t\t}\r\n\t\t\tObject.defineProperty(self.root[name], method[1], {\r\n\t\t\t\tenumerable: true,\r\n\t\t\t\tconfigurable: true,\r\n\t\t\t\tget:function(){\r\n\t\t\t\t\treturn items;\r\n\t\t\t\t},\r\n\t\t\t\tset:function(val){\r\n\t\t\t\t\tfor (var i = 0; i < val.length; i++) {\r\n\t\t\t\t\t\tif(items[i]){\r\n\t\t\t\t\t\t\titems[i] = val[i];\r\n\t\t\t\t\t\t\titems.softRefresh(i);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse items.push(val[i]);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif(items.length > val.length)\r\n\t\t\t\t\t\titems.splice(val.length);\r\n\r\n\t\t\t\t\treturn items;\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t\tbindArray(content, items, mask, name, method[1], targetNode, parentNode, returns);\r\n\t\t}\r\n\t\treturn returns;\r\n\t}\r\n\r\n\tvar bindInput = function(targetNode){\r\n\t\t$('input[sf-bound]', targetNode).each(function(){\r\n\t\t\tvar element = $(this);\r\n\t\t\tvar model = element.parents('[sf-controller]').attr('sf-controller');\r\n\t\t\tif(!model) return;\r\n\r\n\t\t\tvar whichVar = element.attr('sf-bound');\r\n\r\n\t\t\t// Get reference\r\n\t\t\tif(typeof self.root[model][whichVar] === undefined){\r\n\t\t\t\tconsole.error('Cannot get reference for self.root[\"' + model + '\"][\"' + whichVar+'\"]');\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\telement.attr('sf-bounded', whichVar);\r\n\t\t\telement.removeAttr('sf-bound');\r\n\r\n\t\t\t// Bound key up\r\n\t\t\telement.keyup(function(e){\r\n\t\t\t\tself.root[model][whichVar] = element.val();\r\n\t\t\t});\r\n\r\n\t\t\t// Bind value\r\n\t\t\telement.attr('value', '{{'+whichVar+'}}');\r\n\t\t\tbindObject(element, self.root[model], whichVar, 'attr');\r\n\t\t});\r\n\t}\r\n\r\n\tvar alreadyInitialized = false;\r\n\tself.init = function(targetNode){\r\n\t\tif(alreadyInitialized && !targetNode) return;\r\n\t\talreadyInitialized = true;\r\n\t\tsetTimeout(function(){\r\n\t\t\talreadyInitialized = false;\r\n\t\t}, 50);\r\n\r\n\t\tif(targetNode){\r\n\t\t\tif(!(targetNode instanceof Node))\r\n\t\t\t\ttargetNode = $(targetNode)[0];\r\n\t\t}\r\n\t\telse targetNode = document.body;\r\n\r\n\t\tself.parsePreprocess(self.queuePreprocess(targetNode));\r\n\t\tbindInput(targetNode);\r\n\r\n\t\t$('[sf-repeat-this]', targetNode).each(function(){\r\n\t\t\tvar self = $(this);\r\n\t\t\tvar parent = self.parent();\r\n\r\n\t\t\tif(this.parentNode.classList.contains('sf-virtual-list')){\r\n\t\t\t\tvar tagName = $(this.parentNode).children('[sf-repeat-this]')[0].tagName;\r\n\t\t\t\tvar ceiling = document.createElement(tagName);\r\n\t\t\t\tceiling.classList.add('virtual-spacer');\r\n\t\t\t\tceiling.classList.add('ceiling');\r\n\t\t\t\t//ceiling.style.transform = 'scaleY(0)';\r\n\t\t\t\tthis.parentNode.prepend(ceiling);\r\n\r\n\t\t\t\tvar floor = document.createElement(tagName);\r\n\t\t\t\tfloor.classList.add('virtual-spacer');\r\n\t\t\t\tfloor.classList.add('floor');\r\n\t\t\t\t//floor.style.transform = 'scaleY(0)';\r\n\t\t\t\tthis.parentNode.append(floor);\r\n\r\n\t\t\t\t// His total scrollHeight\r\n\t\t\t\tvar styles = window.getComputedStyle(this);\r\n\t\t\t\tvar absHeight = parseFloat(styles['marginTop']) + parseFloat(styles['marginBottom']);\r\n\t\t\t\tstyles = null;\r\n\r\n\t\t\t\t// Element height + margin\r\n\t\t\t\tabsHeight = Math.ceil(this.offsetHeight + absHeight);\r\n\t\t\t}\r\n\r\n\t\t\tvar after = self.next();\r\n\t\t\tif(!after.length || self[0] === after[0])\r\n\t\t\t\tafter = false;\r\n\r\n\t\t\tvar before = self.prev();\r\n\t\t\tif(!before.length || self[0] === before[0])\r\n\t\t\t\tbefore = false;\r\n\r\n\t\t\tvar script = self.attr('sf-repeat-this');\r\n\t\t\tself.removeAttr('sf-repeat-this');\r\n\t\t\tvar controller = sf.controller.modelName(this);\r\n\r\n\t\t\tvar content = this.outerHTML;\r\n\r\n\t\t\t// Check if the element was already bound to prevent vulnerability\r\n\t\t\tif(/sf-bind-id|sf-bind-list/.test(content))\r\n\t\t\t\tthrow \"Can't parse element that already bound\";\r\n\r\n\t\t\tif(this.parentNode.classList.contains('sf-virtual-list')){\r\n\t\t\t\tif(loopParser(controller, content, script, targetNode, [this.parentNode, absHeight]))\r\n\t\t\t\t\tself.remove();\r\n\t\t\t\telse {\r\n\t\t\t\t\tself.attr('sf-bind-list', script.split(' in ')[1]);\r\n\t\t\t\t\tclearElementData(this);\r\n\t\t\t\t}\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tvar data = loopParser(controller, content, script, targetNode);\r\n\t\t\tif(data){\r\n\t\t\t\tself.remove();\r\n\t\t\t\t\r\n\t\t\t\tdata = $(data);\r\n\t\t\t\tif(after)\r\n\t\t\t\t\tdata.insertBefore(after);\r\n\t\t\t\telse if(before)\r\n\t\t\t\t\tdata.insertAfter(before);\r\n\t\t\t\telse\r\n\t\t\t\t\tparent.append(data);\r\n\t\t\t}\r\n\t\t\telse{\r\n\t\t\t\tself.attr('sf-bind-list', script.split(' in ')[1]);\r\n\t\t\t\tclearElementData(this);\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\t// Reset model properties\r\n\t// Don't call if the removed element is TEXT or #comment\r\n\tfunction DOMNodeRemoved(element){\r\n\t\tvar model = sf.controller.modelName(element);\r\n\r\n\t\t$('[sf-bind-id], [sf-bind-list], [sf-bounded], [sf-repeat-this]', element).each(function(){\r\n\t\t\tremoveBinding(this, model);\r\n\t\t});\r\n\r\n\t\tremoveBinding(element);\r\n\t}\r\n\r\n\t$(function(){\r\n\t\tif(typeof MutationObserver === 'function' && MutationObserver.prototype.observe){\r\n\t\t\tvar observer = new MutationObserver(function(records){\r\n\t\t\t\tif(!bindingEnabled) return;\r\n\r\n\t\t\t\tfor(var i in records){\r\n\t\t\t\t\tfor(var a in records[i].removedNodes){\r\n\t\t\t\t\t\tvar tagName = records[i].removedNodes[a].nodeName;\r\n\t\t\t\t\t\tif(tagName !== 'TEXT' || tagName !== '#comment') continue;\r\n\t\t\t\t\t\tDOMNodeRemoved(records[i].removedNodes[a]);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t\tobserver.observe(document.body, { childList: true, subtree: true });\r\n\t\t}\r\n\t\telse {\r\n\t\t\tdocument.body.addEventListener('DOMNodeRemoved', function(e){\r\n\t\t\t\tif(bindingEnabled){\r\n\t\t\t\t\tvar tagName = e.target.nodeName;\r\n\t\t\t\t\tif(tagName !== 'TEXT' || tagName !== '#comment') return;\r\n\t\t\t\t\tDOMNodeRemoved(e.target);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\t});\r\n\r\n\tvar removeBinding = function(element, modelNames){\r\n\t\tif(!element.attributes) return;\r\n\r\n\t\tvar attrs = element.attributes;\r\n\t\tif(attrs['sf-bind-id']){\r\n\t\t\tvar id = attrs['sf-bind-id'].value;\r\n\r\n\t\t\tif(!bindRef[id]) return;\r\n\t\t\tvar ref = bindRef[id];\r\n\r\n\t\t\tfor (var i = 0; i < ref.propertyName.length; i++) {\r\n\t\t\t\tvar value = ref.object[ref.propertyName[i]];\r\n\t\t\t\tObject.defineProperty(ref.object, ref.propertyName[i], {\r\n\t\t\t\t\tconfigurable: true,\r\n\t\t\t\t\tenumerable:true,\r\n\t\t\t\t\twritable:true,\r\n\t\t\t\t\tvalue:value\r\n\t\t\t\t});\r\n\t\t\t}\r\n\r\n\t\t\tdelete bindRef[id];\r\n\r\n\t\t\t// Remove callback left\r\n\t\t\tvar cache = bindRef.cache\r\n\t\t\tfor(var i in cache){\r\n\t\t\t\tif(cache[i].callback && cache[i].callback[id])\r\n\t\t\t\t\tdelete cache[i].callback[id];\r\n\t\t\t\tif($.isEmptyObject(cache[i].callback))\r\n\t\t\t\t\tdelete cache[i];\r\n\t\t\t}\r\n\r\n\t\t\tif(cache[id]){\r\n\t\t\t\tdelete cache[id].attrs;\r\n\t\t\t\tdelete cache[id].innerHTML;\r\n\t\t\t\tdelete cache[id].modelName;\r\n\t\t\t\tdelete cache[id].model;\r\n\t\t\t\tdelete cache[id].created;\r\n\t\t\t\tdelete cache[id].element;\r\n\t\t\t}\r\n\r\n\t\t\tbindRef.length--;\r\n\t\t\tif(bindRef.length === 0)\r\n\t\t\t\tbindRef.index = 0;\r\n\t\t}\r\n\r\n\t\tif(!modelNames) return;\r\n\r\n\t\tvar propertyName = false;\r\n\t\tif(attrs['sf-bind-list']){\r\n\t\t\tpropertyName = attrs['sf-bind-list'].value;\r\n\t\t}\r\n\r\n\t\tif(attrs['sf-repeat-this'])\r\n\t\t\tpropertyName = attrs['sf-repeat-this'].value.split(' in ')[1];\r\n\r\n\t\tif(attrs['sf-bounded'])\r\n\t\t\tpropertyName = attrs['sf-bounded'].value;\r\n\r\n\t\tfor (var i = 0; i < modelNames.length; i++) {\r\n\t\t\tvar modelRef = self.root[modelNames[i]];\r\n\t\t\tif(!modelRef[propertyName]) continue;\r\n\r\n\t\t\tvar value = modelRef[propertyName].slice(0);\r\n\t\t\tObject.defineProperty(modelRef, propertyName, {\r\n\t\t\t\tconfigurable: true,\r\n\t\t\t\tenumerable:true,\r\n\t\t\t\twritable:true,\r\n\t\t\t\tvalue:value\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\t/*{\r\n\t\tid:{\r\n\t\t\tobject,\r\n\t\t\t[propertyName]\r\n\t\t}\r\n\t}*/\r\n\t// For resetting object property it the element was removed from DOM\r\n\tvar bindRef = {length:0, index:0, cache:{}};\r\n\tself.bindRef = bindRef;\r\n\tvar dcBracket = /{{[\\s\\S]*?}}/;\r\n\tvar bindObject = function(element, object, propertyName, which){\r\n\t\tif(!(element instanceof Node))\r\n\t\t\telement = element[0];\r\n\r\n\t\t// Get reference for debugging\r\n\t\tprocessingElement = element;\r\n\r\n\t\t// First initialization\r\n\t\tvar id = bindRef.index;\r\n\t\t$(element).attr('sf-bind-id', id);\r\n\r\n\t\tbindRef.index++;\r\n\t\tbindRef.length++;\r\n\t\tbindRef.cache[id] = {};\r\n\t\tvar cache = bindRef.cache[id];\r\n\r\n\t\tcache.attrs = {};\r\n\t\tcache.innerHTML = '';\r\n\t\tcache.modelName = sf.controller.modelName(element);\r\n\t\tcache.model = self.root[cache.modelName];\r\n\t\tcache.created = Date.now();\r\n\r\n\t\tif(which === 'attr' || !which){\r\n\t\t\tfor(var i in element.attributes){\r\n\t\t\t\t// Check if it has a bracket\r\n\t\t\t\tif(!dcBracket.test(element.attributes[i].value))\r\n\t\t\t\t\tcontinue;\r\n\r\n\t\t\t\tvar attrName = element.attributes[i].name;\r\n\t\t\t\tcache.attrs[attrName] = element.attributes[i].value;\r\n\r\n\t\t\t\tif(attrName === 'value')\r\n\t\t\t\t\telement.removeAttribute(attrName);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif(which === 'html' || !which)\r\n\t\t\tcache.innerHTML = element.innerHTML;\r\n\r\n\t\t// Get current object reference\r\n\t\tif(!bindRef[id]) bindRef[id] = {object:object, propertyName:[]};\r\n\t\tbindRef[id].propertyName.push(propertyName);\r\n\r\n\t\tcache.element = $(element);\r\n\t\tvar callbackFunction = function(){\r\n\t\t\tif(which === 'attr' || !which){\r\n\t\t\t\tfor(var name in cache.attrs){\r\n\t\t\t\t\tif(cache.attrs[name].indexOf(propertyName) === -1)\r\n\t\t\t\t\t\tcontinue;\r\n\r\n\t\t\t\t\tvar temp = dataParser(cache.attrs[name], cache.model, false, cache.modelName);\r\n\t\t\t\t\tif(name === 'value')\r\n\t\t\t\t\t\tcache.element.val(temp);\r\n\t\t\t\t\telse\r\n\t\t\t\t\t\tcache.element.attr(name, temp);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif(which === 'html' || !which){\r\n\t\t\t\tvar temp = uniqueDataParser(cache.innerHTML, cache.model, false, cache.modelName);\r\n\t\t\t\ttemp = dataParser(temp, cache.model, false, cache.modelName);\r\n\t\t\t\tcache.element.html(temp);\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tif(cache.model[propertyName] === undefined) throw \"Property '\"+propertyName+\"' was not found on '\"+cache.modelName+\"' model\";\r\n\t\tif(Object.getOwnPropertyDescriptor(cache.model, propertyName)['set']){\r\n\t\t\tfor(var i in bindRef){\r\n\t\t\t\tif(cache.model === bindRef[i].object && bindRef[i].propertyName.indexOf(propertyName) !== -1){\r\n\t\t\t\t\tbindRef.cache[i].callback[id] = callbackFunction;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tcache.callback = {};\r\n\t\tcache.callback[id] = callbackFunction;\r\n\r\n\t\tvar objValue = object[propertyName]; // Object value\r\n\t\tObject.defineProperty(object, propertyName, {\r\n\t\t\tenumerable: true,\r\n\t\t\tconfigurable: true,\r\n\t\t\tget:function(){\r\n\t\t\t\treturn objValue;\r\n\t\t\t},\r\n\t\t\tset:function(val){\r\n\t\t\t\tobjValue = val;\r\n\r\n\t\t\t\tfor(var i in cache.callback){\r\n\t\t\t\t\tcache.callback[i]();\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn objValue;\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tself.bindElement = function(element, which){\r\n\t\tvar modelName = sf.controller.modelName(element);\r\n\t\tvar model = self.root[modelName];\r\n\t\tif(!model) return console.error(\"Model for \"+modelName+\" was not found while binding:\", element);\r\n\r\n\t\tvar html = element.outerHTML;\r\n\r\n\t\t// Check if the child element was already bound to prevent vulnerability\r\n\t\tif(/sf-bind-id|sf-bind-list/.test(html))\r\n\t\t\tthrow \"Can't parse element that already bound\";\r\n\r\n\t\tif(which === 'attr')\r\n\t\t\thtml = html.replace(element.innerHTML, '');\r\n\r\n\t\tvar brackets = /{{([\\s\\S]*?)}}/g;\r\n\r\n\t\t// Unmatch any function\r\n\t\tvar variableList = self.modelKeys(model);\r\n\t\tfor(var i = variableList.length - 1; i >= 0; i--){\r\n\t\t\tif(model[variableList[i]] instanceof Function)\r\n\t\t\t\tvariableList.splice(i, 1);\r\n\t\t}\r\n\r\n\t\tvar scopeMask = RegExp(sf.regex.strictVar+'('+variableList+')'+sf.regex.avoidQuotes+'\\\\b', 'g');\r\n\t\tvar s1, s2 = null;\r\n\t\twhile((s1 = brackets.exec(html)) !== null){\r\n\t\t\twhile ((s2 = scopeMask.exec(s1[1])) !== null) {\r\n\t\t\t\tbindObject(element, model, s2[1], which);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tself.queuePreprocess = function(targetNode){\r\n\t\tvar childNodes = (targetNode || document.body).childNodes;\r\n\r\n\t\tvar excludes = ['html','head','style','link','meta','script','object','iframe'];\r\n\t\tfor (var i = 0; i < excludes.length; i++) {\r\n\t\t\texcludes[i] = excludes[i].toUpperCase();\r\n\t\t}\r\n\r\n\t\tvar temp = [];\r\n\t\tfor (var i = 0; i < childNodes.length; i++) {\r\n\t\t\tvar currentNode = childNodes[i];\r\n\t\t\tif(excludes.indexOf(currentNode.nodeName) !== -1)\r\n\t\t\t\tcontinue;\r\n\r\n\t\t\tif(currentNode.nodeType === 1){ // Tag\r\n\t\t\t\tvar attrs = currentNode.attributes;\r\n\r\n\t\t\t\t// Skip element and it's childs that already bound to prevent vulnerability\r\n\t\t\t\tif(attrs['sf-bind-id'] || attrs['sf-repeat-this'] || attrs['sf-bind-list']) continue;\r\n\r\n\t\t\t\tfor (var a = 0; a < attrs.length; a++) {\r\n\t\t\t\t\tif(attrs[a].value.indexOf('{{') !== -1){\r\n\t\t\t\t\t\tcurrentNode.setAttribute('sf-preprocess', 'attronly');\r\n\t\t\t\t\t\ttemp.push(currentNode);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\ttemp = temp.concat(self.queuePreprocess(currentNode));\r\n\t\t\t}\r\n\r\n\t\t\telse if(currentNode.nodeType === 3){ // Text\r\n\t\t\t\tif(currentNode.nodeValue.indexOf('{{') !== -1){\r\n\t\t\t\t\tcurrentNode.parentNode.setAttribute('sf-preprocess', '');\r\n\r\n\t\t\t\t\t// Reset Siblings\r\n\t\t\t\t\tfor (var a = 0; a < temp.length; a++) {\r\n\t\t\t\t\t\ttemp[a].removeAttribute('sf-preprocess');\r\n\t\t\t\t\t}\r\n\t\t\t\t\ttemp.push(currentNode.parentNode);\r\n\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn temp;\r\n\t}\r\n\r\n\tself.parsePreprocess = function(nodes){\r\n\t\tfor (var a = 0; a < nodes.length; a++) {\r\n\t\t\tvar model = sf.controller.modelName(nodes[a]);\r\n\t\t\tnodes[a].removeAttribute('sf-preprocess');\r\n\r\n\t\t\tif(!self.root[model])\r\n\t\t\t\treturn console.error(\"Can't parse element because model for '\"+model+\"' was not found\", nodes[a]);\r\n\r\n\t\t\t// Get reference for debugging\r\n\t\t\tprocessingElement = nodes[a];\r\n\r\n\t\t\t// Double check if the child element already bound to prevent vulnerability\r\n\t\t\tif(/sf-bind-id|sf-bind-list/.test(nodes[a].innerHTML)){\r\n\t\t\t\tconsole.error(\"Can't parse element that already bound\");\r\n\t\t\t\tconsole.log($(processingElement.outerHTML)[0]);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif($(nodes[a]).attr('sf-bind'))\r\n\t\t\t\tself.bindElement(nodes[a], $(nodes[a]).attr('sf-bind'));\r\n\r\n\t\t\t// Avoid editing the outerHTML because it will remove the bind\r\n\t\t\tvar temp = uniqueDataParser(nodes[a].innerHTML, self.root[model], false, model);\r\n\t\t\tnodes[a].innerHTML = dataParser(temp, self.root[model], false, model);\r\n\t\t\tfor (var i = 0; i < nodes[a].attributes.length; i++) {\r\n\t\t\t\tif(nodes[a].attributes[i].value.indexOf('{{') !== -1){\r\n\t\t\t\t\tnodes[a].attributes[i].value = dataParser(nodes[a].attributes[i].value, self.root[model], false, model);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n})();","sf.router = new function(){\r\n\tvar self = this;\r\n\tself.loading = false;\r\n\tself.enabled = false;\r\n\tself.pauseRenderOnTransition = false;\r\n\tself.currentPage = [];\r\n\tvar initialized = false;\r\n\tvar lazyRouting = false;\r\n\tvar currentRouterURL = '';\r\n\r\n\t// Should be called if not using lazy page load\r\n\tself.init = function(targetNode){\r\n\t\tif(!sf.loader.DOMWasLoaded)\r\n\t\t\treturn sf(function(){\r\n\t\t\t\tself.init();\r\n\t\t\t});\r\n\r\n\t\t// Reinit lazy router\r\n\t\tself.lazy();\r\n\r\n\t\t// Run 'before' event for new page view\r\n\t\t$('[sf-controller], [sf-page]', $(targetNode)[0]).each(function(){\r\n\t\t\tif(this.attributes['sf-controller'])\r\n\t\t\t\tsf.controller.run(this.attributes['sf-controller'].value);\r\n\t\t\t\r\n\t\t\tif(this.attributes['sf-page']){\r\n\t\t\t\tvar name = this.attributes['sf-page'].value;\r\n\t\t\t\tbeforeEvent(name);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tinitialized = true;\r\n\t\tcurrentRouterURL = window.location.pathname;\r\n\t}\r\n\r\n\tself.enable = function(status){\r\n\t\tif(status === undefined) status = true;\r\n\t\tif(self.enabled === status) return;\r\n\t\tself.enabled = status;\r\n\r\n\t\tif(status)\r\n\t\t\tself.lazy();\r\n\t\telse{\r\n\t\t\t$('a[href][onclick]').each(function(){\r\n\t\t\t\tvar current = $(this);\r\n\t\t\t\tif(current.attr('onclick') === 'return sf.router.load(this)')\r\n\t\t\t\t\tcurrent.removeAttr('onclick');\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\twindow.addEventListener('popstate', function(event) {\r\n\t\t\t// Don't continue if the last routing was error\r\n\t\t\tif(routingError){\r\n\t\t\t\troutingError = false;\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\troutingBack = true;\r\n\t\t\tself.goto(window.location.pathname);\r\n\t\t}, false);\r\n\t}\r\n\r\n\tvar before = {};\r\n\t// Set index with number if you want to replace old function\r\n\tself.before = function(name, func, index){\r\n\t\tif(!before[name])\r\n\t\t\tbefore[name] = [];\r\n\r\n\t\tif(index === undefined){\r\n\t\t\tif(before[name].indexOf(func) === -1)\r\n\t\t\t\tbefore[name].push(func);\r\n\t\t}\r\n\t\telse\r\n\t\t\tbefore[name][index] = func;\r\n\t}\r\n\r\n\tvar after = {};\r\n\t// Set index with number if you want to replace old function\r\n\tself.after = function(name, func, index){\r\n\t\tif(!after[name])\r\n\t\t\tafter[name] = [];\r\n\r\n\t\tif(index === undefined){\r\n\t\t\tif(after[name].indexOf(func) === -1)\r\n\t\t\t\tafter[name].push(func);\r\n\t\t}\r\n\t\telse\r\n\t\t\tafter[name][index] = func;\r\n\t}\r\n\r\n\tvar root_ = function(scope){\r\n\t\tif(!sf.model.root[scope])\r\n\t\t\tsf.model.root[scope] = {};\r\n\r\n\t\tif(!sf.model.root[scope])\r\n\t\t\tsf.controller.run(scope);\r\n\t\t\r\n\t\treturn sf.model.root[scope];\r\n\t}\r\n\r\n\t// Running 'before' new page going to be displayed\r\n\tvar beforeEvent = function(name){\r\n\t\tif(self.currentPage.indexOf(name) === -1)\r\n\t\t\tself.currentPage.push(name);\r\n\r\n\t\tif(before[name]){\r\n\t\t\tfor (var i = 0; i < before[name].length; i++) {\r\n\t\t\t\tbefore[name][i](root_);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t// Running 'after' old page going to be removed\r\n\tvar afterEvent = function(name){\r\n\t\tif(self.currentPage.indexOf(name) === -1)\r\n\t\t\tself.currentPage.splice(self.currentPage.indexOf(name), 1);\r\n\r\n\t\tif(after[name]){\r\n\t\t\tfor (var i = 0; i < after[name].length; i++) {\r\n\t\t\t\tafter[name][i](root_);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tvar onEvent = {\r\n\t\t'loading':[],\r\n\t\t'loaded':[],\r\n\t\t'special':[],\r\n\t\t'error':[]\r\n\t};\r\n\tself.on = function(event, func){\r\n\t\tif(onEvent[event].indexOf(func) === -1)\r\n\t\t\tonEvent[event].push(func);\r\n\t}\r\n\r\n\tself.lazyViewPoint = {};\r\n\t/*\r\n\t\t{\r\n\t\t\toldURlPattern:{\r\n\t\t\t\tnewURLPattern:'.viewPoint'\r\n\t\t\t}\r\n\t\t}\r\n\t*/\r\n\tself.lazy = function(){\r\n\t\tif(!self.enabled) return;\r\n\r\n\t\t$('a[href]:not([onclick])').each(function(){\r\n\t\t\tvar url = this.href;\r\n\t\t\tif(url.indexOf('#') !== -1)\r\n\t\t\t\treturn;\r\n\r\n\t\t\tif(url.indexOf(window.location.origin) !== 0 && url.charAt(0) !== '/')\r\n\t\t\t\treturn; //Not current domain origin\r\n\r\n\t\t\t$(this).attr('onclick', 'return sf.router.load(this)');\r\n\t\t});\r\n\t}\r\n\r\n\tself.load = function(elem){\r\n\t\tif(!history.pushState || $(elem).attr('sf-router') == 'ignore')\r\n\t\t\treturn true;\r\n\r\n\t\treturn !self.goto(elem.href.replace(window.location.origin, ''));\r\n\t}\r\n\r\n\tvar RouterLoading = false;\r\n\tvar routingBack = false;\r\n\tvar routingError = false;\r\n\tself.goto = function(path, data, method){\r\n\t\tif(!method) method = 'GET';\r\n else method = method.toUpperCase();\r\n\r\n\t\tfor (var i = 0; i < onEvent['loading'].length; i++) {\r\n\t\t\tif(onEvent['loading'][i](path)) return;\r\n\t\t}\r\n\t\tvar oldPath = window.location.pathname;\r\n\t\tinitialized = false;\r\n\r\n\t\tif(RouterLoading) RouterLoading.abort();\r\n\t\tRouterLoading = $.ajax({\r\n\t\t\turl:window.location.origin + path,\r\n\t\t\tmethod:method,\r\n data:Object.assign(data, {\r\n _scarlets:'.dynamic.'\r\n }),\r\n\t\t\tsuccess:function(data){\r\n\t\t\t\tif(initialized) return;\r\n\t\t\t\tlazyRouting = true;\r\n\r\n\t\t\t\t// Run 'loaded' event\r\n\t\t\t\tRouterLoading = false;\r\n\r\n\t\t\t\t// Find special data\r\n\t\t\t\tvar regex = RegExp(''+sf.regex.avoidQuotes, 'gm');\r\n\t\t\t\tvar special = regex.exec(data);\r\n\t\t\t\tif(special && special.length !== 1){\r\n\t\t\t\t\tspecial = special[1].split('--|&>').join('-->');\r\n\t\t\t\t\tspecial = JSON.parse(special);\r\n\r\n\t\t\t\t\tif(!$.isEmptyObject(special)){\r\n\t\t\t\t\t\tfor (var i = 0; i < onEvent['special'].length; i++) {\r\n\t\t\t\t\t\t\tif(onEvent['special'][i](special)) return;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvar DOMReference = false;\r\n\t\t\t\tvar foundAction = function(ref){\r\n\t\t\t\t\tDOMReference = $(ref);\r\n\r\n\t\t\t\t\t// Run 'after' event for old page view\r\n\t\t\t\t\tafterEvent($('[sf-page]', DOMReference[0]).attr('sf-page'));\r\n\r\n\t\t\t\t\t// Redefine title if exist\r\n\t\t\t\t\tif(special && special.title)\r\n\t\t\t\t\t\t$('head title').html(special.title);\r\n\r\n\t\t\t\t\tfound = true;\r\n\t\t\t\t};\r\n\r\n\t\t\t\tvar found = false;\r\n\t\t\t\tfor(var oldURL in self.lazyViewPoint){\r\n\t\t\t\t\tif(currentRouterURL.indexOf(oldURL) !== -1){\r\n\t\t\t\t\t\tfor(var newURL in self.lazyViewPoint[oldURL]){\r\n\t\t\t\t\t\t\tif(currentRouterURL.indexOf(oldURL) !== -1){\r\n\t\t\t\t\t\t\t\tfoundAction(self.lazyViewPoint[oldURL][newURL]);\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif(found) break;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// When the view point was not found\r\n\t\t\t\tif(!found){\r\n\t\t\t\t\t// Use fallback if exist\r\n\t\t\t\t\tif(sf.router.lazyViewPoint[\"@default\"])\r\n\t\t\t\t\t\tfoundAction(sf.router.lazyViewPoint[\"@default\"]);\r\n\r\n\t\t\t\t\tif(!found){\r\n\t\t\t\t\t\tfor (var i = 0; i < onEvent['error'].length; i++) {\r\n\t\t\t\t\t\t\tonEvent['error'][i]('sf.router.lazyViewPoint[\"'+oldURL+'\"][\"'+newURL+'\"] was not found');\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Reinit lazy router\r\n\t\t\t\tself.lazy();\r\n\r\n\t\t\t\t// Run 'before' event for new page view\r\n\t\t\t\tif(!DOMReference) DOMReference = $(document.body);\r\n\t\t\t\tif(self.pauseRenderOnTransition)\r\n\t\t\t\t\tself.pauseRenderOnTransition.css('display', 'none');\r\n\r\n\t\t\t\t// Let page script running first, then update the data binding\r\n\t\t\t\tDOMReference.html(data);\r\n\r\n\t\t\t\t// Parse the DOM data binding\r\n\t\t\t\tsf.model.init(DOMReference);\r\n\r\n\t\t\t\t// Init template to model binding\r\n\t\t\t\t$('[sf-page]', DOMReference[0]).each(function(){\r\n\t\t\t\t\tif(this.attributes['sf-page'])\r\n\t\t\t\t\t\tbeforeEvent(this.attributes['sf-page'].value);\r\n\t\t\t\t});\r\n\r\n\t\t\t\tif(self.pauseRenderOnTransition)\r\n\t\t\t\t\tself.pauseRenderOnTransition.css('display', '');\r\n\r\n\t\t\t\trouterLoaded(currentRouterURL, path, DOMReference);\r\n\r\n\t\t\t\tinitialized = true;\r\n\t\t\t\tlazyRouting = false;\r\n\r\n\t\t\t\tcurrentRouterURL = path;\r\n\t\t\t\troutingError = false;\r\n\t\t\t},\r\n\t\t\terror:function(xhr, data){\r\n\t\t\t\troutingError = true;\r\n\t\t\t\tif(xhr.aborted) return;\r\n\r\n\t\t\t\tRouterLoading = false;\r\n\t\t\t\tfor (var i = 0; i < onEvent['error'].length; i++) {\r\n\t\t\t\t\tonEvent['error'][i](xhr.status, data);\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Back on error\r\n\t\t\t\twindow.history.back();\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tif(!routingBack)\r\n\t\t\twindow.history.pushState(null, \"\", path);\r\n\r\n\t\troutingBack = false;\r\n\t\treturn true;\r\n\t}\r\n\r\n\t// Trigger loaded event\r\n\tfunction routerLoaded(currentRouterURL, path, data){\r\n\t\tfor (var i = 0; i < onEvent['loaded'].length; i++) {\r\n\t\t\tonEvent['loaded'][i](currentRouterURL, path, data);\r\n\t\t}\r\n\t}\r\n};","sf.internal.virtual_scroll = new function(){\r\n\tvar self = this;\r\n\tvar styleInitialized = false;\r\n\r\n\t// before and after\r\n\tself.prepareCount = 4; // 4, 8, 12, 16, ...\r\n\r\n\tself.handle = function(list, targetNode, parentNode){\r\n\t\tif(!styleInitialized){\r\n\t\t\tinitStyles();\r\n\t\t\tstyleInitialized = true;\r\n\t\t}\r\n\r\n\t\tlist.$virtual.elements = function(){\r\n\t\t\treturn obtainElements(list, parentNode);\r\n\t\t}\r\n\r\n\t\tlist.$virtual.dCursor = { // DOM Cursor\r\n\t\t\tceiling:parentNode.querySelector('.virtual-spacer.ceiling'),\r\n\t\t\tfloor:parentNode.querySelector('.virtual-spacer.floor')\r\n\t\t};\r\n\r\n\t\tlist.$virtual.bounding = {\r\n\t\t\tceiling:-1,\r\n\t\t\tfloor:0\r\n\t\t}\r\n\r\n\t\tlist.$virtual.vCursor = { // Virtual Cursor\r\n\t\t\tceiling:null, // for forward direction\r\n\t\t\tfloor:null // for backward direction\r\n\t\t}\r\n\r\n\t\tlist.$virtual.targetNode = parentNode;\r\n\t\tlist.$virtual.DOMCursor = 0; // cursor of first element in DOM tree as a cursor\r\n\r\n\t\tlist.$virtual.scrollHeight = \r\n\t\t\tlist.$virtual.dCursor.floor.offsetTop - \r\n\t\t\tlist.$virtual.dCursor.ceiling.offsetTop;\r\n\r\n\t\tvar scroller = null;\r\n\t\tlist.$virtual.destroy = function(){\r\n\t\t\t$(scroller).off();\r\n\t\t\t$(parentNode).off();\r\n\t\t\tlist.$virtual.dom.innerHTML = '';\r\n\t\t\tdelete list.$virtual;\r\n\t\t}\r\n\r\n\t\tlist.$virtual.resetViewport = function(){\r\n\t\t\tlist.$virtual.visibleLength = Math.floor(scroller.clientHeight / list.$virtual.scrollHeight);\r\n\t\t\tlist.$virtual.preparedLength = list.$virtual.visibleLength + self.prepareCount * 2;\r\n\t\t}\r\n\r\n\t\tsetTimeout(function(){\r\n\t\t\tscroller = parentNode;\r\n\r\n\t\t\tvar length = parentNode.getAttribute('scroll-parent-index') || 0;\r\n\t\t\tfor (var i = 0; i < length; i++) {\r\n\t\t\t\tscroller = scroller.parentElement;\r\n\t\t\t}\r\n\r\n\t\t\tlist.$virtual.resetViewport();\r\n\r\n\t\t\tif(parentNode.classList.contains('sf-list-dynamic'))\r\n\t\t\t\tdynamicHeight(list, targetNode, parentNode, scroller);\r\n\t\t\telse\r\n\t\t\t\tstaticHeight(list, targetNode, parentNode, scroller);\r\n\t\t}, 500);\r\n\t}\r\n\r\n\t// Recommended for a list that have different element height\r\n\tfunction dynamicHeight(list, targetNode, parentNode, scroller){\r\n\t\tvar virtual = list.$virtual;\r\n\t\tvar ceiling = virtual.dCursor.ceiling;\r\n\t\tvar floor = virtual.dCursor.floor;\r\n\t\tvar vCursor = virtual.vCursor;\r\n\t\tvCursor.floor = virtual.dom.firstElementChild;\r\n\t\t\r\n\t\tvirtual.scrollTo = function(index){\r\n\t\t\tscrollTo(index, list, self.prepareCount, parentNode, scroller);\r\n\t\t}\r\n\r\n\t\tvirtual.refresh = function(force){\r\n\t\t\trefresh(force, list, self.prepareCount, parentNode, scroller);\r\n\t\t}\r\n\r\n\t\t// Insert some element until reach visible height\r\n\t\tfillViewport();\r\n\r\n\t\tvirtual.visibleLength = parentNode.childElementCount - 2;\r\n\t\tvirtual.preparedLength = virtual.visibleLength + self.prepareCount * 2;\r\n\r\n\t\tfor (var i = 0; i < self.prepareCount; i++) {\r\n\t\t\tvar temp = vCursor.floor;\r\n\t\t\tif(temp === null) break;\r\n\r\n\t\t\tvCursor.floor = temp.nextElementSibling;\r\n\t\t\tfloor.insertAdjacentElement('beforeBegin', temp);\r\n\t\t}\r\n\t\tvirtual.DOMCursor = 0;\r\n\r\n\t\tvar ceilingHeight = 0;\r\n\t\tvar floorHeight = 0;\r\n\t\tfunction previousCeiling(){\r\n\t\t\tvar temp = null;\r\n\t\t\tvar resetCeiling = false;\r\n\r\n\t\t\t// Add some element on the ceiling\r\n\t\t\tfor (var i = 0; i < self.prepareCount; i++) {\r\n\t\t\t\tif(vCursor.floor === null)\r\n\t\t\t\t\ttemp = virtual.dom.lastElementChild;\r\n\t\t\t\telse\r\n\t\t\t\t\ttemp = vCursor.floor.previousElementSibling;\r\n\r\n\t\t\t\tif(temp === null) break;\r\n\t\t\t\tvCursor.ceiling = temp.previousElementSibling;\r\n\t\t\t\tvirtual.DOMCursor--;\r\n\r\n\t\t\t\tceiling.insertAdjacentElement('afterEnd', temp);\r\n\r\n\t\t\t\tif(ceilingHeight > 0)\r\n\t\t\t\t\tceilingHeight -= getAbsoluteHeight(temp);\r\n\r\n\t\t\t\tif(virtual.DOMCursor < self.prepareCount && !resetCeiling){\r\n\t\t\t\t\ti = 0;\r\n\t\t\t\t\tresetCeiling = true;\r\n\t\t\t\t\ttemp = null;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif(ceilingHeight < 0 || temp === null)\r\n\t\t\t\tceilingHeight = 0;\r\n\r\n\t\t\tvar length = parentNode.childElementCount - 2 - list.$virtual.preparedLength;\r\n\t\t\t// Remove some element on the floor\r\n\t\t\tfor (var i = 0; i < length; i++) {\r\n\t\t\t\ttemp = floor.previousElementSibling;\r\n\t\t\t\tfloorHeight += getAbsoluteHeight(temp);\r\n\r\n\t\t\t\tif(vCursor.floor === null)\r\n\t\t\t\t\tvirtual.dom.insertAdjacentElement('beforeEnd', temp);\r\n\t\t\t\telse vCursor.floor.insertAdjacentElement('beforeBegin', temp);\r\n\r\n\t\t\t\tvCursor.floor = temp;\r\n\t\t\t}\r\n\r\n\t\t\tif(vCursor.floor === null)\r\n\t\t\t\tvCursor.ceiling = virtual.dom.lastElementChild;\r\n\t\t\telse \r\n\t\t\t\tvCursor.ceiling = vCursor.floor.previousElementSibling;\r\n\r\n\t\t\tceiling.style.height = ceilingHeight+'px';\r\n\t\t\tfloor.style.height = floorHeight+'px';\r\n\t\t}\r\n\r\n\t\tfunction fillViewport(){\r\n\t\t\t// Insert some element depend on prepared length\r\n\t\t\tvar length = virtual.preparedLength - (parentNode.childElementCount - 2);\r\n\t\t\tfor (var i = 0; i < length; i++) {\r\n\t\t\t\tif(vCursor.ceiling === null)\r\n\t\t\t\t\ttemp = virtual.dom.firstElementChild;\r\n\t\t\t\telse\r\n\t\t\t\t\ttemp = vCursor.ceiling.nextElementSibling;\r\n\r\n\t\t\t\tif(temp === null) break;\r\n\t\t\t\tvCursor.floor = temp.nextElementSibling;\r\n\r\n\t\t\t\tfloor.insertAdjacentElement('beforeBegin', temp);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tfunction nextFloor(){\r\n\t\t\tvar temp = null;\r\n\t\t\tfillViewport();\r\n\r\n\t\t\tif(vCursor.ceiling === null)\r\n\t\t\t\tvCursor.ceiling = vCursor.floor.previousElementSibling;\r\n\r\n\t\t\t// Add extra element based on prepare count\r\n\t\t\tfor (var i = 0; i < self.prepareCount; i++) {\r\n\t\t\t\ttemp = vCursor.floor;\r\n\t\t\t\tif(temp === null) break;\r\n\r\n\t\t\t\tvCursor.floor = temp.nextElementSibling;\r\n\t\t\t\tfloor.insertAdjacentElement('beforeBegin', temp);\r\n\r\n\t\t\t\tif(floorHeight > 0)\r\n\t\t\t\t\tfloorHeight -= getAbsoluteHeight(temp);\r\n\t\t\t}\r\n\r\n\t\t\tif(floorHeight < 0 || temp === null)\r\n\t\t\t\tfloorHeight = 0;\r\n\r\n\t\t\t// Remove some element on the ceiling\r\n\t\t\tvar length = parentNode.childElementCount - 2 - list.$virtual.preparedLength;\r\n\t\t\tfor (var i = 0; i < length; i++) {\r\n\t\t\t\ttemp = ceiling.nextElementSibling;\r\n\t\t\t\tceilingHeight += getAbsoluteHeight(temp);\r\n\t\t\t\tvirtual.DOMCursor++;\r\n\r\n\t\t\t\tif(vCursor.ceiling === null)\r\n\t\t\t\t\tvirtual.dom.insertAdjacentElement('afterBegin', temp);\r\n\t\t\t\telse vCursor.ceiling.insertAdjacentElement('afterEnd', temp);\r\n\r\n\t\t\t\tvCursor.ceiling = temp;\r\n\t\t\t}\r\n\r\n\t\t\tif(vCursor.ceiling === null)\r\n\t\t\t\tvCursor.floor = virtual.dom.firstElementChild;\r\n\t\t\telse \r\n\t\t\t\tvCursor.floor = vCursor.ceiling.nextElementSibling;\r\n\r\n\t\t\tceiling.style.height = ceilingHeight+'px';\r\n\t\t\tfloor.style.height = floorHeight+'px';\r\n\t\t}\r\n\r\n\t\tvar bounding = virtual.bounding;\r\n\t\trefreshScrollBounding(0, bounding, list, parentNode);\r\n\r\n\t\tvar updating = false;\r\n\t\tfunction checkCursorPosition(){\r\n\t\t\tif(updating) return;\r\n\t\t\tupdating = true;\r\n\r\n\t\t\tif(scroller.scrollTop < bounding.ceiling){\r\n\t\t\t\t// console.log('back', bounding, scroller.scrollTop, virtual.DOMCursor);\r\n\t\t\t\tpreviousCeiling();\r\n\t\t\t\trefreshScrollBounding(virtual.DOMCursor, bounding, list, parentNode);\r\n\t\t\t\t// console.warn('back', bounding, scroller.scrollTop, virtual.DOMCursor);\r\n\t\t\t}\r\n\r\n\t\t\telse if(scroller.scrollTop > bounding.floor){\r\n\t\t\t\t// console.log('front', bounding, scroller.scrollTop, virtual.DOMCursor);\r\n\t\t\t\tnextFloor();\r\n\t\t\t\trefreshScrollBounding(virtual.DOMCursor, bounding, list, parentNode);\r\n\t\t\t\t// console.warn('front', bounding, scroller.scrollTop, virtual.DOMCursor);\r\n\t\t\t}\r\n\r\n\t\t\tupdating = false;\r\n\t\t}\r\n\r\n\t\t$(scroller).on('scroll', checkCursorPosition);\r\n\t\t$(scroller).on('resize', function(){\r\n\t\t\tfillViewport();\r\n\t\t\trefreshScrollBounding(virtual.DOMCursor, bounding, list, parentNode);\r\n\t\t});\r\n\t}\r\n\r\n\t// Recommended for a list that have similar element height\r\n\tfunction staticHeight(list, targetNode, parentNode, scroller){\r\n\t\tvar virtual = list.$virtual;\r\n\t\tvar ceiling = virtual.dCursor.ceiling;\r\n\t\tvar floor = virtual.dCursor.floor;\r\n\r\n\t\t// Insert visible element to dom tree\r\n\t\tvar insertCount = virtual.preparedLength <= list.length ? virtual.preparedLength : list.length;\r\n\t\tfor (var i = 0; i < insertCount; i++) {\r\n\t\t\tif(virtual.dom.firstElementChild === null)\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tfloor.insertAdjacentElement('beforeBegin', virtual.dom.firstElementChild);\r\n\t\t}\r\n\r\n\t\tfunction refreshVirtualSpacer(cursor){\r\n\t\t\tif(cursor >= self.prepareCount){\r\n\t\t\t\tceiling.style.height = (cursor - self.prepareCount) * virtual.scrollHeight + 'px';\r\n\t\t\t\tfloor.style.height = (list.length - virtual.preparedLength - cursor) * virtual.scrollHeight + 'px';\r\n\t\t\t}\r\n\t\t\telse{\r\n\t\t\t\tceiling.style.height = cursor * virtual.scrollHeight + 'px'; //'0px';\r\n\t\t\t\tvar count = (list.length - virtual.preparedLength);\r\n\t\t\t\tfloor.style.height = (count || 0) * virtual.scrollHeight + 'px';\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tvar bounding = virtual.bounding;\r\n\r\n\t\trefreshVirtualSpacer(0);\r\n\t\trefreshScrollBounding(self.prepareCount, bounding, list, parentNode);\r\n\t\tbounding.ceiling = -1;\r\n\r\n\t\tvirtual.offsetTo = function(index){\r\n\t\t\treturn index * virtual.scrollHeight + ceiling.offsetTop;\r\n\t\t}\r\n\r\n\t\tvar vCursor = virtual.vCursor;\r\n\t\tvCursor.floor = virtual.dom.firstElementChild;\r\n\t\tvirtual.scrollTo = function(index){\r\n\t\t\tscrollTo(index, list, self.prepareCount, parentNode, scroller, refreshVirtualSpacer);\r\n\t\t}\r\n\r\n\t\tvirtual.refresh = function(force){\r\n\t\t\trefresh(force, list, self.prepareCount, parentNode, scroller, checkCursorPosition, refreshVirtualSpacer);\r\n\t\t}\r\n\r\n\t\tvar updating = false;\r\n\t\tvar fromCeiling = true;\r\n\t\tvar scrollFocused = false;\r\n\t\tfunction checkCursorPosition(){\r\n\t\t\tif(updating || scroller.scrollTop >= bounding.ceiling && scroller.scrollTop <= bounding.floor){\r\n\t\t\t\t// Fix chrome scroll anchoring bugs when scrolling at corner\r\n\t\t\t\tif(scrollFocused){\r\n\t\t\t\t\tif(scroller.scrollTop === 0 || scroller.scrollTop === scroller.scrollHeight - scroller.clientHeight){\r\n\t\t\t\t\t\tremoveUserScrollFocus(scroller);\r\n\t\t\t\t\t\tscrollFocused = false;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tvar cursor = Math.floor(scroller.scrollTop / virtual.scrollHeight);\r\n\t\t\tif(cursor + virtual.preparedLength > list.length)\r\n\t\t\t\tcursor = list.length - virtual.preparedLength;\r\n\r\n\t\t\tif(fromCeiling){\r\n\t\t\t\tif(cursor < self.prepareCount*2)\r\n\t\t\t\t\tcursor -= self.prepareCount;\r\n\r\n\t\t\t\t// Fix chrome scroll anchoring bugs\r\n\t\t\t\tif(scrollFocused){\r\n\t\t\t\t\tremoveUserScrollFocus(scroller);\r\n\t\t\t\t\tscrollFocused = false;\r\n\t\t\t\t}\r\n\t\t\t\tfromCeiling = false;\r\n\t\t\t}\r\n\r\n\t\t\tif(cursor < self.prepareCount){\r\n\t\t\t\tcursor = 0;\r\n\t\t\t\tfromCeiling = true;\r\n\t\t\t}\r\n\r\n\t\t\tupdating = true;\r\n\r\n\t\t\tvar changes = cursor - virtual.DOMCursor;\r\n\t\t\tif(cursor + changes >= list.length)\r\n\t\t\t\tchanges = cursor + changes - list.length;\r\n\r\n\t\t\tif(changes === 0){ // This should be fixed to improve performance and future bugs\r\n\t\t\t\t//console.warn(\"No changes (The scroll bounding is not correct)\");\r\n\t\t\t\tupdating = false;\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tvirtual.DOMCursor = cursor;\r\n\r\n\t\t\t//console.log(cursor, changes);\r\n\r\n\t\t\t//console.log(cursor, changes, bounding.ceiling, bounding.floor, scroller.scrollTop);\r\n\t\t\tmoveElementCursor(changes, list);\r\n\t\t\trefreshVirtualSpacer(cursor);\r\n\t\t\trefreshScrollBounding(cursor, bounding, list, parentNode);\r\n\t\t\t//console.log('a', bounding.ceiling, bounding.floor, scroller.scrollTop);\r\n\r\n\t\t\tupdating = false;\r\n\t\t}\r\n\r\n\t\t$(scroller).on('scroll', checkCursorPosition);\r\n\r\n\t\t// For preventing scroll jump if scrolling over than viewport\r\n\t\tif(scroller === parentNode && navigator.userAgent.indexOf('Chrom') !== -1){\r\n\t\t\t$(parentNode).on('mousedown', function(){\r\n\t\t\t\tscrollFocused = true;\r\n\t\t\t});\r\n\t\t\t$(parentNode).on('mouseup', function(){\r\n\t\t\t\tscrollFocused = false;\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\tfunction refreshScrollBounding(cursor, bounding, list, parentNode){\r\n\t\tvar temp = Math.floor(self.prepareCount / 2); // half of element preparation\r\n\t\tif(cursor < self.prepareCount){\r\n\t\t\tbounding.ceiling = -1;\r\n\t\t\tbounding.floor = parentNode.children[self.prepareCount * 2 + 1];\r\n\r\n\t\t\tif(bounding.floor !== undefined)\r\n\t\t\t\tbounding.floor = bounding.floor.offsetTop;\r\n\t\t\telse bounding.floor = parentNode.lastElementChild.offsetTop + 1000;\r\n\r\n\t\t\treturn;\r\n\t\t}\r\n\t\telse if(parentNode.children[temp + 1] !== undefined)\r\n\t\t\t\tbounding.ceiling = parentNode.children[temp + 1].offsetTop; // -2 element\r\n\r\n\t\tif(list.$virtual.preparedLength !== undefined && cursor >= list.length - list.$virtual.preparedLength)\r\n\t\t\tbounding.floor = list.$virtual.dCursor.floor.offsetTop + list.$virtual.scrollHeight*2;\r\n\t\telse{\r\n\t\t\tbounding.floor = parentNode.children[self.prepareCount + 3].offsetTop; // +2 element\r\n\r\n\t\t\tif(parentNode.hasAttribute('scroll-reduce-floor')){\r\n\t\t\t\tvar currentFloor = bounding.floor - parentNode.getAttribute('scroll-reduce-floor');\r\n\t\t\t\tif(currentFloor > bounding.ceiling)\r\n\t\t\t\t\tbounding.floor = currentFloor;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tfunction moveElementCursor(changes, list){\r\n\t\tvar vDOM = list.$virtual.dom;\r\n\t\tvar vCursor = list.$virtual.vCursor;\r\n\t\tvar dCursor = list.$virtual.dCursor;\r\n\r\n\t\tif(changes > 0){ // forward\r\n\t\t\tvar ref = 0;\r\n\r\n\t\t\t// Select from virtual ceiling cursor to Dom tree\r\n\t\t\tfor (var i = 0; i < changes; i++) { // vDom -> Dom tree\r\n\t\t\t\tif(vCursor.ceiling === null)\r\n\t\t\t\t\tref = vDOM.firstElementChild;\r\n\r\n\t\t\t\telse ref = vCursor.ceiling.nextElementSibling;\r\n\t\t\t\tdCursor.floor.insertAdjacentElement('beforeBegin', ref);\r\n\t\t\t}\r\n\r\n\t\t\t// Move element on the ceiling to vDom\r\n\t\t\tfor (var i = changes; i > 0; i--) { // Dom tree -> vDom\r\n\t\t\t\tif(vCursor.ceiling === null){\r\n\t\t\t\t\tvCursor.ceiling = dCursor.ceiling.nextElementSibling;\r\n\t\t\t\t\tvDOM.insertAdjacentElement('afterBegin', vCursor.ceiling);\r\n\t\t\t\t}\r\n\t\t\t\telse{\r\n\t\t\t\t\tref = dCursor.ceiling.nextElementSibling;\r\n\t\t\t\t\tvCursor.ceiling.insertAdjacentElement('afterEnd', ref);\r\n\t\t\t\t\tvCursor.ceiling = ref;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tvCursor.floor = vCursor.ceiling.nextElementSibling;\r\n\t\t}\r\n\t\telse if(changes < 0){ // backward\r\n\t\t\tvar ref = 0;\r\n\t\t\tchanges = -changes;\r\n\r\n\t\t\t// Select from virtual floor cursor to Dom tree\r\n\t\t\tfor (var i = 0; i < changes; i++) { // vDom -> Dom tree\r\n\t\t\t\tif(vCursor.floor === null)\r\n\t\t\t\t\tref = vDOM.lastElementChild;\r\n\r\n\t\t\t\telse ref = vCursor.floor.previousElementSibling;\r\n\t\t\t\tdCursor.ceiling.insertAdjacentElement('afterEnd', ref);\r\n\t\t\t}\r\n\r\n\t\t\t// Move element on the floor to vDom\r\n\t\t\tfor (var i = 0; i < changes; i++) { // Dom tree -> vDom\r\n\t\t\t\tif(vCursor.floor === null){\r\n\t\t\t\t\tvCursor.floor = dCursor.floor.previousElementSibling;\r\n\t\t\t\t\tvDOM.insertAdjacentElement('beforeEnd', vCursor.floor);\r\n\t\t\t\t}\r\n\r\n\t\t\t\telse{\r\n\t\t\t\t\tref = dCursor.floor.previousElementSibling;\r\n\t\t\t\t\tvCursor.floor.insertAdjacentElement('beforeBegin', ref);\r\n\t\t\t\t\tvCursor.floor = ref;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tvCursor.ceiling = vCursor.floor.previousElementSibling;\r\n\t\t}\r\n\t}\r\n\r\n\tfunction scrollTo(index, list, prepareCount, parentNode, scroller, refreshVirtualSpacer){\r\n\t\tvar virtual = list.$virtual;\r\n\t\tvar reduce = 0;\r\n\r\n\t\tif(index >= list.length - virtual.preparedLength){\r\n\t\t\treduce -= prepareCount;\r\n\t\t\tindex = list.length - virtual.preparedLength;\r\n\t\t}\r\n\r\n\t\tif(index - virtual.DOMCursor === 0 || index >= list.length) return;\r\n\r\n\t\tupdating = true;\r\n\r\n\t\t// Already on DOM tree\r\n\t\tif((virtual.DOMCursor === 0 && index < prepareCount + prepareCount/2) ||\r\n\t\t\t(virtual.DOMCursor + prepareCount/2 > index\r\n\t\t\t&& virtual.DOMCursor + prepareCount < index))\r\n\t\t\tscroller.scrollTop = parentNode.children[index - virtual.DOMCursor + 1].offsetTop;\r\n\r\n\t\t// Move cursor\r\n\t\telse {\r\n\t\t\tvar temp = null;\r\n\t\t\tvar ceiling = virtual.dCursor.ceiling;\r\n\t\t\tvar floor = virtual.dCursor.floor;\r\n\t\t\tvar vCursor = virtual.vCursor;\r\n\r\n\t\t\t// DOM tree to virtual DOM\r\n\t\t\tvar length = parentNode.childElementCount - 2;\r\n\t\t\tfor (var i = 0; i < length; i++) {\r\n\t\t\t\ttemp = ceiling.nextElementSibling;\r\n\r\n\t\t\t\tif(vCursor.floor === null){\r\n\t\t\t\t\tvirtual.dom.insertAdjacentElement('beforeEnd', temp);\r\n\r\n\t\t\t\t\tif(i === length-1)\r\n\t\t\t\t\t\tvCursor.floor = temp;\r\n\t\t\t\t}\r\n\t\t\t\telse vCursor.floor.insertAdjacentElement('beforeBegin', temp);\r\n\t\t\t}\r\n\r\n\t\t\tif(index >= prepareCount){\r\n\t\t\t\tif(index < list.length - virtual.preparedLength)\r\n\t\t\t\t\tindex -= prepareCount;\r\n\t\t\t}\r\n\t\t\telse{\r\n\t\t\t\treduce = prepareCount - index;\r\n\t\t\t\tvirtual.DOMCursor = index = 0;\r\n\t\t\t}\r\n\r\n\t\t\tvar insertCount = virtual.preparedLength <= list.length ? virtual.preparedLength : list.length;\r\n\r\n\t\t\t// Virtual DOM to DOM tree\r\n\t\t\tfor (var i = 0; i < insertCount; i++) {\r\n\t\t\t\ttemp = virtual.dom.children[index];\r\n\t\t\t\tif(temp === undefined) break;\r\n\r\n\t\t\t\tfloor.insertAdjacentElement('beforeBegin', temp);\r\n\t\t\t}\r\n\t\t\tvirtual.DOMCursor = index;\r\n\r\n\t\t\tvCursor.floor = virtual.dom.children[index] || null;\r\n\t\t\tvCursor.ceiling = vCursor.floor ? vCursor.floor.previousElementSibling : null;\r\n\r\n\t\t\tif(refreshVirtualSpacer)\r\n\t\t\t\trefreshVirtualSpacer(index);\r\n\r\n\t\t\trefreshScrollBounding(index, virtual.bounding, list, parentNode);\r\n\r\n\t\t\ttemp = parentNode.children[prepareCount - reduce + 1];\r\n\t\t\tif(temp !== undefined)\r\n\t\t\t\tscroller.scrollTop = temp.offsetTop;\r\n\t\t}\r\n\r\n\t\tupdating = false;\r\n\t}\r\n\r\n\tfunction removeUserScrollFocus(parentNode){\r\n\t\tparentNode.style.overflow = 'hidden';\r\n\t\tsetTimeout(function(){\r\n\t\t\tparentNode.style.overflow = '';\r\n\t\t}, 50);\r\n\t}\r\n\r\n\tfunction getAbsoluteHeight(el){\r\n\t var styles = window.getComputedStyle(el);\r\n\t var margin = parseInt(styles['marginTop']) + parseInt(styles['marginBottom']);\r\n\t return el.offsetHeight + margin || 0;\r\n\t}\r\n\r\n\tfunction obtainElements(list, parentNode){\r\n\t\tvar exist = [];\r\n\t\tvar temp = undefined;\r\n\r\n\t\tvar length = list.$virtual.DOMCursor;\r\n\t\tfor (var i = 0; i < length; i++) {\r\n\t\t\ttemp = list.$virtual.dom.children[i];\r\n\t\t\tif(temp === undefined) break;\r\n\t\t\texist.push(temp);\r\n\t\t}\r\n\r\n\t\tlength = parentNode.childElementCount - 2;\r\n\t\tfor (var i = 1; i <= length; i++) {\r\n\t\t\ttemp = parentNode.children[i];\r\n\t\t\tif(temp === undefined) break;\r\n\t\t\texist.push(temp);\r\n\t\t}\r\n\r\n\t\tlength = list.length - length - list.$virtual.DOMCursor;\r\n\t\tfor (var i = 0; i < length; i++) {\r\n\t\t\ttemp = list.$virtual.dom.children[list.$virtual.DOMCursor + i];\r\n\t\t\tif(temp === undefined) break;\r\n\t\t\texist.push(temp);\r\n\t\t}\r\n\r\n\t\treturn exist;\r\n\t}\r\n\r\n\tfunction refresh(force, list, prepareCount, parentNode, scroller, checkCursorPosition, refreshVirtualSpacer){\r\n\t\tvar cursor = list.$virtual.DOMCursor;\r\n\r\n\t\t// Find nearest cursor for current view position\r\n\t\tif(force){\r\n\t\t\tvar i = -1;\r\n\t\t\tvar length = list.$virtual.preparedLength;\r\n\r\n\t\t\tdo{\r\n\t\t\t\ti++;\r\n\t\t\t} while(i < length && parentNode.children[i].offsetTop < scroller.scrollTop);\r\n\r\n\t\t\tcursor = cursor + i;\r\n\t\t\tif(cursor > 0) cursor -= 1;\r\n\t\t}\r\n\r\n\t\t// Force move cursor if element in the DOM tree was overloaded\r\n\t\tif(force || parentNode.childElementCount - 2 > list.$virtual.preparedLength){\r\n\t\t\tlist.$virtual.DOMCursor = list.length;\r\n\t\t\tvar moveTo = cursor;\r\n\t\t\tif(!force)\r\n\t\t\t\tmoveTo = cursor <= prepareCount ? cursor : (cursor + prepareCount);\r\n\r\n\t\t\tscrollTo(moveTo,\r\n\t\t\t\tlist,\r\n\t\t\t\tprepareCount,\r\n\t\t\t\tparentNode,\r\n\t\t\t\tscroller,\r\n\t\t\t\trefreshVirtualSpacer\r\n\t\t\t);\r\n\t\t}\r\n\r\n\t\tif(refreshVirtualSpacer)\r\n\t\t\trefreshVirtualSpacer(cursor);\r\n\r\n\t\tif(checkCursorPosition)\r\n\t\t\tcheckCursorPosition();\r\n\r\n\t\trefreshScrollBounding(cursor, list.$virtual.bounding, list, parentNode);\r\n\t}\r\n\r\n\tfunction initStyles(){\r\n\t\tvar style = document.getElementById('sf-styles');\r\n\r\n\t\tif(!style){\r\n\t\t\tstyle = document.createElement('style');\r\n\t\t\tstyle.id = 'sf-styles';\r\n \tdocument.head.appendChild(style);\r\n\t\t}\r\n\r\n\t\tstyle.sheet.insertRule(\r\n\t\t'.sf-virtual-list .virtual-spacer{'+\r\n 'visibility: hidden;'+\r\n 'position: relative;'+\r\n 'height: 1px;'+\r\n 'transform-origin: 0 0;'+\r\n 'width: 1px;'+\r\n 'margin: 0;'+\r\n 'padding: 0;'+\r\n 'background: none;'+\r\n 'border: none;'+\r\n 'box-shadow: none;'+\r\n '}');\r\n\t}\r\n};"]} \ No newline at end of file diff --git a/package.json b/package.json index ee5416b..bcaa50b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "scarletsframe", "description":"A frontend framework that can help you write a simple web structure", - "version": "0.9.2", + "version": "0.9.3", "repository": { "type": "git", "url": "https://github.com/ScarletsFiction/ScarletsFrame.git"