diff --git a/dist/scarletsframe.js b/dist/scarletsframe.js index 760069d..cb37778 100644 --- a/dist/scarletsframe.js +++ b/dist/scarletsframe.js @@ -562,6 +562,10 @@ sf.model = function(scope){ firstTime = false; } + // Remove var because no variable are being passed + if(firstTime === true) + strDeclare = strDeclare.replace('var ', ''); + // Disable function call for addional security eval protection strDeclare = strDeclare.split('(').join('').split(')').join(''); @@ -608,12 +612,15 @@ sf.model = function(scope){ check = temp.split('@if '); if(check.length != 1){ check = check[1].split(':'); + var scopes = [check[0], _model_, _modelScope, _content_]; - // If condition was meet - if(localEval.apply(self.root, [check[0], _model_, _modelScope, _content_])){ - check.shift(); - return check.join(':'); - } + // If condition was not meet + if(localEval.apply(self.root, scopes) == false) + return ''; + + check.shift(); + scopes.splice(0, 1, check.join(':').split('&VarPass&').join('{}')); + return localEval.apply(self.root, scopes); } // Get defined variables @@ -931,6 +938,7 @@ sf.model = function(scope){ content = content.replace(/ +|\t+/g, ''); if(method.length === 2){ + var temp = ''; for(var i in items){ var item = items[i]; @@ -1412,9 +1420,6 @@ sf.router = new function(){ self.init(); }); - // Reinit lazy router - self.lazy(); - // Run 'before' event for new page view $('[sf-controller], [sf-page]', $(targetNode)[0]).each(function(){ if(this.attributes['sf-controller']) @@ -1430,31 +1435,33 @@ sf.router = new function(){ currentRouterURL = window.location.pathname; } + function popstateListener(event) { + // Don't continue if the last routing was error + if(routingError){ + routingError = false; + return; + } + + routingBack = true; + self.goto(window.location.pathname); + } + self.enable = function(status){ if(status === undefined) status = true; if(self.enabled === status) return; self.enabled = status; - if(status) - self.lazy(); + if(status === true){ + // Create listener for link click + $(document.body).on('click', 'a[href]', self.load); + + // Create listener when navigate backward + window.addEventListener('popstate', popstateListener, false); + } else{ - $('a[href][onclick]').each(function(){ - var current = $(this); - if(current.attr('onclick') === 'return sf.router.load(this)') - current.removeAttr('onclick'); - }); + $(document.body).off('click', 'a[href]', self.load); + window.removeEventListener('popstate', popstateListener, false); } - - window.addEventListener('popstate', function(event) { - // Don't continue if the last routing was error - if(routingError){ - routingError = false; - return; - } - - routingBack = true; - self.goto(window.location.pathname); - }, false); } var before = {}; @@ -1538,26 +1545,23 @@ sf.router = new function(){ } } */ - self.lazy = function(){ - if(!self.enabled) return; - $('a[href]:not([onclick])').each(function(){ - var url = this.href; - if(url.indexOf('#') !== -1) - return; + self.load = function(ev){ + if(self.enabled !== true) return; - if(url.indexOf(window.location.origin) !== 0 && url.charAt(0) !== '/') - return; //Not current domain origin + var elem = ev.target; + if(!elem.href) return; - $(this).attr('onclick', 'return sf.router.load(this)'); - }); - } + if(!history.pushState || elem.hasAttribute('sf-router-ignore')) + return; - self.load = function(elem){ - if(!history.pushState || $(elem).attr('sf-router') == 'ignore') - return true; + // Make sure it's from current origin + var path = elem.href.replace(window.location.origin, ''); + if(path.indexOf('//') !== -1) + return; - return !self.goto(elem.href.replace(window.location.origin, '')); + ev.preventDefault() + return !self.goto(path); } var RouterLoading = false; @@ -1567,6 +1571,8 @@ sf.router = new function(){ if(!method) method = 'GET'; else method = method.toUpperCase(); + if(!data) data = {}; + for (var i = 0; i < onEvent['loading'].length; i++) { if(onEvent['loading'][i](path)) return; } @@ -1641,9 +1647,6 @@ sf.router = new function(){ } } - // Reinit lazy router - self.lazy(); - // Run 'before' event for new page view if(!DOMReference) DOMReference = $(document.body); if(self.pauseRenderOnTransition) @@ -2228,8 +2231,9 @@ sf.internal.virtual_scroll = new function(){ refreshScrollBounding(index, virtual.bounding, list, parentNode); temp = parentNode.children[prepareCount - reduce + 1]; + if(temp !== undefined) - scroller.scrollTop = temp.offsetTop; + scroller.scrollTop = temp.offsetTop - scroller.offsetTop; } scrollingByScript = false; diff --git a/dist/scarletsframe.min.js b/dist/scarletsframe.min.js index f884b47..f418dfc 100644 --- a/dist/scarletsframe.min.js +++ b/dist/scarletsframe.min.js @@ -6,5 +6,5 @@ https://github.com/ScarletsFiction/ScarletsFrame */ -!function(e,t){var r=null;if("object"==typeof exports&&"undefined"!=typeof module){try{r=require("dom7")}catch(e){try{r=require("jquery")}catch(e){}}if(null===r)return void console.log("ScarletsFrame can't load jQuery or Dom7!");module.exports=t(r)}else{if("undefined"!=typeof Dom7)r=Dom7;else{if("undefined"==typeof jQuery)throw"Please load jQuery before ScarletsFrame";r=jQuery}e.sf=t(r)}}(this,function($){"use strict";var sf=function e(){if(arguments[0].constructor===Function)return e.loader.onFinish.apply(null,arguments)};return sf.internal={},sf.regex={avoidQuotes:"(?=(?:[^\"']*(?:'|\")[^\"']*(?:'|\"))*[^\"']*$)",strictVar:"(?=\\b[^.]|^|\\n| +|\\t|\\W )"},$.fn.extend||($.fn.extend=function(e){for(var t in e)$.fn[t]=e[t]}),$.isEmptyObject||($.isEmptyObject=function(e){for(var t in e)return!1;return!0}),$.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,e.DOMReady=!1,e.turnedOff=!1;var t=[],r=[],n=[];e.off=function(){e.turnedOff=!0},e.onFinish=function(t){if(e.DOMWasLoaded)return t();-1===r.indexOf(t)&&r.push(t)},e.domReady=function(r){if(e.DOMReady)return r();-1===t.indexOf(r)&&t.push(r)},e.onProgress=function(t){if(e.DOMWasLoaded)return t(e.loadedContent,e.totalContent);-1===n.indexOf(t)&&n.push(t)},e.f=function(t){e.loadedContent++;for(var r=0;r=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';e.domReady(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!1===/{{.*?}}/.test(t)?"_result_ += '"+t.split("'").join("\\'")+"'":(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,u=[],c=null;null!==(c=f.exec(n));)u.push(c[2]);if(u.length){for(var d=[],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"],u=-1,c=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(u),u=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 c=self.root[n][o],d="",p=0;p=0;i--)c(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,c(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=sf.controller.modelName(this);if(e){var t=this.getAttribute("sf-bound");if(void 0!==typeof self.root[e][t]){this.setAttribute("sf-bounded",t),this.removeAttribute("sf-bound");var r=$(this);"INPUT"===this.tagName||"TEXTAREA"===this.tagName?r.on("keyup",function(n){self.root[e][t]=r.val()}):r.on("change",function(n){self.root[e][t]=r.val()})}else console.error('Cannot get reference for self.root["'+e+'"]["'+t+'"]')}})},alreadyInitialized=!1;function DOMNodeRemoved(e){$("[sf-controller]",e).each(function(){removeModelBinding(this.getAttribute("sf-controller"))}),!1!==e.hasAttribute("sf-controller")&&removeModelBinding(e.getAttribute("sf-controller"))}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 u=t.attr("sf-repeat-this");t.removeAttr("sf-repeat-this");var c=sf.controller.modelName(this),d=this.outerHTML;if(/sf-bind-key|sf-bind-list/.test(d))throw"Can't parse element that already bound";if(this.parentNode.classList.contains("sf-virtual-list"))loopParser(c,d,u,e,this.parentNode)?t.remove():(t.attr("sf-bind-list",u.split(" in ")[1]),clearElementData(this));else{var p=loopParser(c,d,u,e,this.parentNode);p?(t.remove(),p=$(p),s?p.insertBefore(s):f?p.insertAfter(f):r.append(p)):(t.attr("sf-bind-list",u.split(" in ")[1]),clearElementData(this))}}))},sf(function(){var e=function(e){var t=e.nodeName;"TEXT"!==t&&"#text"!==t&&"#comment"!==t&&DOMNodeRemoved(e)};if("function"==typeof MutationObserver&&MutationObserver.prototype.observe){var t=function(t){t.removedNodes.forEach(e)};new MutationObserver(function(e){bindingEnabled&&e.forEach(t)}).observe(document.body,{childList:!0,subtree:!0})}else document.body.addEventListener("DOMNodeRemoved",function(t){bindingEnabled&&e(t.target)})});var removeModelBinding=function(e){var t=self.root[e];if(void 0!==t){var r=t.sf$bindedKey,n=null;for(var o in r)if(delete r[o],void 0!==t[o]&&null!==t[o]){if(t[o].constructor===String||t[o].constructor===Number||t[o].constructor===Boolean);else{if(t[o].constructor!==Array)continue;t[o].$virtual&&(t[o].$virtual.destroy(),delete t[o].$virtual),n=t[o].splice("obtain"),delete t[o],t[o]=n}if(void 0!==Object.getOwnPropertyDescriptor(t,o)){n=t[o];delete t[o],t[o]=n}}}},dcBracket=/{{[\s\S]*?}}/,bindObject=function(e,t,r,n){e instanceof Node||(e=e[0]),processingElement=e,e.setAttribute("sf-bind-key",r);var o=sf.controller.modelName(e);if("attr"===n||!n){var i={};for(var l in e.attributes)if(dcBracket.test(e.attributes[l].value)){var a=e.attributes[l].name;"value"===a&&e.removeAttribute(a),i[a]=e.attributes[l].value}}if("html"===n||!n)var s=e.innerHTML;e=$(e);var f=function(){if("attr"===n||!n)for(var l in i)if(-1!==i[l].indexOf(r)){var a=dataParser(i[l],t,!1,o);"value"===l?e.val(a):e.attr(l,a);break}if("html"===n||!n){a=uniqueDataParser(s,t,!1,o);a=dataParser(a,t,!1,o),e.html(a)}};if(void 0===t[r])throw"Property '"+r+"' was not found on '"+o+"' model";if(void 0===t.sf$bindedKey&&initBindingInformation(t),void 0===t.sf$bindedKey[r]){var u=t[r];Object.defineProperty(t,r,{enumerable:!0,configurable:!0,get:function(){return u},set:function(e){u=e;for(var n=t.sf$bindedKey[r],o=0;o=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"),u=null;null!==(s=i.exec(o));)for(;null!==(u=f.exec(s[1]));)bindObject(e,n,u[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"),c=JSON.parse(c),!$.isEmptyObject(c)))for(var d=0;d=n.length-n.$virtual.preparedLength?r.floor=n.$virtual.dCursor.floor.offsetTop+2*n.$virtual.scrollHeight:(r.floor=o.children[e.prepareCount+3].offsetTop,o.hasAttribute("scroll-reduce-floor")&&(r.floor-=o.getAttribute("scroll-reduce-floor"),r.ceiling-=o.getAttribute("scroll-reduce-floor")))}function o(e,t,o,i,l,a){var s=t.$virtual,f=0;if(e>=t.length-s.preparedLength&&(f-=o,e=t.length-s.preparedLength),!(e-s.DOMCursor==0||e>=t.length)){if(r=!0,0===s.DOMCursor&&ee&&s.DOMCursor+o=o?e0&&(f-=1),u=l.scrollTop-i.children[c].offsetTop}if(e||i.childElementCount-2>t.$virtual.preparedLength){t.$virtual.DOMCursor=t.length;var p=f;e||(p=f<=r?f:f+r),o(p,t,r,i,l,s),l.scrollTop+=u}s&&s(f),a&&a(),n(f,t.$virtual.bounding,t,i)}e.prepareCount=4,e.handle=function(u,c,d){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),u.$virtual.elements=function(){return function(e,t){for(var r=[],n=void 0,o=e.$virtual.DOMCursor,i=0;i=0;t--)s[t].element===e&&s.splice(t,1)}(d),delete u.$virtual},u.$virtual.resetViewport=function(){u.$virtual.visibleLength=Math.floor(p.clientHeight/u.$virtual.scrollHeight),u.$virtual.preparedLength=u.$virtual.visibleLength+2*e.prepareCount},setTimeout(function(){p=d;for(var t=d.getAttribute("scroll-parent-index")||0,c=0;c0&&(b-=l(r)),d.DOMCursorC.floor&&(!function(){var r=null;E(),null===v.ceiling&&(v.ceiling=v.floor.previousElementSibling);for(var n=0;n0&&(y-=l(r));(y<0||null===r)&&(y=0);for(var o=u.childElementCount-2-t.$virtual.preparedLength,n=0;n=0;t--)(e=s[t]).element.scrollHeight!==e.height&&e.element.scrollWidth!==e.width&&(null!==e.element.parentElement?e.callback():s.splice(t,1));0===s.length&&(clearInterval(f),f=-1)},200));s.push({element:e,callback:t,height:e.scrollHeight,width:e.scrollWidth})}(u,function(){n(d.DOMCursor,C,t,u)})}(u,0,d,p):function(t,l,s,f){for(var u=t.$virtual,c=u.dCursor.ceiling,d=u.dCursor.floor,p=u.preparedLength<=t.length?u.preparedLength:t.length,h=0;h=e.prepareCount)c.style.height=(r-e.prepareCount)*u.scrollHeight+"px",d.style.height=(t.length-u.preparedLength-r)*u.scrollHeight+"px";else{c.style.height=r*u.scrollHeight+"px";var n=t.length-u.preparedLength;d.style.height=(n||0)*u.scrollHeight+"px"}}var g=u.bounding;v(0),n(e.prepareCount,g,t,s),g.ceiling=-1,u.offsetTo=function(e){return e*u.scrollHeight+c.offsetTop},u.vCursor.floor=u.dom.firstElementChild,u.scrollTo=function(r){o(r,t,e.prepareCount,s,f,v)},u.refresh=function(r){a(r,t,e.prepareCount,s,f,E,v)};var m=!1,b=!0,y=!1;function E(){if(m||r||f.scrollTop>=g.ceiling&&f.scrollTop<=g.floor)y&&(0!==f.scrollTop&&f.scrollTop!==f.scrollHeight-f.clientHeight||(i(f),y=!1));else{var o=Math.floor(f.scrollTop/u.scrollHeight);o+u.preparedLength>t.length&&(o=t.length-u.preparedLength),b&&(o<2*e.prepareCount&&(o-=e.prepareCount),y&&(i(f),y=!1),b=!1),o=t.length&&(l=o+l-t.length),0!==l?(u.DOMCursor=o,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';e.domReady(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!0===l&&(i=i.replace("var ","")),i=i.split("(").join("").split(")").join(""),dataParser(this[o],t,r,n,i+";")}};e=e.replace(/{\[([\s\S]*?)\]}/g,function(e,t){return!1===/{{.*?}}/.test(t)?"_result_ += '"+t.split("'").join("\\'")+"'":(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){var f=[(s=s[1].split(":"))[0],t,i,o];return 0==localEval.apply(self.root,f)?"":(s.shift(),f.splice(0,1,s.join(":").split("&VarPass&").join("{}")),localEval.apply(self.root,f))}for(var u=/(var|let)([\w,\s]+)(?=\s(?==|in|of))/g,c=[],d=null;null!==(d=u.exec(n));)c.push(d[2]);if(c.length){for(var p=[],v=0;v").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"],u=-1,c=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(u),u=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 c=self.root[n][o],d="",p=0;p=0;i--)c(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,c(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=sf.controller.modelName(this);if(e){var t=this.getAttribute("sf-bound");if(void 0!==typeof self.root[e][t]){this.setAttribute("sf-bounded",t),this.removeAttribute("sf-bound");var r=$(this);"INPUT"===this.tagName||"TEXTAREA"===this.tagName?r.on("keyup",function(n){self.root[e][t]=r.val()}):r.on("change",function(n){self.root[e][t]=r.val()})}else console.error('Cannot get reference for self.root["'+e+'"]["'+t+'"]')}})},alreadyInitialized=!1;function DOMNodeRemoved(e){$("[sf-controller]",e).each(function(){removeModelBinding(this.getAttribute("sf-controller"))}),!1!==e.hasAttribute("sf-controller")&&removeModelBinding(e.getAttribute("sf-controller"))}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 u=t.attr("sf-repeat-this");t.removeAttr("sf-repeat-this");var c=sf.controller.modelName(this),d=this.outerHTML;if(/sf-bind-key|sf-bind-list/.test(d))throw"Can't parse element that already bound";if(this.parentNode.classList.contains("sf-virtual-list"))loopParser(c,d,u,e,this.parentNode)?t.remove():(t.attr("sf-bind-list",u.split(" in ")[1]),clearElementData(this));else{var p=loopParser(c,d,u,e,this.parentNode);p?(t.remove(),p=$(p),s?p.insertBefore(s):f?p.insertAfter(f):r.append(p)):(t.attr("sf-bind-list",u.split(" in ")[1]),clearElementData(this))}}))},sf(function(){var e=function(e){var t=e.nodeName;"TEXT"!==t&&"#text"!==t&&"#comment"!==t&&DOMNodeRemoved(e)};if("function"==typeof MutationObserver&&MutationObserver.prototype.observe){var t=function(t){t.removedNodes.forEach(e)};new MutationObserver(function(e){bindingEnabled&&e.forEach(t)}).observe(document.body,{childList:!0,subtree:!0})}else document.body.addEventListener("DOMNodeRemoved",function(t){bindingEnabled&&e(t.target)})});var removeModelBinding=function(e){var t=self.root[e];if(void 0!==t){var r=t.sf$bindedKey,n=null;for(var o in r)if(delete r[o],void 0!==t[o]&&null!==t[o]){if(t[o].constructor===String||t[o].constructor===Number||t[o].constructor===Boolean);else{if(t[o].constructor!==Array)continue;t[o].$virtual&&(t[o].$virtual.destroy(),delete t[o].$virtual),n=t[o].splice("obtain"),delete t[o],t[o]=n}if(void 0!==Object.getOwnPropertyDescriptor(t,o)){n=t[o];delete t[o],t[o]=n}}}},dcBracket=/{{[\s\S]*?}}/,bindObject=function(e,t,r,n){e instanceof Node||(e=e[0]),processingElement=e,e.setAttribute("sf-bind-key",r);var o=sf.controller.modelName(e);if("attr"===n||!n){var i={};for(var l in e.attributes)if(dcBracket.test(e.attributes[l].value)){var a=e.attributes[l].name;"value"===a&&e.removeAttribute(a),i[a]=e.attributes[l].value}}if("html"===n||!n)var s=e.innerHTML;e=$(e);var f=function(){if("attr"===n||!n)for(var l in i)if(-1!==i[l].indexOf(r)){var a=dataParser(i[l],t,!1,o);"value"===l?e.val(a):e.attr(l,a);break}if("html"===n||!n){a=uniqueDataParser(s,t,!1,o);a=dataParser(a,t,!1,o),e.html(a)}};if(void 0===t[r])throw"Property '"+r+"' was not found on '"+o+"' model";if(void 0===t.sf$bindedKey&&initBindingInformation(t),void 0===t.sf$bindedKey[r]){var u=t[r];Object.defineProperty(t,r,{enumerable:!0,configurable:!0,get:function(){return u},set:function(e){u=e;for(var n=t.sf$bindedKey[r],o=0;o=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"),u=null;null!==(s=i.exec(o));)for(;null!==(u=f.exec(s[1]));)bindObject(e,n,u[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"),u=JSON.parse(u),!$.isEmptyObject(u)))for(var d=0;d=n.length-n.$virtual.preparedLength?r.floor=n.$virtual.dCursor.floor.offsetTop+2*n.$virtual.scrollHeight:(r.floor=o.children[e.prepareCount+3].offsetTop,o.hasAttribute("scroll-reduce-floor")&&(r.floor-=o.getAttribute("scroll-reduce-floor"),r.ceiling-=o.getAttribute("scroll-reduce-floor")))}function o(e,t,o,i,l,a){var s=t.$virtual,f=0;if(e>=t.length-s.preparedLength&&(f-=o,e=t.length-s.preparedLength),!(e-s.DOMCursor==0||e>=t.length)){if(r=!0,0===s.DOMCursor&&ee&&s.DOMCursor+o=o?e0&&(f-=1),u=l.scrollTop-i.children[c].offsetTop}if(e||i.childElementCount-2>t.$virtual.preparedLength){t.$virtual.DOMCursor=t.length;var p=f;e||(p=f<=r?f:f+r),o(p,t,r,i,l,s),l.scrollTop+=u}s&&s(f),a&&a(),n(f,t.$virtual.bounding,t,i)}e.prepareCount=4,e.handle=function(u,c,d){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),u.$virtual.elements=function(){return function(e,t){for(var r=[],n=void 0,o=e.$virtual.DOMCursor,i=0;i=0;t--)s[t].element===e&&s.splice(t,1)}(d),delete u.$virtual},u.$virtual.resetViewport=function(){u.$virtual.visibleLength=Math.floor(p.clientHeight/u.$virtual.scrollHeight),u.$virtual.preparedLength=u.$virtual.visibleLength+2*e.prepareCount},setTimeout(function(){p=d;for(var t=d.getAttribute("scroll-parent-index")||0,c=0;c0&&(b-=l(r)),d.DOMCursorC.floor&&(!function(){var r=null;E(),null===h.ceiling&&(h.ceiling=h.floor.previousElementSibling);for(var n=0;n0&&(y-=l(r));(y<0||null===r)&&(y=0);for(var o=u.childElementCount-2-t.$virtual.preparedLength,n=0;n=0;t--)(e=s[t]).element.scrollHeight!==e.height&&e.element.scrollWidth!==e.width&&(null!==e.element.parentElement?e.callback():s.splice(t,1));0===s.length&&(clearInterval(f),f=-1)},200));s.push({element:e,callback:t,height:e.scrollHeight,width:e.scrollWidth})}(u,function(){n(d.DOMCursor,C,t,u)})}(u,0,d,p):function(t,l,s,f){for(var u=t.$virtual,c=u.dCursor.ceiling,d=u.dCursor.floor,p=u.preparedLength<=t.length?u.preparedLength:t.length,v=0;v=e.prepareCount)c.style.height=(r-e.prepareCount)*u.scrollHeight+"px",d.style.height=(t.length-u.preparedLength-r)*u.scrollHeight+"px";else{c.style.height=r*u.scrollHeight+"px";var n=t.length-u.preparedLength;d.style.height=(n||0)*u.scrollHeight+"px"}}var g=u.bounding;h(0),n(e.prepareCount,g,t,s),g.ceiling=-1,u.offsetTo=function(e){return e*u.scrollHeight+c.offsetTop},u.vCursor.floor=u.dom.firstElementChild,u.scrollTo=function(r){o(r,t,e.prepareCount,s,f,h)},u.refresh=function(r){a(r,t,e.prepareCount,s,f,E,h)};var m=!1,b=!0,y=!1;function E(){if(m||r||f.scrollTop>=g.ceiling&&f.scrollTop<=g.floor)y&&(0!==f.scrollTop&&f.scrollTop!==f.scrollHeight-f.clientHeight||(i(f),y=!1));else{var o=Math.floor(f.scrollTop/u.scrollHeight);o+u.preparedLength>t.length&&(o=t.length-u.preparedLength),b&&(o<2*e.prepareCount&&(o-=e.prepareCount),y&&(i(f),y=!1),b=!1),o=t.length&&(l=o+l-t.length),0!==l?(u.DOMCursor=o,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\tself.domReady(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 && !self.turnedOff){\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.DOMReady === false){\r\n\t\t\tself.DOMReady = true;\r\n\t\t\tfor (var i = 0; i < whenDOMReady.length; i++) {\r\n\t\t\t\ttry{\r\n\t\t\t\t\twhenDOMReady[i]();\r\n\t\t\t\t} catch(e) {\r\n\t\t\t\t\tconsole.error(e);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\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\twhenDOMReady.splice(0);\r\n\t\twhenDOMLoaded.splice(0);\r\n\t\twhenProgress = whenDOMReady = whenDOMLoaded = null;\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\nsf.loader.domReady(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}, 0);","// 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\t\"use strict\";\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\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\r\n\t\ttry{\r\n\t\t\tif(/@return /.test(script_) === true){\r\n\t\t\t\tvar _evaled_ = eval('(function(){'+script_.split('@return ').join('return ')+'})()');\r\n\t\t\t\treturn _result_ + _evaled_;\r\n\t\t\t}\r\n\t\t\telse var _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\tif(/{{.*?}}/.test(matched) === false)\r\n\t\t\t\treturn \"_result_ += '\"+matched.split(\"'\").join(\"\\\\'\")+\"'\";\r\n\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// Obtaining all data\r\n\t\t\t\t\t\tif(arguments[0] === null){\r\n\t\t\t\t\t\t\toldArray.splice(0);\r\n\t\t\t\t\t\t\treturn temp;\r\n\t\t\t\t\t\t}\r\n\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\tif(parentNode && parentNode.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);\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\r\n\t\tObject.defineProperty(list, 'getElement', {\r\n\t\t\tenumerable: false,\r\n\t\t\tconfigurable: true,\r\n\t\t\tvalue: function(index){\r\n\t\t\t\tif(list.$virtual){\r\n\t\t\t\t\tif(index < list.$virtual.DOMCursor)\r\n\t\t\t\t\t\treturn list.$virtual.dom.children[index];\r\n\r\n\t\t\t\t\tindex -= list.$virtual.DOMCursor;\r\n\t\t\t\t\tvar reducedIndex = index - parentNode.childElementCount + 2;\r\n\t\t\t\t\tif(reducedIndex <= 0)\r\n\t\t\t\t\t\treturn parentNode.children[index + 1];\r\n\r\n\t\t\t\t\treturn list.$virtual.dom.children[index + list.$virtual.DOMCursor];\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif(parentNode.childElementCount === list.length)\r\n\t\t\t\t\treturn parentNode.children[index];\r\n\r\n\t\t\t\treturn parentNode.querySelectorAll('[sf-bind-list=\"'+propertyName+'\"]')[index];\r\n\t\t\t}\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\r\n\t\t\tvar modelRef = self.root[name];\r\n\r\n\t\t\t// Enable element binding\r\n\t\t\tif(modelRef.sf$bindedKey === undefined)\r\n\t\t\t\tinitBindingInformation(modelRef);\r\n\r\n\t\t\tif(modelRef.sf$bindedKey[method[1]] === undefined)\r\n\t\t\t\tmodelRef.sf$bindedKey[method[1]] = null;\r\n\r\n\t\t\tObject.defineProperty(modelRef, 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\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 model = sf.controller.modelName(this);\r\n\t\t\tif(!model) return;\r\n\r\n\t\t\tvar whichVar = this.getAttribute('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\tthis.setAttribute('sf-bounded', whichVar);\r\n\t\t\tthis.removeAttribute('sf-bound');\r\n\r\n\t\t\t// Bound value change\r\n\t\t\tvar element = $(this);\r\n\t\t\tif(this.tagName === 'INPUT' || this.tagName === 'TEXTAREA')\r\n\t\t\t\telement.on('keyup', function(e){\r\n\t\t\t\t\tself.root[model][whichVar] = element.val();\r\n\t\t\t\t});\r\n\r\n\t\t\telse\r\n\t\t\t\telement.on('change', function(e){\r\n\t\t\t\t\tself.root[model][whichVar] = element.val();\r\n\t\t\t\t});\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-key|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))\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, this.parentNode);\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\t$('[sf-controller]', element).each(function(){\r\n\t\t\tremoveModelBinding(this.getAttribute('sf-controller'));\r\n\t\t});\r\n\r\n\t\tif(element.hasAttribute('sf-controller') === false)\r\n\t\t\treturn;\r\n\r\n\t\tremoveModelBinding(element.getAttribute('sf-controller'));\r\n\t}\r\n\r\n\tsf(function(){\r\n\t\tvar everyRemovedNodes = function(nodes){\r\n\t\t\tvar tagName = nodes.nodeName;\r\n\t\t\tif(tagName === 'TEXT' || tagName === '#text' || tagName === '#comment') return;\r\n\r\n\t\t\tDOMNodeRemoved(nodes);\r\n\t\t}\r\n\r\n\t\tif(typeof MutationObserver === 'function' && MutationObserver.prototype.observe){\r\n\t\t\tvar everyRecords = function(record){\r\n\t\t\t\trecord.removedNodes.forEach(everyRemovedNodes);\r\n\t\t\t}\r\n\r\n\t\t\tvar observer = new MutationObserver(function(records){\r\n\t\t\t\tif(!bindingEnabled) return;\r\n\t\t\t\trecords.forEach(everyRecords);\r\n\t\t\t});\r\n\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) return;\r\n\t\t\t\teveryRemovedNodes(e.target);\r\n\t\t\t});\r\n\t\t}\r\n\t});\r\n\r\n\tvar removeModelBinding = function(modelName){\r\n\t\tvar ref = self.root[modelName];\r\n\t\tif(ref === undefined)\r\n\t\t\treturn;\r\n\r\n\t\tvar bindedKey = ref.sf$bindedKey;\r\n\t\tvar temp = null;\r\n\t\tfor(var key in bindedKey){\r\n\t\t\tdelete bindedKey[key];\r\n\r\n\t\t\tif(ref[key] === undefined || ref[key] === null)\r\n\t\t\t\tcontinue;\r\n\r\n\t\t\tif(ref[key].constructor === String ||\r\n\t\t\t\tref[key].constructor === Number ||\r\n\t\t\t\tref[key].constructor === Boolean\r\n\t\t\t){/* Ok */}\r\n\r\n\t\t\telse if(ref[key].constructor === Array){\r\n\t\t\t\tif(ref[key].$virtual){\r\n\t\t\t\t\tref[key].$virtual.destroy();\r\n\t\t\t\t\tdelete ref[key].$virtual;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Reset property without copying the array\r\n\t\t\t\ttemp = ref[key].splice('obtain');\r\n\t\t\t\tdelete ref[key];\r\n\t\t\t\tref[key] = temp;\r\n\t\t\t}\r\n\t\t\telse continue;\r\n\r\n\t\t\tif(Object.getOwnPropertyDescriptor(ref, key) === undefined)\r\n\t\t\t\tcontinue;\r\n\r\n\t\t\t// Reconfigure / Remove property descriptor\r\n\t\t\tvar temp = ref[key];\r\n\t\t\tdelete ref[key];\r\n\t\t\tref[key] = temp;\r\n\t\t}\r\n\t}\r\n\r\n\tvar dcBracket = /{{[\\s\\S]*?}}/;\r\n\tvar bindObject = function(element, modelRef, 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\telement.setAttribute('sf-bind-key', propertyName);\r\n\t\tvar modelName = sf.controller.modelName(element);\r\n\r\n\t\t// Cache attribute content\r\n\t\tif(which === 'attr' || !which){\r\n\t\t\tvar attrs = {};\r\n\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\tif(attrName === 'value')\r\n\t\t\t\t\telement.removeAttribute(attrName);\r\n\r\n\t\t\t\tattrs[attrName] = element.attributes[i].value;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Cache html content\r\n\t\tif(which === 'html' || !which)\r\n\t\t\tvar innerHTML = element.innerHTML;\r\n\r\n\t\telement = $(element);\r\n\t\tvar onChanges = function(){\r\n\t\t\tif(which === 'attr' || !which){\r\n\t\t\t\tfor(var name in attrs){\r\n\t\t\t\t\tif(attrs[name].indexOf(propertyName) === -1)\r\n\t\t\t\t\t\tcontinue;\r\n\r\n\t\t\t\t\tvar temp = dataParser(attrs[name], modelRef, false, modelName);\r\n\t\t\t\t\tif(name === 'value')\r\n\t\t\t\t\t\telement.val(temp);\r\n\t\t\t\t\telse\r\n\t\t\t\t\t\telement.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(innerHTML, modelRef, false, modelName);\r\n\t\t\t\ttemp = dataParser(temp, modelRef, false, modelName);\r\n\t\t\t\telement.html(temp);\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tif(modelRef[propertyName] === undefined)\r\n\t\t\tthrow \"Property '\"+propertyName+\"' was not found on '\"+modelName+\"' model\";\r\n\r\n\t\t// Enable multiple element binding\r\n\t\tif(modelRef.sf$bindedKey === undefined)\r\n\t\t\tinitBindingInformation(modelRef);\r\n\r\n\t\tif(modelRef.sf$bindedKey[propertyName] !== undefined){\r\n\t\t\tmodelRef.sf$bindedKey[propertyName].push(onChanges);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tvar objValue = modelRef[propertyName]; // Object value\r\n\t\tObject.defineProperty(modelRef, 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\tvar ref = modelRef.sf$bindedKey[propertyName];\r\n\t\t\t\tfor (var i = 0; i < ref.length; i++) {\r\n\t\t\t\t\tref[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\r\n\t\tmodelRef.sf$bindedKey[propertyName] = [onChanges];\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-key|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-key'] || 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\tvar modelRef = self.root[model];\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-key|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\r\n\tfunction initBindingInformation(modelRef){\r\n\t\tif(modelRef.sf$bindedKey !== undefined)\r\n\t\t\treturn;\r\n\r\n\t\t// Element binding data\r\n\t\tObject.defineProperty(modelRef, 'sf$bindedKey', {\r\n\t\t\tconfigurable: true,\r\n\t\t\tenumerable:false,\r\n\t\t\twritable:true,\r\n\t\t\tvalue:{}\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\tvar scrollingByScript = 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('scroll');\r\n\t\t\t$(parentNode).off('mousedown mouseup');\r\n\t\t\tlist.$virtual.dom.innerHTML = '';\r\n\t\t\toffElementResize(parentNode);\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 || scrollingByScript) 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\tonElementResize(parentNode, function(){\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 || scrollingByScript || 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\tbounding.floor -= parentNode.getAttribute('scroll-reduce-floor');\r\n\t\t\t\tbounding.ceiling -= parentNode.getAttribute('scroll-reduce-floor');\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\tscrollingByScript = 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\tscrollingByScript = 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\t\tvar additionalScroll = 0;\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\r\n\t\t\tadditionalScroll = scroller.scrollTop - parentNode.children[i].offsetTop;\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\r\n\t\t\tscroller.scrollTop += additionalScroll;\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\tvar _onElementResize = [];\r\n\tvar _onElementResize_timer = -1;\r\n\tfunction onElementResize(parentNode, callback){\r\n\t\tif(_onElementResize_timer === -1){\r\n\t\t\t_onElementResize_timer = setInterval(function(){\r\n\t\t\t\tvar temp = null;\r\n\t\t\t\tfor (var i = _onElementResize.length - 1; i >= 0; i--) {\r\n\t\t\t\t\ttemp = _onElementResize[i];\r\n\r\n\t\t\t\t\t// Check resize\r\n\t\t\t\t\tif(temp.element.scrollHeight === temp.height\r\n\t\t\t\t\t\t|| temp.element.scrollWidth === temp.width)\r\n\t\t\t\t\t\tcontinue;\r\n\r\n\t\t\t\t\t// Check if it's removed from DOM\r\n\t\t\t\t\tif(temp.element.parentElement === null){\r\n\t\t\t\t\t\t_onElementResize.splice(i, 1);\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\ttemp.callback();\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif(_onElementResize.length === 0){\r\n\t\t\t\t\tclearInterval(_onElementResize_timer);\r\n\t\t\t\t\t_onElementResize_timer = -1;\r\n\t\t\t\t}\r\n\t\t\t}, 200);\r\n\t\t}\r\n\r\n\t\t_onElementResize.push({\r\n\t\t\telement:parentNode,\r\n\t\t\tcallback:callback,\r\n\t\t\theight:parentNode.scrollHeight,\r\n\t\t\twidth:parentNode.scrollWidth\r\n\t\t});\r\n\t}\r\n\r\n\tfunction offElementResize(parentNode){\r\n\t\tfor (var i = _onElementResize.length - 1; i >= 0; i--) {\r\n\t\t\tif(_onElementResize[i].element === parentNode)\r\n\t\t\t\t_onElementResize.splice(i, 1);\r\n\t\t}\r\n\r\n\t\t// Interval will be cleared when the array is empty\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-z_end.js","sf-controller.js","sf-loader.js","sf-model.js","sf-router.js","sf-virtual_scroll.js"],"names":["global","factory","$","exports","module","require","e","console","log","Dom7","jQuery","sf","this","arguments","constructor","Function","loader","onFinish","apply","internal","regex","avoidQuotes","strictVar","fn","extend","obj","func","isEmptyObject","key","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","target","script","eq","_modelScope","modelKeys","scopeMask","RegExp","replace","full","matched","split","method","method_","eval","shift","join","pop","error","root_","scope","DOMWasLoaded","init","parent","document","body","each","on","loadedContent","totalContent","DOMReady","turnedOff","whenDOMReady","whenDOMLoaded","whenProgress","off","indexOf","push","domReady","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_","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","JSON","stringify","check","scopes","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","children","childElementCount","querySelectorAll","obj1","obj2","loopParser","content","returns","items","sf$bindedKey","initBindingInformation","get","set","softRefresh","bindInput","whichVar","alreadyInitialized","DOMNodeRemoved","removeModelBinding","hasAttribute","Node","parsePreprocess","queuePreprocess","ceiling","add","floor","append","styles","window","getComputedStyle","absHeight","parseFloat","Math","ceil","offsetHeight","after","next","before","removeAttr","data","everyRemovedNodes","nodes","nodeName","MutationObserver","observe","everyRecords","record","removedNodes","records","childList","subtree","addEventListener","bindedKey","String","Number","Boolean","destroy","getOwnPropertyDescriptor","dcBracket","bindObject","which","attrs","attrName","onChanges","objValue","writable","bindElement","brackets","s2","childNodes","excludes","toUpperCase","currentNode","nodeType","a","concat","nodeValue","loading","enabled","pauseRenderOnTransition","currentPage","initialized","currentRouterURL","popstateListener","event","routingError","routingBack","goto","location","pathname","beforeEvent","enable","status","load","removeEventListener","onEvent","loaded","special","lazyViewPoint","ev","href","history","pushState","path","origin","preventDefault","RouterLoading","abort","assign","_scarlets","success","parse","DOMReference","foundAction","afterEvent","title","found","oldURL","newURL","routerLoaded","xhr","aborted","back","styleInitialized","scrollingByScript","refreshScrollBounding","cursor","bounding","prepareCount","offsetTop","lastElementChild","preparedLength","dCursor","scrollHeight","scrollTo","scroller","refreshVirtualSpacer","virtual","reduce","scrollTop","vCursor","nextElementSibling","insertAdjacentElement","insertCount","previousElementSibling","removeUserScrollFocus","overflow","getAbsoluteHeight","el","margin","parseInt","force","checkCursorPosition","additionalScroll","moveTo","getElementById","id","head","appendChild","sheet","insertRule","initStyles","obtainElements","querySelector","_onElementResize","offElementResize","resetViewport","visibleLength","clientHeight","parentElement","firstElementChild","fillViewport","ceilingHeight","floorHeight","updating","resetCeiling","height","previousCeiling","nextFloor","_onElementResize_timer","scrollWidth","width","onElementResize","dynamicHeight","count","offsetTo","fromCeiling","scrollFocused","changes","vDOM","moveElementCursor","navigator","userAgent","staticHeight"],"mappings":"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","file":"scarletsframe.min.js","sourcesContent":["(function(global, factory){\r\n var $ = null;\r\n if(typeof exports === 'object' && typeof module !== 'undefined'){\r\n \ttry { $ = require(\"dom7\") }catch(e){\r\n \t\ttry { $ = require(\"jquery\") }catch(e){}\r\n \t}\r\n\r\n \tif($ === null){\r\n \t\tconsole.log(\"ScarletsFrame can't load jQuery or Dom7!\");\r\n \t\treturn;\r\n \t}\r\n\r\n \tmodule.exports = factory($);\r\n }\r\n\r\n else{\r\n\tif(typeof Dom7 !== 'undefined')\r\n\t\t$ = Dom7;\r\n\telse if(typeof jQuery !== 'undefined')\r\n\t\t$ = jQuery;\r\n\telse\r\n\t\tthrow \"Please load jQuery before ScarletsFrame\";\r\n\r\n \tglobal.sf = factory($);\r\n }\r\n}(this, (function($){'use strict';\r\n// ===== Module Init =====\r\n\r\nvar 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(!$.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\nif(!$.isEmptyObject){\r\n\t$.isEmptyObject = function(obj){\r\n\t\tfor(var key in obj){\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\treturn true\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});","return sf;\r\n\r\n// ===== Module End =====\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\r\n\t\treturn sf.model.root[scope];\r\n\t}\r\n\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\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.DOMReady = false;\r\n\tself.turnedOff = false;\r\n\r\n\tvar whenDOMReady = [];\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.domReady = function(func){\r\n\t\tif(self.DOMReady) return func();\r\n\t\tif(whenDOMReady.indexOf(func) !== -1) return;\r\n\t\twhenDOMReady.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\tself.domReady(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 && !self.turnedOff){\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.DOMReady === false){\r\n\t\t\tself.DOMReady = true;\r\n\t\t\tfor (var i = 0; i < whenDOMReady.length; i++) {\r\n\t\t\t\ttry{\r\n\t\t\t\t\twhenDOMReady[i]();\r\n\t\t\t\t} catch(e) {\r\n\t\t\t\t\tconsole.error(e);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\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\twhenDOMReady.splice(0);\r\n\t\twhenDOMLoaded.splice(0);\r\n\t\twhenProgress = whenDOMReady = whenDOMLoaded = null;\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\nsf.loader.domReady(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}, 0);","// 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\t\"use strict\";\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\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\r\n\t\ttry{\r\n\t\t\tif(/@return /.test(script_) === true){\r\n\t\t\t\tvar _evaled_ = eval('(function(){'+script_.split('@return ').join('return ')+'})()');\r\n\t\t\t\treturn _result_ + _evaled_;\r\n\t\t\t}\r\n\t\t\telse var _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// Remove var because no variable are being passed\r\n\t\t\t\tif(firstTime === true)\r\n\t\t\t\t\tstrDeclare = strDeclare.replace('var ', '');\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\tif(/{{.*?}}/.test(matched) === false)\r\n\t\t\t\treturn \"_result_ += '\"+matched.split(\"'\").join(\"\\\\'\")+\"'\";\r\n\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\tvar scopes = [check[0], _model_, _modelScope, _content_];\r\n\t\t\t\r\n\t\t\t\t// If condition was not meet\r\n\t\t\t\tif(localEval.apply(self.root, scopes) == false)\r\n\t\t\t\t\treturn '';\r\n\r\n\t\t\t\tcheck.shift();\r\n\t\t\t\tscopes.splice(0, 1, check.join(':').split('&VarPass&').join('{}'));\r\n\t\t\t\treturn localEval.apply(self.root, scopes);\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// Obtaining all data\r\n\t\t\t\t\t\tif(arguments[0] === null){\r\n\t\t\t\t\t\t\toldArray.splice(0);\r\n\t\t\t\t\t\t\treturn temp;\r\n\t\t\t\t\t\t}\r\n\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\tif(parentNode && parentNode.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);\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\r\n\t\tObject.defineProperty(list, 'getElement', {\r\n\t\t\tenumerable: false,\r\n\t\t\tconfigurable: true,\r\n\t\t\tvalue: function(index){\r\n\t\t\t\tif(list.$virtual){\r\n\t\t\t\t\tif(index < list.$virtual.DOMCursor)\r\n\t\t\t\t\t\treturn list.$virtual.dom.children[index];\r\n\r\n\t\t\t\t\tindex -= list.$virtual.DOMCursor;\r\n\t\t\t\t\tvar reducedIndex = index - parentNode.childElementCount + 2;\r\n\t\t\t\t\tif(reducedIndex <= 0)\r\n\t\t\t\t\t\treturn parentNode.children[index + 1];\r\n\r\n\t\t\t\t\treturn list.$virtual.dom.children[index + list.$virtual.DOMCursor];\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif(parentNode.childElementCount === list.length)\r\n\t\t\t\t\treturn parentNode.children[index];\r\n\r\n\t\t\t\treturn parentNode.querySelectorAll('[sf-bind-list=\"'+propertyName+'\"]')[index];\r\n\t\t\t}\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\tvar temp = '';\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\r\n\t\t\tvar modelRef = self.root[name];\r\n\r\n\t\t\t// Enable element binding\r\n\t\t\tif(modelRef.sf$bindedKey === undefined)\r\n\t\t\t\tinitBindingInformation(modelRef);\r\n\r\n\t\t\tif(modelRef.sf$bindedKey[method[1]] === undefined)\r\n\t\t\t\tmodelRef.sf$bindedKey[method[1]] = null;\r\n\r\n\t\t\tObject.defineProperty(modelRef, 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\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 model = sf.controller.modelName(this);\r\n\t\t\tif(!model) return;\r\n\r\n\t\t\tvar whichVar = this.getAttribute('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\tthis.setAttribute('sf-bounded', whichVar);\r\n\t\t\tthis.removeAttribute('sf-bound');\r\n\r\n\t\t\t// Bound value change\r\n\t\t\tvar element = $(this);\r\n\t\t\tif(this.tagName === 'INPUT' || this.tagName === 'TEXTAREA')\r\n\t\t\t\telement.on('keyup', function(e){\r\n\t\t\t\t\tself.root[model][whichVar] = element.val();\r\n\t\t\t\t});\r\n\r\n\t\t\telse\r\n\t\t\t\telement.on('change', function(e){\r\n\t\t\t\t\tself.root[model][whichVar] = element.val();\r\n\t\t\t\t});\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-key|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))\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, this.parentNode);\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\t$('[sf-controller]', element).each(function(){\r\n\t\t\tremoveModelBinding(this.getAttribute('sf-controller'));\r\n\t\t});\r\n\r\n\t\tif(element.hasAttribute('sf-controller') === false)\r\n\t\t\treturn;\r\n\r\n\t\tremoveModelBinding(element.getAttribute('sf-controller'));\r\n\t}\r\n\r\n\tsf(function(){\r\n\t\tvar everyRemovedNodes = function(nodes){\r\n\t\t\tvar tagName = nodes.nodeName;\r\n\t\t\tif(tagName === 'TEXT' || tagName === '#text' || tagName === '#comment') return;\r\n\r\n\t\t\tDOMNodeRemoved(nodes);\r\n\t\t}\r\n\r\n\t\tif(typeof MutationObserver === 'function' && MutationObserver.prototype.observe){\r\n\t\t\tvar everyRecords = function(record){\r\n\t\t\t\trecord.removedNodes.forEach(everyRemovedNodes);\r\n\t\t\t}\r\n\r\n\t\t\tvar observer = new MutationObserver(function(records){\r\n\t\t\t\tif(!bindingEnabled) return;\r\n\t\t\t\trecords.forEach(everyRecords);\r\n\t\t\t});\r\n\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) return;\r\n\t\t\t\teveryRemovedNodes(e.target);\r\n\t\t\t});\r\n\t\t}\r\n\t});\r\n\r\n\tvar removeModelBinding = function(modelName){\r\n\t\tvar ref = self.root[modelName];\r\n\t\tif(ref === undefined)\r\n\t\t\treturn;\r\n\r\n\t\tvar bindedKey = ref.sf$bindedKey;\r\n\t\tvar temp = null;\r\n\t\tfor(var key in bindedKey){\r\n\t\t\tdelete bindedKey[key];\r\n\r\n\t\t\tif(ref[key] === undefined || ref[key] === null)\r\n\t\t\t\tcontinue;\r\n\r\n\t\t\tif(ref[key].constructor === String ||\r\n\t\t\t\tref[key].constructor === Number ||\r\n\t\t\t\tref[key].constructor === Boolean\r\n\t\t\t){/* Ok */}\r\n\r\n\t\t\telse if(ref[key].constructor === Array){\r\n\t\t\t\tif(ref[key].$virtual){\r\n\t\t\t\t\tref[key].$virtual.destroy();\r\n\t\t\t\t\tdelete ref[key].$virtual;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Reset property without copying the array\r\n\t\t\t\ttemp = ref[key].splice('obtain');\r\n\t\t\t\tdelete ref[key];\r\n\t\t\t\tref[key] = temp;\r\n\t\t\t}\r\n\t\t\telse continue;\r\n\r\n\t\t\tif(Object.getOwnPropertyDescriptor(ref, key) === undefined)\r\n\t\t\t\tcontinue;\r\n\r\n\t\t\t// Reconfigure / Remove property descriptor\r\n\t\t\tvar temp = ref[key];\r\n\t\t\tdelete ref[key];\r\n\t\t\tref[key] = temp;\r\n\t\t}\r\n\t}\r\n\r\n\tvar dcBracket = /{{[\\s\\S]*?}}/;\r\n\tvar bindObject = function(element, modelRef, 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\telement.setAttribute('sf-bind-key', propertyName);\r\n\t\tvar modelName = sf.controller.modelName(element);\r\n\r\n\t\t// Cache attribute content\r\n\t\tif(which === 'attr' || !which){\r\n\t\t\tvar attrs = {};\r\n\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\tif(attrName === 'value')\r\n\t\t\t\t\telement.removeAttribute(attrName);\r\n\r\n\t\t\t\tattrs[attrName] = element.attributes[i].value;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Cache html content\r\n\t\tif(which === 'html' || !which)\r\n\t\t\tvar innerHTML = element.innerHTML;\r\n\r\n\t\telement = $(element);\r\n\t\tvar onChanges = function(){\r\n\t\t\tif(which === 'attr' || !which){\r\n\t\t\t\tfor(var name in attrs){\r\n\t\t\t\t\tif(attrs[name].indexOf(propertyName) === -1)\r\n\t\t\t\t\t\tcontinue;\r\n\r\n\t\t\t\t\tvar temp = dataParser(attrs[name], modelRef, false, modelName);\r\n\t\t\t\t\tif(name === 'value')\r\n\t\t\t\t\t\telement.val(temp);\r\n\t\t\t\t\telse\r\n\t\t\t\t\t\telement.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(innerHTML, modelRef, false, modelName);\r\n\t\t\t\ttemp = dataParser(temp, modelRef, false, modelName);\r\n\t\t\t\telement.html(temp);\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tif(modelRef[propertyName] === undefined)\r\n\t\t\tthrow \"Property '\"+propertyName+\"' was not found on '\"+modelName+\"' model\";\r\n\r\n\t\t// Enable multiple element binding\r\n\t\tif(modelRef.sf$bindedKey === undefined)\r\n\t\t\tinitBindingInformation(modelRef);\r\n\r\n\t\tif(modelRef.sf$bindedKey[propertyName] !== undefined){\r\n\t\t\tmodelRef.sf$bindedKey[propertyName].push(onChanges);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tvar objValue = modelRef[propertyName]; // Object value\r\n\t\tObject.defineProperty(modelRef, 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\tvar ref = modelRef.sf$bindedKey[propertyName];\r\n\t\t\t\tfor (var i = 0; i < ref.length; i++) {\r\n\t\t\t\t\tref[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\r\n\t\tmodelRef.sf$bindedKey[propertyName] = [onChanges];\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-key|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-key'] || 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\tvar modelRef = self.root[model];\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-key|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\r\n\tfunction initBindingInformation(modelRef){\r\n\t\tif(modelRef.sf$bindedKey !== undefined)\r\n\t\t\treturn;\r\n\r\n\t\t// Element binding data\r\n\t\tObject.defineProperty(modelRef, 'sf$bindedKey', {\r\n\t\t\tconfigurable: true,\r\n\t\t\tenumerable:false,\r\n\t\t\twritable:true,\r\n\t\t\tvalue:{}\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// 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\tfunction popstateListener(event) {\r\n\t\t// Don't continue if the last routing was error\r\n\t\tif(routingError){\r\n\t\t\troutingError = false;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\troutingBack = true;\r\n\t\tself.goto(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 === true){\r\n\t\t\t// Create listener for link click\r\n\t\t\t$(document.body).on('click', 'a[href]', self.load);\r\n\r\n\t\t\t// Create listener when navigate backward\r\n\t\t\twindow.addEventListener('popstate', popstateListener, false);\r\n\t\t}\r\n\t\telse{\r\n\t\t\t$(document.body).off('click', 'a[href]', self.load);\r\n\t\t\twindow.removeEventListener('popstate', popstateListener, false);\r\n\t\t}\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\r\n\tself.load = function(ev){\r\n\t\tif(self.enabled !== true) return;\r\n\r\n\t\tvar elem = ev.target;\r\n\t\tif(!elem.href) return;\r\n\r\n\t\tif(!history.pushState || elem.hasAttribute('sf-router-ignore'))\r\n\t\t\treturn;\r\n\r\n\t\t// Make sure it's from current origin\r\n\t\tvar path = elem.href.replace(window.location.origin, '');\r\n\t\tif(path.indexOf('//') !== -1)\r\n\t\t\treturn;\r\n\r\n\t\tev.preventDefault()\r\n\t\treturn !self.goto(path);\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\tif(!data) data = {};\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// 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\tvar scrollingByScript = 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('scroll');\r\n\t\t\t$(parentNode).off('mousedown mouseup');\r\n\t\t\tlist.$virtual.dom.innerHTML = '';\r\n\t\t\toffElementResize(parentNode);\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 || scrollingByScript) 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\tonElementResize(parentNode, function(){\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 || scrollingByScript || 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\tbounding.floor -= parentNode.getAttribute('scroll-reduce-floor');\r\n\t\t\t\tbounding.ceiling -= parentNode.getAttribute('scroll-reduce-floor');\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\tscrollingByScript = 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\r\n\t\t\tif(temp !== undefined)\r\n\t\t\t\tscroller.scrollTop = temp.offsetTop - scroller.offsetTop;\r\n\t\t}\r\n\r\n\t\tscrollingByScript = 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\t\tvar additionalScroll = 0;\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\r\n\t\t\tadditionalScroll = scroller.scrollTop - parentNode.children[i].offsetTop;\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\r\n\t\t\tscroller.scrollTop += additionalScroll;\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\tvar _onElementResize = [];\r\n\tvar _onElementResize_timer = -1;\r\n\tfunction onElementResize(parentNode, callback){\r\n\t\tif(_onElementResize_timer === -1){\r\n\t\t\t_onElementResize_timer = setInterval(function(){\r\n\t\t\t\tvar temp = null;\r\n\t\t\t\tfor (var i = _onElementResize.length - 1; i >= 0; i--) {\r\n\t\t\t\t\ttemp = _onElementResize[i];\r\n\r\n\t\t\t\t\t// Check resize\r\n\t\t\t\t\tif(temp.element.scrollHeight === temp.height\r\n\t\t\t\t\t\t|| temp.element.scrollWidth === temp.width)\r\n\t\t\t\t\t\tcontinue;\r\n\r\n\t\t\t\t\t// Check if it's removed from DOM\r\n\t\t\t\t\tif(temp.element.parentElement === null){\r\n\t\t\t\t\t\t_onElementResize.splice(i, 1);\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\ttemp.callback();\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif(_onElementResize.length === 0){\r\n\t\t\t\t\tclearInterval(_onElementResize_timer);\r\n\t\t\t\t\t_onElementResize_timer = -1;\r\n\t\t\t\t}\r\n\t\t\t}, 200);\r\n\t\t}\r\n\r\n\t\t_onElementResize.push({\r\n\t\t\telement:parentNode,\r\n\t\t\tcallback:callback,\r\n\t\t\theight:parentNode.scrollHeight,\r\n\t\t\twidth:parentNode.scrollWidth\r\n\t\t});\r\n\t}\r\n\r\n\tfunction offElementResize(parentNode){\r\n\t\tfor (var i = _onElementResize.length - 1; i >= 0; i--) {\r\n\t\t\tif(_onElementResize[i].element === parentNode)\r\n\t\t\t\t_onElementResize.splice(i, 1);\r\n\t\t}\r\n\r\n\t\t// Interval will be cleared when the array is empty\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