simplify localization

This commit is contained in:
tophf 2020-11-16 00:47:46 +03:00
parent 151805f1bb
commit b8322ecf01
13 changed files with 284 additions and 223 deletions

View File

@ -1,4 +1,10 @@
/* global CodeMirror prefs editor $ template */ /* global
$
CodeMirror
editor
prefs
t
*/
'use strict'; 'use strict';
@ -183,7 +189,7 @@
// setTimeout(() => { // setTimeout(() => {
// $('.CodeMirror-dialog', section).focus(); // $('.CodeMirror-dialog', section).focus();
// }); // });
cm.openDialog(template.jumpToLine.cloneNode(true), str => { cm.openDialog(t.template.jumpToLine.cloneNode(true), str => {
const m = str.match(/^\s*(\d+)(?:\s*:\s*(\d+))?\s*$/); const m = str.match(/^\s*(\d+)(?:\s*:\s*(\d+))?\s*$/);
if (m) { if (m) {
cm.setCursor(m[1] - 1, m[2] ? m[2] - 1 : cur.ch); cm.setCursor(m[1] - 1, m[2] ? m[2] - 1 : cur.ch);

View File

@ -26,7 +26,6 @@
setupLivePrefs setupLivePrefs
SourceEditor SourceEditor
t t
tHTML
tryCatch tryCatch
tryJSONparse tryJSONparse
*/ */
@ -449,7 +448,7 @@ function showHelp(title = '', body) {
const contents = $('.contents', div); const contents = $('.contents', div);
contents.textContent = ''; contents.textContent = '';
if (body) { if (body) {
contents.appendChild(typeof body === 'string' ? tHTML(body) : body); contents.appendChild(typeof body === 'string' ? t.HTML(body) : body);
} }
$('.title', div).textContent = title; $('.title', div).textContent = title;

View File

@ -1,5 +1,18 @@
/* global CodeMirror focusAccessibility colorMimicry editor chromeLocal /* global
onDOMready $ $$ $create t debounce tryRegExp stringAsRegExp template */ $
$$
$create
chromeLocal
CodeMirror
colorMimicry
debounce
editor
focusAccessibility
onDOMready
stringAsRegExp
t
tryRegExp
*/
'use strict'; 'use strict';
onDOMready().then(() => { onDOMready().then(() => {
@ -563,14 +576,14 @@ onDOMready().then(() => {
state.originalFocus = document.activeElement; state.originalFocus = document.activeElement;
state.firstRun = true; state.firstRun = true;
const dialog = state.dialog = template.searchReplaceDialog.cloneNode(true); const dialog = state.dialog = t.template.searchReplaceDialog.cloneNode(true);
Object.assign(dialog, DIALOG_PROPS.dialog); Object.assign(dialog, DIALOG_PROPS.dialog);
dialog.addEventListener('focusout', EVENTS.onfocusout); dialog.addEventListener('focusout', EVENTS.onfocusout);
dialog.dataset.type = type; dialog.dataset.type = type;
dialog.style.pointerEvents = 'auto'; dialog.style.pointerEvents = 'auto';
const content = $('[data-type="content"]', dialog); const content = $('[data-type="content"]', dialog);
content.parentNode.replaceChild(template[type].cloneNode(true), content); content.parentNode.replaceChild(t.template[type].cloneNode(true), content);
createInput(0, 'input', state.find); createInput(0, 'input', state.find);
createInput(1, 'input2', state.replace); createInput(1, 'input2', state.replace);
@ -633,7 +646,7 @@ onDOMready().then(() => {
input.value = value; input.value = value;
Object.assign(input, DIALOG_PROPS[name]); Object.assign(input, DIALOG_PROPS[name]);
input.parentElement.appendChild(template.clearSearch.cloneNode(true)); input.parentElement.appendChild(t.template.clearSearch.cloneNode(true));
$('[data-action]', input.parentElement)._input = input; $('[data-action]', input.parentElement)._input = input;
} }

View File

@ -9,7 +9,6 @@
prefs prefs
regExpTester regExpTester
t t
template
tryCatch tryCatch
*/ */
'use strict'; 'use strict';
@ -55,7 +54,7 @@ function MozSectionWidget(
$create('ul' + C_LIST), $create('ul' + C_LIST),
]), ]),
listItem: listItem:
template.appliesTo.cloneNode(true), t.template.appliesTo.cloneNode(true),
appliesToEverything: appliesToEverything:
$create('li.applies-to-everything', t('appliesToEverything')), $create('li.applies-to-everything', t('appliesToEverything')),
}; };

View File

@ -1,4 +1,12 @@
/* global showHelp $ $create tryRegExp URLS t template openURL */ /* global
$
$create
openURL
showHelp
t
tryRegExp
URLS
*/
/* exported regExpTester */ /* exported regExpTester */
'use strict'; 'use strict';
@ -86,7 +94,7 @@ const regExpTester = (() => {
full: {data: [], label: t('styleRegexpTestFull')}, full: {data: [], label: t('styleRegexpTestFull')},
partial: {data: [], label: [ partial: {data: [], label: [
t('styleRegexpTestPartial'), t('styleRegexpTestPartial'),
template.regexpTestPartial.cloneNode(true), t.template.regexpTestPartial.cloneNode(true),
]}, ]},
none: {data: [], label: t('styleRegexpTestNone')}, none: {data: [], label: t('styleRegexpTestNone')},
invalid: {data: [], label: t('styleRegexpTestInvalid')}, invalid: {data: [], label: t('styleRegexpTestInvalid')},

View File

@ -9,7 +9,6 @@
prefs prefs
regExpTester regExpTester
t t
template
trimCommentLabel trimCommentLabel
tryRegExp tryRegExp
*/ */
@ -26,7 +25,7 @@
function createSection(originalSection, genId, si) { function createSection(originalSection, genId, si) {
const {dirty} = editor; const {dirty} = editor;
const sectionId = genId(); const sectionId = genId();
const el = template.section.cloneNode(true); const el = t.template.section.cloneNode(true);
const elLabel = $('.code-label', el); const elLabel = $('.code-label', el);
const cm = cmFactory.create(wrapper => { const cm = cmFactory.create(wrapper => {
// making it tall during initial load so IntersectionObserver sees only one adjacent CM // making it tall during initial load so IntersectionObserver sees only one adjacent CM
@ -265,8 +264,8 @@ function createSection(originalSection, genId, si) {
function createApply({type = 'url', value, all = false}) { function createApply({type = 'url', value, all = false}) {
const applyId = genId(); const applyId = genId();
const dirtyPrefix = `section.${sectionId}.apply.${applyId}`; const dirtyPrefix = `section.${sectionId}.apply.${applyId}`;
const el = all ? template.appliesToEverything.cloneNode(true) : const el = all ? t.template.appliesToEverything.cloneNode(true) :
template.appliesTo.cloneNode(true); t.template.appliesTo.cloneNode(true);
const selectEl = !all && $('.applies-type', el); const selectEl = !all && $('.applies-type', el);
if (selectEl) { if (selectEl) {
@ -359,7 +358,7 @@ function createSection(originalSection, genId, si) {
function createResizeGrip(cm) { function createResizeGrip(cm) {
const wrapper = cm.display.wrapper; const wrapper = cm.display.wrapper;
wrapper.classList.add('resize-grip-enabled'); wrapper.classList.add('resize-grip-enabled');
const resizeGrip = template.resizeGrip.cloneNode(true); const resizeGrip = t.template.resizeGrip.cloneNode(true);
wrapper.appendChild(resizeGrip); wrapper.appendChild(resizeGrip);
let lastClickTime = 0; let lastClickTime = 0;
let initHeight; let initHeight;

View File

@ -1,5 +1,14 @@
/* global CodeMirror showHelp onDOMready $ $$ $create template t /* global
prefs stringAsRegExp */ $
$$
$create
CodeMirror
onDOMready
prefs
showHelp
stringAsRegExp
t
*/
'use strict'; 'use strict';
onDOMready().then(() => { onDOMready().then(() => {
@ -11,7 +20,7 @@ function showKeyMapHelp() {
const keyMapSorted = Object.keys(keyMap) const keyMapSorted = Object.keys(keyMap)
.map(key => ({key, cmd: keyMap[key]})) .map(key => ({key, cmd: keyMap[key]}))
.sort((a, b) => (a.cmd < b.cmd || (a.cmd === b.cmd && a.key < b.key) ? -1 : 1)); .sort((a, b) => (a.cmd < b.cmd || (a.cmd === b.cmd && a.key < b.key) ? -1 : 1));
const table = template.keymapHelp.cloneNode(true); const table = t.template.keymapHelp.cloneNode(true);
const tBody = table.tBodies[0]; const tBody = table.tBodies[0];
const row = tBody.rows[0]; const row = tBody.rows[0];
const cellA = row.children[0]; const cellA = row.children[0];

View File

@ -1,97 +1,90 @@
/* global tryCatch */
/* exported tHTML formatDate */
'use strict'; 'use strict';
const template = {};
tDocLoader();
function t(key, params) { function t(key, params) {
const s = chrome.i18n.getMessage(key, params); const s = chrome.i18n.getMessage(key, params);
if (!s) throw `Missing string "${key}"`; if (!s) throw `Missing string "${key}"`;
return s; return s;
} }
Object.assign(t, {
template: {},
DOMParser: new DOMParser(),
ALLOWED_TAGS: 'a,b,code,i,sub,sup,wbr'.split(','),
RX_WORD_BREAK: new RegExp([
'(',
/[\d\w\u007B-\uFFFF]{10}/,
'|',
/[\d\w\u007B-\uFFFF]{5,10}[!-/]/,
'|',
/((?!\s)\W){10}/,
')',
/(?!\b|\s|$)/,
].map(rx => rx.source || rx).join(''), 'g'),
function tHTML(html, tag) { HTML(html) {
// body is a text node without HTML tags return typeof html !== 'string'
if (typeof html === 'string' && !tag && /<\w+/.test(html) === false) { ? html
return document.createTextNode(html); : /<\w+/.test(html) // check for html tags
} ? t.createHtml(html.replace(/>\n\s*</g, '><').trim())
if (typeof html === 'string') { : document.createTextNode(html);
// spaces are removed; use &nbsp; for an explicit space },
html = html.replace(/>\s+</g, '><').trim();
if (tag) {
html = `<${tag}>${html}</${tag}>`;
}
const body = t.DOMParser.parseFromString(html, 'text/html').body;
if (html.includes('i18n-')) {
tNodeList(body.getElementsByTagName('*'));
}
// the html string may contain more than one top-level node
if (!body.childNodes[1]) {
return body.firstChild;
}
const fragment = document.createDocumentFragment();
while (body.firstChild) {
fragment.appendChild(body.firstChild);
}
return fragment;
}
return html;
}
NodeList(nodes) {
function tNodeList(nodes) { const PREFIX = 'i18n-';
const PREFIX = 'i18n-'; for (let n = nodes.length; --n >= 0;) {
const node = nodes[n];
for (let n = nodes.length; --n >= 0;) { if (node.nodeType !== Node.ELEMENT_NODE) {
const node = nodes[n];
if (node.nodeType !== Node.ELEMENT_NODE) {
continue;
}
if (node.localName === 'template') {
createTemplate(node);
continue;
}
for (let a = node.attributes.length; --a >= 0;) {
const attr = node.attributes[a];
const name = attr.nodeName;
if (!name.startsWith(PREFIX)) {
continue; continue;
} }
const type = name.substr(PREFIX.length); if (node.localName === 'template') {
const value = t(attr.value); t.createTemplate(node);
let toInsert, before; continue;
switch (type) { }
case 'word-break': for (let a = node.attributes.length; --a >= 0;) {
// we already know that: hasWordBreak const attr = node.attributes[a];
break; const name = attr.nodeName;
case 'text': if (!name.startsWith(PREFIX)) {
before = node.firstChild; continue;
// fallthrough to text-append
case 'text-append':
toInsert = createText(value);
break;
case 'html': {
toInsert = createHtml(value);
break;
} }
default: const type = name.substr(PREFIX.length);
node.setAttribute(type, value); const value = t(attr.value);
let toInsert, before;
switch (type) {
case 'word-break':
// we already know that: hasWordBreak
break;
case 'text':
before = node.firstChild;
// fallthrough to text-append
case 'text-append':
toInsert = t.createText(value);
break;
case 'html': {
toInsert = t.createHtml(value);
break;
}
default:
node.setAttribute(type, value);
}
t.stopObserver();
if (toInsert) {
node.insertBefore(toInsert, before || null);
}
node.removeAttribute(name);
} }
tDocLoader.pause();
if (toInsert) {
node.insertBefore(toInsert, before || null);
}
node.removeAttribute(name);
} }
} },
function createTemplate(node) { /** Adds soft hyphens every 10 characters to ensure the long words break before breaking the layout */
breakWord(text) {
return text.length <= 10 ? text :
text.replace(t.RX_WORD_BREAK, '$&\u00AD');
},
createTemplate(node) {
const elements = node.content.querySelectorAll('*'); const elements = node.content.querySelectorAll('*');
tNodeList(elements); t.NodeList(elements);
template[node.dataset.id] = elements[0]; t.template[node.dataset.id] = elements[0];
// compress inter-tag whitespace to reduce number of DOM nodes by 25% // compress inter-tag whitespace to reduce number of DOM nodes by 25%
const walker = document.createTreeWalker(elements[0], NodeFilter.SHOW_TEXT); const walker = document.createTreeWalker(elements[0], NodeFilter.SHOW_TEXT);
const toRemove = []; const toRemove = [];
@ -101,104 +94,96 @@ function tNodeList(nodes) {
toRemove.push(textNode); toRemove.push(textNode);
} }
} }
tDocLoader.pause(); t.stopObserver();
toRemove.forEach(el => el.remove()); toRemove.forEach(el => el.remove());
} },
function createText(str) { createText(str) {
return document.createTextNode(tWordBreak(str)); return document.createTextNode(t.breakWord(str));
} },
function createHtml(value) { createHtml(str, trusted) {
// <a> and <code> are the only acceptable HTML elements, const root = t.DOMParser.parseFromString(str, 'text/html').body;
// <a> also allows `href` attribute with an http/https URL if (!trusted) {
const rx = /(<)(a|code)(\s[^>]*|)>(.*?)<\/\2>/i; t.sanitizeHtml(root);
} else if (str.includes('i18n-')) {
t.NodeList(root.getElementsByTagName('*'));
}
const bin = document.createDocumentFragment(); const bin = document.createDocumentFragment();
for (let parts = value.split(rx), i = 0; i < parts.length; i++) { while (root.firstChild) {
const s = parts[i]; bin.appendChild(root.firstChild);
if (s === '<') {
const tag = parts[++i].toLowerCase();
const el = bin.appendChild(document.createElement(tag));
const attrs = parts[++i];
const href = tag === 'a' && /(?:^|\s)href\s*=\s*(["'])?(https?:\/\/\S*?)\1/i.exec(attrs);
if (href) el.href = href[2];
el.appendChild(createText(parts[++i]));
} else {
bin.appendChild(createText(s));
}
} }
return bin; return bin;
} },
}
sanitizeHtml(root) {
function tDocLoader() { const toRemove = [];
t.DOMParser = new DOMParser(); const walker = document.createTreeWalker(root);
t.RX_WORD_BREAK = new RegExp([ for (let n; (n = walker.nextNode());) {
'(', if (n.nodeType === Node.TEXT_NODE) {
/[\d\w\u007B-\uFFFF]{10}/, n.nodeValue = t.breakWord(n.nodeValue);
'|', } else if (t.ALLOWED_TAGS.includes(n.localName)) {
/[\d\w\u007B-\uFFFF]{5,10}[!-/]/, for (const attr of n.attributes) {
'|', if (n.localName !== 'a' || attr.localName !== 'href' || !/^https?:/.test(n.href)) {
/((?!\s)\W){10}/, n.removeAttribute(attr.name);
')', }
/(?!\b|\s|$)/, }
].map(rx => rx.source || rx).join(''), 'g'); } else {
toRemove.push(n);
Object.assign(tDocLoader, {
observer: new MutationObserver(process),
start() {
if (!tDocLoader.observing) {
tDocLoader.observing = true;
tDocLoader.observer.observe(document, {subtree: true, childList: true});
} }
}, }
stop() { for (const n of toRemove) {
tDocLoader.pause(); const parent = n.parentNode;
document.removeEventListener('DOMContentLoaded', onLoad); if (parent) parent.removeChild(n); // not using .remove() as there may be a non-element
}, }
pause() { },
if (tDocLoader.observing) {
tDocLoader.observing = false; formatDate(date) {
tDocLoader.observer.disconnect(); if (!date) {
return '';
}
try {
const newDate = new Date(Number(date) || date);
const string = newDate.toLocaleDateString([chrome.i18n.getUILanguage(), 'en'], {
day: '2-digit',
month: 'short',
year: newDate.getYear() === new Date().getYear() ? undefined : '2-digit',
});
return string === 'Invalid Date' ? '' : string;
} catch (e) {
return '';
}
},
});
(() => {
const observer = new MutationObserver(process);
let observing = false;
Object.assign(t, {
stopObserver() {
if (observing) {
observing = false;
observer.disconnect();
} }
}, },
}); });
document.addEventListener('DOMContentLoaded', () => {
process(observer.takeRecords());
t.stopObserver();
}, {once: true});
tNodeList(document.getElementsByTagName('*')); t.NodeList(document.getElementsByTagName('*'));
tDocLoader.start(); start();
document.addEventListener('DOMContentLoaded', onLoad);
function process(mutations) { function process(mutations) {
for (const mutation of mutations) { mutations.forEach(m => t.NodeList(m.addedNodes));
tNodeList(mutation.addedNodes); start();
}
function start() {
if (!observing) {
observing = true;
observer.observe(document, {subtree: true, childList: true});
} }
tDocLoader.start();
} }
})();
function onLoad() {
document.removeEventListener('DOMContentLoaded', onLoad);
process(tDocLoader.observer.takeRecords());
tDocLoader.stop();
}
}
function tWordBreak(text) {
// adds soft hyphens every 10 characters to ensure the long words break before breaking the layout
return text.length <= 10 ? text :
text.replace(t.RX_WORD_BREAK, '$&\u00AD');
}
function formatDate(date) {
return !date ? '' : tryCatch(() => {
const newDate = new Date(Number(date) || date);
const string = newDate.toLocaleDateString([t.cache.browserUIlanguage, 'en'], {
day: '2-digit',
month: 'short',
year: newDate.getYear() === new Date().getYear() ? undefined : '2-digit',
});
return string === 'Invalid Date' ? '' : string;
}) || '';
}

View File

@ -1,5 +1,15 @@
/* global messageBox deepCopy $create $createLink $ t tWordBreak /* global
prefs setupLivePrefs debounce API */ $
$create
$createLink
API
debounce
deepCopy
messageBox
prefs
setupLivePrefs
t
*/
/* exported configDialog */ /* exported configDialog */
'use strict'; 'use strict';
@ -305,7 +315,7 @@ function configDialog(style) {
elements.push( elements.push(
$create(`label.config-${va.type}`, [ $create(`label.config-${va.type}`, [
$create('span.config-name', tWordBreak(va.label)), $create('span.config-name', t.breakWord(va.label)),
...children, ...children,
resetter, resetter,
])); ]));

View File

@ -9,7 +9,6 @@
configDialog configDialog
debounce debounce
filterAndAppend filterAndAppend
formatDate
getOwnTab getOwnTab
getStyleWithNoCode getStyleWithNoCode
handleUpdateInstalled handleUpdateInstalled
@ -25,8 +24,6 @@
showFiltersStats showFiltersStats
sorter sorter
t t
template
tWordBreak
VIVALDI VIVALDI
*/ */
'use strict'; 'use strict';
@ -187,7 +184,7 @@ function showStyles(styles = [], matchUrlIds) {
function createStyleElement({style, name: nameLC}) { function createStyleElement({style, name: nameLC}) {
// query the sub-elements just once, then reuse the references // query the sub-elements just once, then reuse the references
if ((createStyleElement.parts || {}).newUI !== newUI.enabled) { if ((createStyleElement.parts || {}).newUI !== newUI.enabled) {
const entry = template[`style${newUI.enabled ? 'Compact' : ''}`]; const entry = t.template[`style${newUI.enabled ? 'Compact' : ''}`];
createStyleElement.parts = { createStyleElement.parts = {
newUI: newUI.enabled, newUI: newUI.enabled,
entry, entry,
@ -197,7 +194,7 @@ function createStyleElement({style, name: nameLC}) {
editLink: $('.style-edit-link', entry) || {}, editLink: $('.style-edit-link', entry) || {},
editHrefBase: 'edit.html?id=', editHrefBase: 'edit.html?id=',
homepage: $('.homepage', entry), homepage: $('.homepage', entry),
homepageIcon: template[`homepageIcon${newUI.enabled ? 'Small' : 'Big'}`], homepageIcon: t.template[`homepageIcon${newUI.enabled ? 'Small' : 'Big'}`],
appliesTo: $('.applies-to', entry), appliesTo: $('.applies-to', entry),
targets: $('.targets', entry), targets: $('.targets', entry),
expander: $('.expander', entry), expander: $('.expander', entry),
@ -215,7 +212,7 @@ function createStyleElement({style, name: nameLC}) {
const configurable = style.usercssData && style.usercssData.vars && Object.keys(style.usercssData.vars).length > 0; const configurable = style.usercssData && style.usercssData.vars && Object.keys(style.usercssData.vars).length > 0;
const name = style.customName || style.name; const name = style.customName || style.name;
parts.checker.checked = style.enabled; parts.checker.checked = style.enabled;
parts.nameLink.textContent = tWordBreak(name); parts.nameLink.textContent = t.breakWord(name);
parts.nameLink.href = parts.editLink.href = parts.editHrefBase + style.id; parts.nameLink.href = parts.editLink.href = parts.editHrefBase + style.id;
parts.homepage.href = parts.homepage.title = style.url || ''; parts.homepage.href = parts.homepage.title = style.url || '';
if (!newUI.enabled) { if (!newUI.enabled) {
@ -243,10 +240,10 @@ function createStyleElement({style, name: nameLC}) {
$('.homepage', entry).appendChild(parts.homepageIcon.cloneNode(true)); $('.homepage', entry).appendChild(parts.homepageIcon.cloneNode(true));
} }
if (style.updateUrl && newUI.enabled) { if (style.updateUrl && newUI.enabled) {
$('.actions', entry).appendChild(template.updaterIcons.cloneNode(true)); $('.actions', entry).appendChild(t.template.updaterIcons.cloneNode(true));
} }
if (configurable && newUI.enabled) { if (configurable && newUI.enabled) {
$('.actions', entry).appendChild(template.configureIcon.cloneNode(true)); $('.actions', entry).appendChild(t.template.configureIcon.cloneNode(true));
} }
createStyleTargetsElement({entry, style}); createStyleTargetsElement({entry, style});
@ -287,12 +284,12 @@ function createStyleTargetsElement({entry, expanded, style = entry.styleMeta}) {
el = next; el = next;
continue; continue;
} }
const element = template.appliesToTarget.cloneNode(true); const element = t.template.appliesToTarget.cloneNode(true);
if (!newUI.enabled) { if (!newUI.enabled) {
if (numTargets === maxTargets) { if (numTargets === maxTargets) {
container = container.appendChild(template.extraAppliesTo.cloneNode(true)); container = container.appendChild(t.template.extraAppliesTo.cloneNode(true));
} else if (numTargets > 0) { } else if (numTargets > 0) {
container.appendChild(template.appliesToSeparator.cloneNode(true)); container.appendChild(t.template.appliesToSeparator.cloneNode(true));
} }
} }
element.dataset.type = type; element.dataset.type = type;
@ -311,7 +308,7 @@ function createStyleTargetsElement({entry, expanded, style = entry.styleMeta}) {
if (entryTargets.firstElementChild) { if (entryTargets.firstElementChild) {
entryTargets.textContent = ''; entryTargets.textContent = '';
} }
entryTargets.appendChild(template.appliesToEverything.cloneNode(true)); entryTargets.appendChild(t.template.appliesToEverything.cloneNode(true));
} }
entry.classList.toggle('global', !numTargets); entry.classList.toggle('global', !numTargets);
entry._allTargetsRendered = allTargetsRendered; entry._allTargetsRendered = allTargetsRendered;
@ -525,7 +522,7 @@ Object.assign(handleEvent, {
{prop: 'installDate', name: 'dateInstalled'}, {prop: 'installDate', name: 'dateInstalled'},
{prop: 'updateDate', name: 'dateUpdated'}, {prop: 'updateDate', name: 'dateUpdated'},
].map(({prop, name}) => ].map(({prop, name}) =>
t(name) + ': ' + (formatDate(entry.styleMeta[prop]) || '—')).join('\n'); t(name) + ': ' + (t.formatDate(entry.styleMeta[prop]) || '—')).join('\n');
}, },
}); });

View File

@ -1,11 +1,18 @@
/* global focusAccessibility moveFocus $ $create t tHTML animateElement */ /* global
$
$create
animateElement
focusAccessibility
moveFocus
t
*/
'use strict'; 'use strict';
/** /**
* @param {Object} params * @param {Object} params
* @param {String} params.title * @param {String} params.title
* @param {String|Node|Object|Array<String|Node|Object>} params.contents * @param {String|Node|Object|Array<String|Node|Object>} params.contents
* a string gets parsed via tHTML, * a string gets parsed via t.HTML,
* a non-string is passed as is to $create() * a non-string is passed as is to $create()
* @param {String} [params.className] * @param {String} [params.className]
* CSS class name of the message box element * CSS class name of the message box element
@ -116,7 +123,7 @@ function messageBox({
$create('SVG:path', {d: 'M11.69,10l4.55,4.55-1.69,1.69L10,11.69,' + $create('SVG:path', {d: 'M11.69,10l4.55,4.55-1.69,1.69L10,11.69,' +
'5.45,16.23,3.77,14.55,8.31,10,3.77,5.45,5.45,3.77,10,8.31l4.55-4.55,1.69,1.69Z', '5.45,16.23,3.77,14.55,8.31,10,3.77,5.45,5.45,3.77,10,8.31l4.55-4.55,1.69,1.69Z',
}))), }))),
$create(`#${id}-contents`, tHTML(contents)), $create(`#${id}-contents`, t.HTML(contents)),
$create(`#${id}-buttons`, $create(`#${id}-buttons`,
buttons.map((content, buttonIndex) => content && buttons.map((content, buttonIndex) => content &&
$create('button', Object.assign({ $create('button', Object.assign({

View File

@ -1,7 +1,23 @@
/* global configDialog hotkeys msg /* global
getActiveTab CHROME FIREFOX URLS API onDOMready $ $$ prefs $
setupLivePrefs template t $create animateElement $$
tryJSONparse CHROME_HAS_BORDER_BUG */ $create
animateElement
API
CHROME
CHROME_HAS_BORDER_BUG
configDialog
FIREFOX
getActiveTab
hotkeys
msg
onDOMready
prefs
setupLivePrefs
t
tryJSONparse
URLS
*/
'use strict'; 'use strict';
@ -165,7 +181,7 @@ function initPopup(frames) {
setTimeout(ping, 100, tab, --retryCountdown); setTimeout(ping, 100, tab, --retryCountdown);
return; return;
} }
const info = template.unreachableInfo; const info = t.template.unreachableInfo;
if (!FIREFOX) { if (!FIREFOX) {
// Chrome "Allow access to file URLs" in chrome://extensions message // Chrome "Allow access to file URLs" in chrome://extensions message
info.appendChild($create('p', t('unreachableFileHint'))); info.appendChild($create('p', t('unreachableFileHint')));
@ -204,7 +220,7 @@ function createWriterElement(frame) {
const targets = $create('span'); const targets = $create('span');
// For this URL // For this URL
const urlLink = template.writeStyle.cloneNode(true); const urlLink = t.template.writeStyle.cloneNode(true);
const isAboutBlank = url === ABOUT_BLANK; const isAboutBlank = url === ABOUT_BLANK;
Object.assign(urlLink, { Object.assign(urlLink, {
href: 'edit.html?url-prefix=' + encodeURIComponent(url), href: 'edit.html?url-prefix=' + encodeURIComponent(url),
@ -233,7 +249,7 @@ function createWriterElement(frame) {
if (domains.length > 1 && numParts === 1) { if (domains.length > 1 && numParts === 1) {
continue; continue;
} }
const domainLink = template.writeStyle.cloneNode(true); const domainLink = t.template.writeStyle.cloneNode(true);
Object.assign(domainLink, { Object.assign(domainLink, {
href: 'edit.html?domain=' + encodeURIComponent(domain), href: 'edit.html?domain=' + encodeURIComponent(domain),
textContent: numParts > 2 ? domain.split('.')[0] : domain, textContent: numParts > 2 ? domain.split('.')[0] : domain,
@ -322,7 +338,7 @@ function showStyles(frameResults) {
if (entries.size) { if (entries.size) {
resortEntries([...entries.values()]); resortEntries([...entries.values()]);
} else { } else {
installed.appendChild(template.noStyles); installed.appendChild(t.template.noStyles);
} }
window.dispatchEvent(new Event('showStyles:done')); window.dispatchEvent(new Event('showStyles:done'));
} }
@ -337,7 +353,7 @@ function resortEntries(entries) {
function createStyleElement(style) { function createStyleElement(style) {
let entry = $.entry(style); let entry = $.entry(style);
if (!entry) { if (!entry) {
entry = template.style.cloneNode(true); entry = t.template.style.cloneNode(true);
entry.setAttribute('style-id', style.id); entry.setAttribute('style-id', style.id);
Object.assign(entry, { Object.assign(entry, {
id: ENTRY_ID_PREFIX_RAW + style.id, id: ENTRY_ID_PREFIX_RAW + style.id,
@ -384,7 +400,7 @@ function createStyleElement(style) {
$('.delete', entry).onclick = handleEvent.delete; $('.delete', entry).onclick = handleEvent.delete;
const indicator = template.regexpProblemIndicator.cloneNode(true); const indicator = t.template.regexpProblemIndicator.cloneNode(true);
indicator.appendChild(document.createTextNode('!')); indicator.appendChild(document.createTextNode('!'));
indicator.onclick = handleEvent.indicator; indicator.onclick = handleEvent.indicator;
$('.main-controls', entry).appendChild(indicator); $('.main-controls', entry).appendChild(indicator);
@ -587,7 +603,7 @@ Object.assign(handleEvent, {
indicator(event) { indicator(event) {
const entry = handleEvent.getClickedStyleElement(event); const entry = handleEvent.getClickedStyleElement(event);
const info = template.regexpProblemExplanation.cloneNode(true); const info = t.template.regexpProblemExplanation.cloneNode(true);
$.remove('#' + info.id); $.remove('#' + info.id);
$$('a', info).forEach(el => (el.onclick = handleEvent.openURLandHide)); $$('a', info).forEach(el => (el.onclick = handleEvent.openURLandHide));
$$('button', info).forEach(el => (el.onclick = handleEvent.closeExplanation)); $$('button', info).forEach(el => (el.onclick = handleEvent.closeExplanation));
@ -684,7 +700,7 @@ function handleDelete(id) {
const el = $.entry(id); const el = $.entry(id);
if (el) { if (el) {
el.remove(); el.remove();
if (!$('.entry')) installed.appendChild(template.noStyles); if (!$('.entry')) installed.appendChild(t.template.noStyles);
} }
} }
@ -714,9 +730,9 @@ async function getStyleDataMerged(url, id) {
function blockPopup(isBlocked = true) { function blockPopup(isBlocked = true) {
document.body.classList.toggle('blocked', isBlocked); document.body.classList.toggle('blocked', isBlocked);
if (isBlocked) { if (isBlocked) {
document.body.prepend(template.unavailableInfo); document.body.prepend(t.template.unavailableInfo);
} else { } else {
template.unavailableInfo.remove(); t.template.unavailableInfo.remove();
template.noStyles.remove(); t.template.noStyles.remove();
} }
} }

View File

@ -1,5 +1,18 @@
/* global URLS tabURL handleEvent $ $$ prefs template FIREFOX debounce /* global
$create t API tWordBreak formatDate tryCatch download */ $
$$
$create
API
debounce
download
FIREFOX
handleEvent
prefs
t
tabURL
tryCatch
URLS
*/
'use strict'; 'use strict';
window.addEventListener('showStyles:done', () => { window.addEventListener('showStyles:done', () => {
@ -103,7 +116,7 @@ window.addEventListener('showStyles:done', () => {
const navOnClick = {prev, next}; const navOnClick = {prev, next};
for (const place of ['top', 'bottom']) { for (const place of ['top', 'bottom']) {
const nav = $(`.search-results-nav[data-type="${place}"]`); const nav = $(`.search-results-nav[data-type="${place}"]`);
nav.appendChild(template.searchNav.cloneNode(true)); nav.appendChild(t.template.searchNav.cloneNode(true));
dom.nav[place] = nav; dom.nav[place] = nav;
for (const child of $$('[data-type]', nav)) { for (const child of $$('[data-type]', nav)) {
const type = child.dataset.type; const type = child.dataset.type;
@ -257,7 +270,7 @@ window.addEventListener('showStyles:done', () => {
* @returns {Node} * @returns {Node}
*/ */
function createSearchResultNode(result) { function createSearchResultNode(result) {
const entry = template.searchResult.cloneNode(true); const entry = t.template.searchResult.cloneNode(true);
const { const {
i: id, i: id,
n: name, n: name,
@ -276,7 +289,7 @@ window.addEventListener('showStyles:done', () => {
href: URLS.usoArchive + `?category=${category}&style=${id}`, href: URLS.usoArchive + `?category=${category}&style=${id}`,
}); });
$('.search-result-title span', entry).textContent = $('.search-result-title span', entry).textContent =
tWordBreak(name.length < 300 ? name : name.slice(0, 300) + '...'); t.breakWord(name.length < 300 ? name : name.slice(0, 300) + '...');
// screenshot // screenshot
const auto = URLS.uso + `auto_style_screenshots/${id}${USO_AUTO_PIC_SUFFIX}`; const auto = URLS.uso + `auto_style_screenshots/${id}${USO_AUTO_PIC_SUFFIX}`;
Object.assign($('.search-result-screenshot', entry), { Object.assign($('.search-result-screenshot', entry), {
@ -303,7 +316,7 @@ window.addEventListener('showStyles:done', () => {
// time // time
Object.assign($('[data-type="updated"] time', entry), { Object.assign($('[data-type="updated"] time', entry), {
dateTime: updateTime * 1000, dateTime: updateTime * 1000,
textContent: formatDate(updateTime * 1000), textContent: t.formatDate(updateTime * 1000),
}); });
// totals // totals
$('[data-type="weekly"] dd', entry).textContent = formatNumber(weeklyInstalls); $('[data-type="weekly"] dd', entry).textContent = formatNumber(weeklyInstalls);