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.
This commit is contained in:
parent
93e3a48004
commit
b38dea0597
25901 changed files with 9982925 additions and 369 deletions
261
gaia/shared/js/contacts/utilities/templates.js
Executable file
261
gaia/shared/js/contacts/utilities/templates.js
Executable file
|
|
@ -0,0 +1,261 @@
|
|||
'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
|
||||
Loading…
Reference in a new issue