/* ***************************************************************************** This is the oficial version of ezBindings library included in class/item pages ***************************************************************************** */ // main object definition... const EZ_BINDINGS = { name: "ezBindings", version: "v1.0", // this map that stores template's initial data, controller and processed HTML... // the key is the template name... tmpls: [], // enable/disable DEBUG logging... debugIn: false, debug: function(msg) { if(this.debugIn) { console.log(msg); } }, // directives definitions... directives: { TMPL: "ezb-tmpl", DATA: "ezb-data", CTRL: "ezb-ctrl", REPEAT: "ezb-repeat" }, // register template's data and controller... register: function(tmplName, tmplData, tmplCtrl) { // instrument the data, by default the template will be shown after processing... tmplData.showTemplateAfterProcessing = true; // create the template object by storing the initial data... this.tmpls[tmplName] = { data: tmplData }; // add controller's reference if any provided... if(tmplCtrl) { this.tmpls[tmplName].controller = tmplCtrl; } }, // remove template from document... remove: function(tmplName) { var _tmpl = document.querySelector("[" + this.directives.TMPL + "=" + tmplName + "]"); if(_tmpl != null) { _tmpl.remove(); } }, // disable template from document (works only before initial processing)... disable: function(tmplName) { var _tmpl = document.querySelector("[" + this.directives.TMPL + "=" + tmplName + "]"); if(_tmpl != null) { _tmpl.removeAttributeNode(_tmpl.getAttributeNode(this.directives.TMPL)); _tmpl.setAttribute(this.directives.TMPL + "-disabled", tmplName); } } }; // just an alias... const $ezb = EZ_BINDINGS; function _ezBindingsGetRepeatHTML(html) { var ret = html; var indexStart = html.indexOf(EZ_BINDINGS.directives.REPEAT + "=\""); var indexEnd = html.indexOf("\"", indexStart + 12); ret = html.substring(0, indexStart - 1) + html.substring(indexEnd + 1, html.length); return ret; } function _ezBindingsProcessRepeats(tmpl) { var _name = tmpl.getAttribute(EZ_BINDINGS.directives.TMPL); // get repeat templates part of this overall template... // SAMPLE: document.querySelectorAll("[ezb-tmpl=MySecondTemplate] [ezb-repeat]"); var _ezRepeats = document.querySelectorAll( "[" + EZ_BINDINGS.directives.TMPL + "=" + _name + "] [" + EZ_BINDINGS.directives.REPEAT + "]" ); EZ_BINDINGS.debug(` REPEAT templates length = ${_ezRepeats.length}`); // get template's HTML code... _tmplHTML = tmpl.innerHTML; // iterate through all repeat templates and generate complete HTML code... var _ctrls = null; var _var = ""; var _data = ""; var _arr = null; var _html = ""; var _htmlRepeatTemp = ""; for (var i = 0; i < _ezRepeats.length; i++) { EZ_BINDINGS.debug(` REPEAT template found: ${_ezRepeats[i]}`); // get basic HTML from the repeat template... _htmlRepeat = _ezBindingsGetRepeatHTML(_ezRepeats[i].outerHTML); // get iteration control items... _ctrls = _ezRepeats[i].getAttribute(EZ_BINDINGS.directives.REPEAT).split(" "); _var = _ctrls[0]; _data = _ctrls[2]; EZ_BINDINGS.debug(` controls: var = ${_var} data = ${_data}`); // build the HTML code from the repeat template by iterating through the original data array... _html = ""; eval("_arr = EZ_BINDINGS.tmpls[tmpl.getAttribute(EZ_BINDINGS.directives.TMPL)].data." + _data); if(_arr != null) { for(var j = 0; j < _arr.length; j++) { // replace variables as objects... _htmlRepeatTemp = _htmlRepeat.replaceAll("[{" + _var + "}]", "EZ_BINDINGS.tmpls['" + _name + "'].data." + _data + "[" + j + "]"); // replace variables as values... _html += _htmlRepeatTemp.replaceAll("[[" + _var, "[[" + _data + "[" + j + "]"); } } EZ_BINDINGS.debug(` generated HTML: ${_html}`); // replace the original repeat template with the generated HTML code in the overall template's HTML... _tmplHTML = _tmplHTML.replaceAll(_ezRepeats[i].outerHTML, _html); } // store the new full generated HTML in the original template... tmpl.innerHTML = _tmplHTML; // store the template's content... EZ_BINDINGS.tmpls[_name].html = tmpl.innerHTML; } function _ezBindingsReplaceVariablesAsObjects(tmpl) { var _name = tmpl.getAttribute(EZ_BINDINGS.directives.TMPL); // get template's HTML code with variables only in it... var _html = EZ_BINDINGS.tmpls[_name].html; var _param = EZ_BINDINGS.tmpls[_name].data; // get all variables... "[[variable_name_here]]" ... var _matches = _html.matchAll(/\[\{[\[\]\.\_a-zA-Z0-9]*\}\]/g); // iterate through template's all variables... for(var _match of _matches) { EZ_BINDINGS.debug(` object variable found: ${_match[0]}`); // replace variable with actual value... _html = _html.replaceAll( "[{" + _match[0].substring(2, _match[0].length - 2) + "}]", "EZ_BINDINGS.tmpls['" + _name + "'].data." + _match[0].substring(2, _match[0].length - 2) ); } // set new template's HTML code... tmpl.innerHTML = _html; // store the template's content... EZ_BINDINGS.tmpls[_name].html = tmpl.innerHTML; } function _ezBindingsReplaceVariablesAsValues(tmpl) { var _name = tmpl.getAttribute(EZ_BINDINGS.directives.TMPL); // get template's HTML code with variables only in it... var _html = EZ_BINDINGS.tmpls[_name].html; var _param = EZ_BINDINGS.tmpls[_name].data; // get all variables... "[[variable_name_here]]" ... var _matches = _html.matchAll(/\[\[[\[\]\.\_a-zA-Z0-9]*\]\]/g); // iterate through template's all variables... for(var _match of _matches) { EZ_BINDINGS.debug(` value variable found: ${_match[0]}`); // replace variable with actual value... _html = _html.replaceAll( "[[" + _match[0].substring(2, _match[0].length - 2) + "]]", eval("_param." + _match[0].substring(2, _match[0].length - 2)) ); } // set new template's HTML code... tmpl.innerHTML = _html; // store the template's content... EZ_BINDINGS.tmpls[_name].html = tmpl.innerHTML; } function _ezBindingsRunController(tmpl) { // template's name... var _name = tmpl.getAttribute(EZ_BINDINGS.directives.TMPL); // get template's data... _param = EZ_BINDINGS.tmpls[_name].data; // run template's controller if any provided... if(EZ_BINDINGS.tmpls[_name].controller != null) { // if controller provided as string then transform it into the corresponding object... if((typeof EZ_BINDINGS.tmpls[_name].controller) == "string") { eval("EZ_BINDINGS.tmpls['" + _name + "'].controller = " + EZ_BINDINGS.tmpls[_name].controller); } // run the actual controller initializer... EZ_BINDINGS.tmpls[_name].controller.initialize(EZ_BINDINGS.tmpls[_name].data); // replace the alias with the actual controller... if(EZ_BINDINGS.tmpls[_name].controller.alias != null) { // replace controller alias in the original template... tmpl.innerHTML = tmpl.innerHTML.replaceAll(EZ_BINDINGS.tmpls[_name].controller.alias + ".", "EZ_BINDINGS.tmpls['" + _name + "'].controller."); } } } function _ezBindingsProcessTemplate(tmpl) { // process template's repeats... _ezBindingsProcessRepeats(tmpl); // replace all object variables in the template... _ezBindingsReplaceVariablesAsObjects(tmpl); // replace all value variables in the template... _ezBindingsReplaceVariablesAsValues(tmpl); } function _ezBindingsRegisterTemplate(tmpl) { // template's name... var _name = tmpl.getAttribute(EZ_BINDINGS.directives.TMPL); var _data = null; var _ctrl = null; if(EZ_BINDINGS.tmpls[_name] == null) { // get template's data... eval("_data = " + tmpl.getAttribute(EZ_BINDINGS.directives.DATA)); // if no data provided then just create an empty one... if(_data == null) { _data = {}; } // instrument the data, by default the template will be shown after processing... _data.showTemplateAfterProcessing = true; // create the template object by storing the initial data... EZ_BINDINGS.tmpls[_name] = { data: _data }; // get template's controller... eval("_ctrl = " + tmpl.getAttribute(EZ_BINDINGS.directives.CTRL)); if(_ctrl != null) { EZ_BINDINGS.tmpls[_name].controller = _ctrl; } } else { // template was manually registered using the "$ezb.register" function, nothing to do in this case... } } function _ezBindingsProcess() { // get all templates from the raw page's html... var _ezTmpls = document.querySelectorAll("[" + EZ_BINDINGS.directives.TMPL + "]"); // iterate through and process each template... var _name = ""; for (var i = 0; i < _ezTmpls.length; i++) { // get the template's name... _name = _ezTmpls[i].getAttribute(EZ_BINDINGS.directives.TMPL); EZ_BINDINGS.debug(`[${EZ_BINDINGS.name}] template found: ${_name}`); // register template if not already registered... _ezBindingsRegisterTemplate(_ezTmpls[i]); // store/save the original template's HTML... EZ_BINDINGS.tmpls[_name].template = _ezTmpls[i].innerHTML; // run template's controller... _ezBindingsRunController(_ezTmpls[i]); // process template... _ezBindingsProcessTemplate(_ezTmpls[i]); // show template... if(EZ_BINDINGS.tmpls[_name].data.showTemplateAfterProcessing) { _ezTmpls[i].classList.remove("w3-hide"); } } } window.onload = function() { _ezBindingsProcess(); }