stylus/localization.js
tophf a889ac6413 templates: compress inter-tag whitespace
to reduce number of DOM nodes by 25%
2017-04-18 12:46:32 +03:00

95 lines
2.3 KiB
JavaScript

'use strict';
const template = {};
tDocLoader();
function t(key, params) {
const s = chrome.i18n.getMessage(key, params);
if (s == '') {
throw `Missing string "${key}"`;
}
return s;
}
function tE(id, key, attr, esc) {
if (attr) {
document.getElementById(id).setAttribute(attr, t(key));
} else if (typeof esc == 'undefined' || esc) {
document.getElementById(id).appendChild(document.createTextNode(t(key)));
} else {
document.getElementById(id).innerHTML = t(key);
}
}
function tHTML(html) {
const node = document.createElement('div');
node.innerHTML = html.replace(/>\s+</g, '><'); // spaces are removed; use &nbsp; for an explicit space
if (html.includes('i18n-')) {
tNodeList(node.querySelectorAll('*'));
}
return node.firstElementChild;
}
function tNodeList(nodes) {
for (const node of [...nodes]) {
// skip non-ELEMENT_NODE
if (node.nodeType != 1) {
continue;
}
if (node.localName == 'template') {
// compress inter-tag whitespace to reduce number of DOM nodes by 25%
template[node.dataset.id] = tHTML(node.innerHTML);
continue;
}
for (const attr of [...node.attributes]) {
let name = attr.nodeName;
if (name.indexOf('i18n-') != 0) {
continue;
}
name = name.substr(5); // 'i18n-'.length
const value = t(attr.value);
switch (name) {
case 'text':
node.insertBefore(document.createTextNode(value), node.firstChild);
break;
case 'html':
node.insertAdjacentHTML('afterbegin', value);
break;
default:
node.setAttribute(name, value);
}
node.removeAttribute(attr.nodeName);
}
}
}
function tDocLoader() {
// localize HEAD
tNodeList(document.all);
// localize BODY
const observer = new MutationObserver(mutations => {
for (const mutation of mutations) {
tNodeList(mutation.addedNodes);
}
});
const onLoad = () => {
tDocLoader.stop();
tNodeList(document.all);
};
tDocLoader.start = () => {
observer.observe(document, {subtree: true, childList: true});
};
tDocLoader.stop = () => {
observer.disconnect();
document.removeEventListener('DOMContentLoaded', onLoad);
};
tDocLoader.start();
document.addEventListener('DOMContentLoaded', onLoad);
}