VulpesOS/gaia/shared/js/contacts/utilities/templates.js
OverSu b38dea0597 Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
2026-09-30 23:13:03 +02:00

261 lines
7.1 KiB
JavaScript
Executable file

'use strict';
var utils = window.utils || {};
if (!utils.templates) {
(function() {
var Templates = utils.templates = {};
/**
* Returns a target HTMLElement from a selector or HTMLElement itself
*
* @param {HTMLElement or Selector} element target element.
*
* @return {HTMLElement} HTMLElement according to the selector or itself.
*
*
*/
function getTarget(element) {
var target = element;
if (!element.tagName) {
target = document.querySelector(element);
}
return target;
}
/**
* Given a target HTML element which contains a template set
* returns the template that will have to be applied over the data
*
* @param {HTMLElement} target which contains the template.
* @param {Object} data to be used on the template.
*
* @return {HTMLElement} HTMLElement with the template.
*
*/
function getTemplate(target, data) {
// Multi templates temporarily disabled to avoid eval usage
// TODO: Implement an alternative for eval
var templates = target.querySelectorAll('*[data-template]');
if (templates.length === 0) {
throw new Error('No template declared');
}
if (templates.length > 1 && templates.item(0).dataset.condition) {
throw new Error('Only one template supported in this version');
}
return {
template: templates.item(0),
isMulti: false
};
}
/**
* Returns a function used to replace data on a template
*
* @param {Object} data the data to be used on the template.
*
* @return {function} to be used.
*
*/
function templateReplace(data) {
return function(text, property) {
var out;
if (property.indexOf('.') === -1) {
out = data[property];
if (Array.isArray(out) && out.length > 0) {
out = out[0];
}
} else {
throw new Error('Dotted expressions not supported');
}
if (typeof out === 'undefined') {
out = text;
}
return out;
};
}
/**
* Adds (append or prepend) a new instance HTMLElement (or array of)
* of a template
* The template is assumed to be a child of the element
* passed as parameter
* The new element will be appended as a child
*
* @param {HTMLElement} ele container lement that contains the template
* and which will contain the new instance. Can be an HTMLElement
* or a CSS selector.
*
* @param {object or array} data with the data displayed by the template.
*
* @param {String} mode oneOf ('A','P').
*
* @return {HTMLElement} (or last element if data is an array).
*
*
*/
function add(element, data, mode, targetNode) {
// It is supported both the element itself or a selector
var target = getTarget(element);
var newElem;
var theData = [data];
if (data instanceof Array) {
theData = data;
}
// Optimization to avoid trying to find a template when
// only one is needed
var multiTemplate = true;
var template;
var idx = 0;
theData.forEach(function(oneData) {
// Pseudo-field with the index
oneData._idx_ = idx++;
// A suitable template for the data is firstly found
if (multiTemplate === true) {
var tresult = getTemplate(target, oneData);
template = tresult.template;
if (tresult.isMulti === false) {
multiTemplate = false;
}
}
if (template) {
newElem = this.render(template, oneData);
target = targetNode || target;
if (mode === 'A') {
target.appendChild(newElem);
} else if (mode === 'P') { // Append mode
if (target.firstChild) {
target.insertBefore(newElem, element.firstChild);
} else {
target.appendChild(newElem);
}
} // prepend mode
} // if template
}.bind(Templates)); // forEach data
return newElem;
}
/**
* Appends a new instance HTMLElement (or array of) of a template
*
* The template is assumed to be a child of the element passed
* as parameter
* The new element will be appended as a child
*
* @param {HTMLElement or String} ele container element that
* contains the template and which will contain the new instance.
* Can be an HTMLElement or a CSS selector.
*
* @param {object or array} data with the data displayed by the template.
*
* @return {HTMLelement} (or last element if data is an array).
*
*
*/
Templates.append = function(element, data, targetNode) {
var f = add.bind(this);
return f(element, data, 'A', targetNode);
};
/**
* Prepends a new instance (or array of) of a template
*
* The template is assumed to be a child of the element passed
* as parameter
*
* @param {HTMLElement or String} ele container element that
* contains the template and which will contain the new instance.
* Can be an HTMLElement or a CSS selector.
*
* @param {Object or Array} data with the data displayed.
*
* @return {HTMLElement} added.
*
*
*/
Templates.prepend = function(element, data, targetNode) {
var f = add.bind(this);
return f(element, data, 'P', targetNode);
};
/**
* Renders the content specified by a template with object data
*
* @param {HTMLElement} eleTemplate the template itself.
* @param {Object} data the data to be used.
*
* @return {HTMLElement} according to the template and with the data.
*
*
*/
Templates.render = function(eleTemplate, data) {
var newElem = eleTemplate.cloneNode(true);
newElem.removeAttribute('data-template');
newElem.removeAttribute('data-condition');
/* var pattern = /#(\w+)#/g; */
var pattern = /#(\w+[\w.]*)#/g;
var inner = newElem.innerHTML;
// Replace function
var replaceFunction = templateReplace(data);
var ninner = inner.replace(pattern, replaceFunction);
newElem.innerHTML = ninner;
var attrs = newElem.attributes;
var total = attrs.length;
for (var c = 0; c < total; c++) {
var val = attrs[c].value;
var nval = val.replace(pattern, replaceFunction);
newElem.setAttribute(attrs[c].name, nval);
}
if (!newElem.id) {
if (data.id) {
newElem.id = data.id;
}
}
return newElem;
};
/**
* Clears a container element
*
* @param {HTMLElement or String} element (selector or HTML element).
*
*
*/
Templates.clear = function(element) {
var target = getTarget(element);
var templates = target.querySelectorAll('*[data-template]');
target.innerHTML = '';
var total = templates.length;
for (var c = 0; c < total; c++) {
target.appendChild(templates.item(c));
}
};
}) ();
} // window.templates