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';
@ -183,7 +189,7 @@
// setTimeout(() => {
// $('.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*$/);
if (m) {
cm.setCursor(m[1] - 1, m[2] ? m[2] - 1 : cur.ch);

View File

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

View File

@ -1,5 +1,18 @@
/* global CodeMirror focusAccessibility colorMimicry editor chromeLocal
onDOMready $ $$ $create t debounce tryRegExp stringAsRegExp template */
/* global
$
$$
$create
chromeLocal
CodeMirror
colorMimicry
debounce
editor
focusAccessibility
onDOMready
stringAsRegExp
t
tryRegExp
*/
'use strict';
onDOMready().then(() => {
@ -563,14 +576,14 @@ onDOMready().then(() => {
state.originalFocus = document.activeElement;
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);
dialog.addEventListener('focusout', EVENTS.onfocusout);
dialog.dataset.type = type;
dialog.style.pointerEvents = 'auto';
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(1, 'input2', state.replace);
@ -633,7 +646,7 @@ onDOMready().then(() => {
input.value = value;
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;
}

View File

@ -9,7 +9,6 @@
prefs
regExpTester
t
template
tryCatch
*/
'use strict';
@ -55,7 +54,7 @@ function MozSectionWidget(
$create('ul' + C_LIST),
]),
listItem:
template.appliesTo.cloneNode(true),
t.template.appliesTo.cloneNode(true),
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 */
'use strict';
@ -86,7 +94,7 @@ const regExpTester = (() => {
full: {data: [], label: t('styleRegexpTestFull')},
partial: {data: [], label: [
t('styleRegexpTestPartial'),
template.regexpTestPartial.cloneNode(true),
t.template.regexpTestPartial.cloneNode(true),
]},
none: {data: [], label: t('styleRegexpTestNone')},
invalid: {data: [], label: t('styleRegexpTestInvalid')},

View File

@ -9,7 +9,6 @@
prefs
regExpTester
t
template
trimCommentLabel
tryRegExp
*/
@ -26,7 +25,7 @@
function createSection(originalSection, genId, si) {
const {dirty} = editor;
const sectionId = genId();
const el = template.section.cloneNode(true);
const el = t.template.section.cloneNode(true);
const elLabel = $('.code-label', el);
const cm = cmFactory.create(wrapper => {
// 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}) {
const applyId = genId();
const dirtyPrefix = `section.${sectionId}.apply.${applyId}`;
const el = all ? template.appliesToEverything.cloneNode(true) :
template.appliesTo.cloneNode(true);
const el = all ? t.template.appliesToEverything.cloneNode(true) :
t.template.appliesTo.cloneNode(true);
const selectEl = !all && $('.applies-type', el);
if (selectEl) {
@ -359,7 +358,7 @@ function createSection(originalSection, genId, si) {
function createResizeGrip(cm) {
const wrapper = cm.display.wrapper;
wrapper.classList.add('resize-grip-enabled');
const resizeGrip = template.resizeGrip.cloneNode(true);
const resizeGrip = t.template.resizeGrip.cloneNode(true);
wrapper.appendChild(resizeGrip);
let lastClickTime = 0;
let initHeight;

View File

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

View File

@ -1,97 +1,90 @@
/* global tryCatch */
/* exported tHTML formatDate */
'use strict';
const template = {};
tDocLoader();
function t(key, params) {
const s = chrome.i18n.getMessage(key, params);
if (!s) throw `Missing string "${key}"`;
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) {
// body is a text node without HTML tags
if (typeof html === 'string' && !tag && /<\w+/.test(html) === false) {
return document.createTextNode(html);
}
if (typeof html === 'string') {
// 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;
}
HTML(html) {
return typeof html !== 'string'
? html
: /<\w+/.test(html) // check for html tags
? t.createHtml(html.replace(/>\n\s*</g, '><').trim())
: document.createTextNode(html);
},
function tNodeList(nodes) {
const PREFIX = 'i18n-';
for (let n = nodes.length; --n >= 0;) {
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)) {
NodeList(nodes) {
const PREFIX = 'i18n-';
for (let n = nodes.length; --n >= 0;) {
const node = nodes[n];
if (node.nodeType !== Node.ELEMENT_NODE) {
continue;
}
const type = name.substr(PREFIX.length);
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 = createText(value);
break;
case 'html': {
toInsert = createHtml(value);
break;
if (node.localName === 'template') {
t.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;
}
default:
node.setAttribute(type, value);
const type = name.substr(PREFIX.length);
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('*');
tNodeList(elements);
template[node.dataset.id] = elements[0];
t.NodeList(elements);
t.template[node.dataset.id] = elements[0];
// compress inter-tag whitespace to reduce number of DOM nodes by 25%
const walker = document.createTreeWalker(elements[0], NodeFilter.SHOW_TEXT);
const toRemove = [];
@ -101,104 +94,96 @@ function tNodeList(nodes) {
toRemove.push(textNode);
}
}
tDocLoader.pause();
t.stopObserver();
toRemove.forEach(el => el.remove());
}
},
function createText(str) {
return document.createTextNode(tWordBreak(str));
}
createText(str) {
return document.createTextNode(t.breakWord(str));
},
function createHtml(value) {
// <a> and <code> are the only acceptable HTML elements,
// <a> also allows `href` attribute with an http/https URL
const rx = /(<)(a|code)(\s[^>]*|)>(.*?)<\/\2>/i;
createHtml(str, trusted) {
const root = t.DOMParser.parseFromString(str, 'text/html').body;
if (!trusted) {
t.sanitizeHtml(root);
} else if (str.includes('i18n-')) {
t.NodeList(root.getElementsByTagName('*'));
}
const bin = document.createDocumentFragment();
for (let parts = value.split(rx), i = 0; i < parts.length; i++) {
const s = parts[i];
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));
}
while (root.firstChild) {
bin.appendChild(root.firstChild);
}
return bin;
}
}
},
function tDocLoader() {
t.DOMParser = new DOMParser();
t.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');
Object.assign(tDocLoader, {
observer: new MutationObserver(process),
start() {
if (!tDocLoader.observing) {
tDocLoader.observing = true;
tDocLoader.observer.observe(document, {subtree: true, childList: true});
sanitizeHtml(root) {
const toRemove = [];
const walker = document.createTreeWalker(root);
for (let n; (n = walker.nextNode());) {
if (n.nodeType === Node.TEXT_NODE) {
n.nodeValue = t.breakWord(n.nodeValue);
} else if (t.ALLOWED_TAGS.includes(n.localName)) {
for (const attr of n.attributes) {
if (n.localName !== 'a' || attr.localName !== 'href' || !/^https?:/.test(n.href)) {
n.removeAttribute(attr.name);
}
}
} else {
toRemove.push(n);
}
},
stop() {
tDocLoader.pause();
document.removeEventListener('DOMContentLoaded', onLoad);
},
pause() {
if (tDocLoader.observing) {
tDocLoader.observing = false;
tDocLoader.observer.disconnect();
}
for (const n of toRemove) {
const parent = n.parentNode;
if (parent) parent.removeChild(n); // not using .remove() as there may be a non-element
}
},
formatDate(date) {
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('*'));
tDocLoader.start();
document.addEventListener('DOMContentLoaded', onLoad);
t.NodeList(document.getElementsByTagName('*'));
start();
function process(mutations) {
for (const mutation of mutations) {
tNodeList(mutation.addedNodes);
mutations.forEach(m => t.NodeList(m.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
prefs setupLivePrefs debounce API */
/* global
$
$create
$createLink
API
debounce
deepCopy
messageBox
prefs
setupLivePrefs
t
*/
/* exported configDialog */
'use strict';
@ -305,7 +315,7 @@ function configDialog(style) {
elements.push(
$create(`label.config-${va.type}`, [
$create('span.config-name', tWordBreak(va.label)),
$create('span.config-name', t.breakWord(va.label)),
...children,
resetter,
]));

View File

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

View File

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

View File

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