@apicart/brackets
Version:
Small, flexible, easy to use, component-oriented javascript template engine.
7 lines (6 loc) • 13.9 kB
JavaScript
/**
* brackets.js v1.0.0-alpha2
* (c) 2018-2019 Vladimír Macháček
* Released under the MIT License.
*/
!function(e){"function"==typeof define&&define.amd?define(e):e()}(function(){"use strict";var utils={cloneObject:function(t){var n={};return Object.keys(t).forEach(function(e){n[e]=t&&typeof t===Object(t)?utils.cloneObject(t[e]):t[e]}),n},mergeObjects:function(){var n={},e=Array.prototype.slice.call(arguments);return utils.each(e,function(e,t){utils.each(t,function(e,t){n[e]=e in n&&utils.isObject(t)?utils.mergeObjects(n[e],t):t})}),n},isObject:function(e){return null!=e&&!Array.isArray(e)&&"object"==typeof e},each:function(e,t){var n,r,a,i,s,c={iterableLength:0,counter:0,isEven:function(){return this.counter%2==0},isOdd:function(){return 1===Math.abs(this.counter%2)},isFirst:function(){return 1===this.counter},isLast:function(){return this.counter===this.iterableLength}};if(!(-1<["undefined","number"].indexOf(typeof e)||null===e))if(Array.isArray(e)){if(!(r=Object.keys(e).length))return;for(c.iterableLength=r,n=0;n<r&&(c.counter++,!1!==t.apply(c,[n,e[n]]));n++);}else{if(i=(a=Object.keys(e)).length,!a.length)return;for(c.iterableLength=i,n=0;n<i&&(c.counter++,s=a[n],!1!==t.apply(c,[s,e[s]]));n++);}},generateHash:function(e){return e=e||10,e+=2,Math.random().toString(36).substring(2,e)}},macros={break:"break;",breakIf:"if (#0) break;",continue:"continue;",continueIf:"if (#0) continue;",component:function(e){var t=e[0].split(","),n=t[0];return t.shift(),"_template += _runtime.components.renderToString.call(_runtime, '"+n+"', "+("{"+t.join(",")+"}")+");"},dump:"console.log(#0);",else:"} else {",elseif:"} else if (#0) {",for:"for (var #0) {","/for":"}",foreach:function(e){var t=(e=e[0].split("as"))[1].trim();return 1===e[1].split(",").length&&(t="key, "+t),"_runtime.utils.each("+e[0].trim()+", function ("+t+") {"},"/foreach":"});",if:"if (#0) {","/if":"}",js:"#0;",returnFalseIf:"if (#0) return false;",returnIf:"if (#0) return;",var:"var #0;",while:"while (#0) {","/while":"}"},openingDelimiter,closingDelimiter,macrosRegularExpression,openingDelimiter$1,closingDelimiter$1,tokenReplacement,textRegularExpression;function addMacro(e,t){if(e in macros)throw new Error('Brackets: Macro "'+e+'" is already defined.');return macros[e]=t,generateMacrosRegularExpression(),Brackets}function getMacros(){return macros}function generateMacrosRegularExpression(){macrosRegularExpression=new RegExp(openingDelimiter+" *(?:(?:("+Object.keys(macros).join("|").replace("/","/")+")(?: (.*?))?) *| *(?:(\\$.*?))) *"+closingDelimiter)}function initMacros(e){openingDelimiter=e.delimiters[0],closingDelimiter=e.delimiters[1],generateMacrosRegularExpression()}function tokenizeTemplate(e){var t,n,r,a=[],i=[];if(e){for(;t=macrosRegularExpression.exec(e);)n=[],r=t[0],t.shift(),utils.each(t,function(e,t){isNaN(parseInt(e))||void 0!==t&&n.push(t)}),a.push(n),e=e.replace(r,tokenReplacement);for(e=openingDelimiter$1+e+closingDelimiter$1;t=textRegularExpression.exec(e);)i.push(t[1]),e=e.replace(t[0],"")}return{macros:a,text:i}}function initTemplateTokenizer(e){openingDelimiter$1=e.delimiters[0],closingDelimiter$1=e.delimiters[1],textRegularExpression=new RegExp(openingDelimiter$1+"((?:.|\n)*?)"+closingDelimiter$1),tokenReplacement=closingDelimiter$1+openingDelimiter$1}var Brackets={config:{devMode:!1,delimiters:["{{","}}"]},configure:function(e){return e&&(this.config=utils.mergeObjects(this.config,e)),initTemplateTokenizer(this.config),initMacros(this.config),this}},eventHandlersAttributeName="b-on",nonInitializedElementAttributeName="b-init",selectorAttributeName="data-b-instance",templateLiteralsEnabled=function(){try{return eval("`x`"),!0}catch(e){return!1}}(),templateLiteral=templateLiteralsEnabled?"`":"'";function processVariable(e){var n,r,a=!0,i=[],t=e[0].split("|"),s=t[0].replace("$","");return t.shift(),t.length&&utils.each(t,function(e,t){n=t.split(":"),"noescape"!==(r=n[0]||null)?((i="string"==typeof n[1]?n[1].split(","):[]).unshift(s),s="_templateAdd(["+i+"], '"+r+"')"):a=!1}),a&&(s="_templateAdd("+s+")"),"_template += "+s+";"}function processMacro(e){var n,t=e[0],r=getMacros();return e.shift(),"string"==typeof r[t]?(n=r[t],utils.each(e,function(e,t){n=n.replace(new RegExp("#"+e),t)})):n=r[t](e),n}var variableMatchRegularExpression=/^\$/;function compileTemplate(n,e){var r,a,i="var _template = '';"+_templateAdd.toString()+";";return utils.each(n.text,function(e,t){if(i+="_template += _templateAdd("+templateLiteral+t+templateLiteral+");",e in n.macros)if(r=n.macros[e],(a=r[0]).match(variableMatchRegularExpression))i+=processVariable(r);else{if(!(a in getMacros()))throw'Unknown token: "'+a+'"';i+=processMacro(r)}}),i+="return _template;",new Function(e.join(","),i)}function _templateAdd(e,t){return _runtime.templateAdd(e,t)}var filters={};function addFilter(e,t){if(getFilter(e,!1))throw new Error('Brackets: Filter "'+e+'" is already defined.');return filters[e]=t,Brackets}function getFilter(e,t){if(!1!==t&&!(e in filters))throw new Error('Brackets: Filter "'+e+'" not found.');return filters[e]||null}function getFilters(){return filters}function bindPropertyDescriptors(n){utils.each(n.data,function(t,e){t in n._data||(n._data[t]=e,Object.defineProperty(n.data,t,{get:function(){return n._data[t]},set:function(e){n._data[t]=e,n._redrawingEnabled&&redrawInstance(n.instanceId)}}))})}addFilter("escape",function(e){var t={'"':""","&":"&","'":"'","/":"/","<":"<","=":"=",">":">","`":"`"};return String(e).replace(/[&<>"'`=/]/g,function(e){return t[e]})});var renderingInstances={},renderingInstancesStatuses={bindingEventHandlers:"bindingEventHandlers",create:"create",destroy:"destroy",pending:"pending",redrawing:"redrawing",renderingToString:"renderingToString",renderingToStringDone:"renderToStringDone",redrawingDone:"redrawingDone"};function getRenderingInstances(n){if(!n)return renderingInstances;var r={};return utils.each(renderingInstances,function(e,t){t._type===n&&(r[e]=t)}),r}function getRenderingInstance(e,t){if(!1!==t&&!(e in renderingInstances))throw new Error('Brackets: Rendering instance "'+e+'" not found.');return renderingInstances[e]||null}function createRenderingInstanceObject(t,e){"function"==typeof(t=utils.cloneObject(t)).template&&(t.template=t.template.call(t));var n={afterRender:function(e){t.afterRender&&(this._redrawingEnabled=!1,t.afterRender.call(this,e),this._redrawingEnabled=!0)},beforeRender:function(e){t.beforeRender&&(this._redrawingEnabled=!1,t.beforeRender.call(this,e),this._redrawingEnabled=!0)},cacheKey:t.cacheKey||null,data:t.data?utils.cloneObject(t.data):{},methods:t.methods||{},onStatusChange:t.onStatusChange||function(){},resultCacheEnabled:t.resultCacheEnabled||!1,template:t.template,addData:function(e,t){this.data[e]=t,bindPropertyDescriptors(this)},_create:function(){return this._setStatus(renderingInstancesStatuses.create),renderingInstances[this.instanceId]=this},_data:{},_destroy:function(){this._setStatus(renderingInstancesStatuses.destroy),delete renderingInstances[this.instanceId]},_hash:utils.generateHash(),_type:t._type||"view",_parent:null,_redrawingEnabled:!0,_status:renderingInstancesStatuses.pending,_setStatus:function(e){this._status!==e&&(this._status=e,this.onStatusChange.call(this,e))},set instanceId(e){this._instanceId=e},get instanceId(){return this._instanceId?this._instanceId+"-"+this._hash:this._hash},get el(){return"["+selectorAttributeName+'="'+this.instanceId+'"]'}};if(n.instanceId=t.instanceId||null,e&&!e.getAttribute(selectorAttributeName)&&e.setAttribute(selectorAttributeName,n.instanceId),!t.template&&e)n.template=e.innerHTML;else if(t.template&&t.template.match(/^#\S+/)){var r=document.querySelector(t.template);r&&(n.template=r.innerHTML)}else if(!t.template&&!e)throw new Error("Brackets: No template or target element provided for rendering.");if(bindPropertyDescriptors(n),getRenderingInstance(n.instanceId,!1))throw new Error('Brackets: Rendering instance "'+n.instanceId+'" is already defined.');return n._create()}var components={register:{},renderToString:renderComponent};function renderComponent(e,t){var n=getComponent(e);t&&utils.each(t,function(e,t){n.addData(e,t)}),n._setStatus(renderingInstancesStatuses.redrawing),n.beforeRender(),n._parent=this.parentInstance;var r=renderToString(n),a=[n.instanceId].concat(r.templateRuntime.renderedComponents);return this.renderedComponents=this.renderedComponents.concat(a),r.templateString}function addComponent(e,t){if(getComponent(e,!1))throw new Error('Brackets: Component "'+e+'" is already defined.');return t._type="component",components.register[e]=t,Brackets}function getComponent(e,t){if(e in components.register)return createRenderingInstanceObject(utils.cloneObject(components.register[e]));if(!1!==t)throw new Error('Brackets: Component "'+e+'" not found.');return null}function getComponents(){return components}var cacheManager={cache:{},getCache:function(e,t){return cacheManager.hasCache(e,t)?cacheManager.cache[e][t]:null},setCache:function(e,t,n){return cacheManager.hasCacheRegion(e)||(cacheManager.cache[e]={}),cacheManager.hasCache(e,t)||(cacheManager.cache[e][t]=n),cacheManager},hasCacheRegion:function(e){return e in cacheManager.cache},hasCache:function(e,t){return!!cacheManager.hasCacheRegion(e)&&t in cacheManager.cache[e]}},TEMPLATE_FUNCTIONS_CACHE_REGION="templateFunctions",TEMPLATE_RESULTS_CACHE_REGION="templateResults";function renderToString(e){e._setStatus(renderingInstancesStatuses.renderingToString);var t=e.resultCacheEnabled?cacheManager.getCache(TEMPLATE_RESULTS_CACHE_REGION,e._hash):null;return t||(t=generateTemplateString(e)),e._setStatus(renderingInstancesStatuses.renderingToStringDone),t}function generateTemplateString(e){var t="string"==typeof e.cacheKey,n=t?cacheManager.getCache(TEMPLATE_FUNCTIONS_CACHE_REGION,e.cacheKey):null,r=e.data,a={parentInstance:e.instanceId,components:getComponents(),getFilter:getFilter,renderedComponents:[],utils:utils,templateAdd:function(e,t){return void 0===e?"":(Array.isArray(e)||(e=[e]),(t=!0===(t=!1===t?null:t)?"escape":t)?this.getFilter(t).apply(null,e):e)}},i=e.template,s=[a];n||(templateLiteralsEnabled||(i=(i=i.replace(/(?:\r\n|\r|\n)/g," ")).replace(/'/g,"'")),n=compileTemplate(tokenizeTemplate(i),["_runtime"].concat(Object.keys(r))),t&&cacheManager.setCache(TEMPLATE_FUNCTIONS_CACHE_REGION,e.cacheKey,n));utils.each(r,function(e,t){s.push(t)});var c=n.apply(null,s);if("component"===e._type){c=c.replace(new RegExp(eventHandlersAttributeName+"=","g"),eventHandlersAttributeName+"-"+e._hash+"=");var o=(new DOMParser).parseFromString(c,"text/html").querySelector("body *");o&&(o.setAttribute(selectorAttributeName,e.instanceId),c=o.outerHTML)}return e.resultCacheEnabled&&cacheManager.setCache(TEMPLATE_RESULTS_CACHE_REGION,e._hash,{templateString:c,templateRuntime:a}),{templateString:c,templateRuntime:a}}function bindEventHandlers(o){o._setStatus(renderingInstancesStatuses.bindingEventHandlers);var e=document.querySelector(o.el);if(e){var t="component"===o._type?"-"+o._hash:"",r=eventHandlersAttributeName+t,n="["+r+"]",a=[];utils.each(e.querySelectorAll(n),function(e,t){a.push(t)}),e.getAttribute(r)&&a.push(e),utils.each(a,function(e,n){var t=n.getAttribute(r).split(";");utils.each(t,function(e,t){!function(e,t){var n,r=(t=t.trim()).match(/^(\S+)/)[1],a=[];if((t=t.replace(r+" ","")).match(/\S+\(.*\)$/)){var i=t.match(/^([^(]+)\((.*)\)/),s=i[1],c=i[2];if(!o.methods||!o.methods[s])throw new Error('Brackets: Method "'+s+'" is not defined.');n=o.methods[s],a=[c]}else n=new Function("data","this."+t+"; return this;");e.addEventListener(r,function(e){n.apply(o.data,[e].concat(a))})}(n,t)}),Brackets.config.devMode||n.removeAttribute(r)})}}function redrawInstance(e){var t=getRenderingInstance(e,!1);if(t){var r=document.querySelector(t.el);if(r){t._setStatus(renderingInstancesStatuses.redrawing),utils.each(r.querySelectorAll("["+selectorAttributeName+"]"),function(e,t){getRenderingInstance(t.getAttribute(selectorAttributeName))._destroy()}),t.beforeRender(r);var n=renderToString(t),a=(new DOMParser).parseFromString(n.templateString,"text/html").querySelector(t.el);a&&(n.templateString=a.innerHTML),r.innerHTML=n.templateString,utils.each(n.templateRuntime.renderedComponents,function(e,t){var n=getRenderingInstance(t);bindEventHandlers(n),"function"==typeof n.afterRender&&n.afterRender.call(n,r),n._setStatus(renderingInstancesStatuses.redrawingDone)}),bindEventHandlers(t),r.removeAttribute(nonInitializedElementAttributeName),t.afterRender(r),t._setStatus(renderingInstancesStatuses.redrawingDone)}}}function render(n){var e;if("string"==typeof n.el)e=document.querySelectorAll(n.el);else if(n.el instanceof Element)e=[n.el];else{if(!(n.el instanceof NodeList||Array.isArray(n.el)))throw new Error("Brackets: unsupported type for parameter el.");e=n.el}if(1<e.length&&n.cacheKey&&!n.template)throw new Error("Brackets: you must provide a single template for '"+n.cacheKey+"' cacheKey because multiple target elements were found.");if(e)return utils.each(e,function(e,t){redrawInstance(createRenderingInstanceObject(n,t).instanceId)}),Brackets}Brackets.utils=utils,Brackets.cacheManager=cacheManager,Brackets.templateLiteral=templateLiteral,Brackets.addFilter=addFilter,Brackets.getFilter=getFilter,Brackets.getFilters=getFilters,Brackets.addComponent=addComponent,Brackets.getComponents=getComponents,Brackets.addMacro=addMacro,Brackets.getMacros=getMacros,Brackets.getRenderingInstance=getRenderingInstance,Brackets.getRenderingInstances=getRenderingInstances,Brackets.renderingInstancesStatuses=renderingInstancesStatuses,Brackets.render=render,Brackets.renderToString=function(e){return renderToString(createRenderingInstanceObject(e))},Brackets.configure(),"undefined"!=typeof window&&void 0===window.Brackets?window.Brackets=Brackets:"object"==typeof module&&"object"==typeof module.exports&&(module.exports=Brackets)});