parent
fbcd3cc965
commit
99cce55a8e
|
@ -48,6 +48,7 @@ globals:
|
||||||
tHTML: false
|
tHTML: false
|
||||||
tNodeList: false
|
tNodeList: false
|
||||||
tDocLoader: false
|
tDocLoader: false
|
||||||
|
tWordBreak: false
|
||||||
# dom.js
|
# dom.js
|
||||||
onDOMready: false
|
onDOMready: false
|
||||||
scrollElementIntoView: false
|
scrollElementIntoView: false
|
||||||
|
|
24
edit/edit.js
24
edit/edit.js
|
@ -75,30 +75,6 @@ function preinit() {
|
||||||
'vendor/codemirror/theme/' + prefs.get('editor.theme') + '.css'
|
'vendor/codemirror/theme/' + prefs.get('editor.theme') + '.css'
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// forcefully break long labels in aligned options to prevent the entire block layout from breaking
|
|
||||||
onDOMready().then(() => new Promise(requestAnimationFrame)).then(() => {
|
|
||||||
const maxWidth2ndChild = $$('#options .aligned > :nth-child(2)')
|
|
||||||
.sort((a, b) => b.offsetWidth - a.offsetWidth)[0].offsetWidth;
|
|
||||||
const widthFor1stChild = $('#options').offsetWidth - maxWidth2ndChild;
|
|
||||||
if (widthFor1stChild > 50) {
|
|
||||||
for (const el of $$('#options .aligned > :nth-child(1)')) {
|
|
||||||
if (el.offsetWidth > widthFor1stChild) {
|
|
||||||
el.style.cssText = 'word-break: break-all; hyphens: auto;';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const width = $('#options').clientWidth;
|
|
||||||
document.head.appendChild($create('style', `
|
|
||||||
#options .aligned > nth-child(1) {
|
|
||||||
max-width: 70px;
|
|
||||||
}
|
|
||||||
#options .aligned > nth-child(2) {
|
|
||||||
max-width: ${width - 70}px;
|
|
||||||
}
|
|
||||||
`));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (chrome.windows) {
|
if (chrome.windows) {
|
||||||
queryTabs({currentWindow: true}).then(tabs => {
|
queryTabs({currentWindow: true}).then(tabs => {
|
||||||
const windowId = tabs[0].windowId;
|
const windowId = tabs[0].windowId;
|
||||||
|
|
|
@ -48,13 +48,51 @@ function tHTML(html, tag) {
|
||||||
|
|
||||||
function tNodeList(nodes) {
|
function tNodeList(nodes) {
|
||||||
const PREFIX = 'i18n-';
|
const PREFIX = 'i18n-';
|
||||||
|
|
||||||
for (let n = nodes.length; --n >= 0;) {
|
for (let n = nodes.length; --n >= 0;) {
|
||||||
const node = nodes[n];
|
const node = nodes[n];
|
||||||
// skip non-ELEMENT_NODE
|
if (node.nodeType !== Node.ELEMENT_NODE) {
|
||||||
if (node.nodeType !== 1) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (node.localName === 'template') {
|
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;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
node.setAttribute(type, value);
|
||||||
|
}
|
||||||
|
tDocLoader.pause();
|
||||||
|
if (toInsert) {
|
||||||
|
node.insertBefore(toInsert, before || null);
|
||||||
|
}
|
||||||
|
node.removeAttribute(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createTemplate(node) {
|
||||||
const elements = node.content.querySelectorAll('*');
|
const elements = node.content.querySelectorAll('*');
|
||||||
tNodeList(elements);
|
tNodeList(elements);
|
||||||
template[node.dataset.id] = elements[0];
|
template[node.dataset.id] = elements[0];
|
||||||
|
@ -67,37 +105,32 @@ function tNodeList(nodes) {
|
||||||
toRemove.push(textNode);
|
toRemove.push(textNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
tDocLoader.pause();
|
||||||
toRemove.forEach(el => el.remove());
|
toRemove.forEach(el => el.remove());
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
for (let a = node.attributes.length; --a >= 0;) {
|
|
||||||
const attr = node.attributes[a];
|
function createText(str) {
|
||||||
const name = attr.nodeName;
|
return document.createTextNode(tWordBreak(str));
|
||||||
if (!name.startsWith(PREFIX)) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
const type = name.substr(PREFIX.length);
|
|
||||||
const value = t(attr.value);
|
function createHtml(value) {
|
||||||
switch (type) {
|
// <a href=foo>bar</a> are the only recognizable HTML elements
|
||||||
case 'text':
|
const rx = /(?:<a\s([^>]*)>([^<]*)<\/a>)?([^<]*)/gi;
|
||||||
node.insertBefore(document.createTextNode(value), node.firstChild);
|
const bin = document.createDocumentFragment();
|
||||||
break;
|
for (let m; (m = rx.exec(value)) && m[0];) {
|
||||||
case 'text-append':
|
const [, linkParams, linkText, nextText] = m;
|
||||||
node.appendChild(document.createTextNode(value));
|
if (linkText) {
|
||||||
break;
|
const href = /\bhref\s*=\s*(\S+)/.exec(linkParams);
|
||||||
case 'html':
|
const a = bin.appendChild(document.createElement('a'));
|
||||||
// localized strings only allow having text nodes and links
|
a.href = href && href[1].replace(/^(["'])(.*)\1$/, '$2') || '';
|
||||||
node.textContent = '';
|
a.appendChild(createText(linkText));
|
||||||
[...tHTML(value, 'div').childNodes]
|
|
||||||
.filter(a => a.nodeType === a.TEXT_NODE || a.tagName === 'A')
|
|
||||||
.forEach(n => node.appendChild(n));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
node.setAttribute(type, value);
|
|
||||||
}
|
}
|
||||||
node.removeAttribute(name);
|
if (nextText) {
|
||||||
|
bin.appendChild(createText(nextText));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return bin;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -115,33 +148,50 @@ function tDocLoader() {
|
||||||
t.cache = {browserUIlanguage: UIlang};
|
t.cache = {browserUIlanguage: UIlang};
|
||||||
localStorage.L10N = JSON.stringify(t.cache);
|
localStorage.L10N = JSON.stringify(t.cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
const cacheLength = Object.keys(t.cache).length;
|
const cacheLength = Object.keys(t.cache).length;
|
||||||
|
|
||||||
// localize HEAD
|
Object.assign(tDocLoader, {
|
||||||
tNodeList(document.getElementsByTagName('*'));
|
observer: new MutationObserver(process),
|
||||||
|
start() {
|
||||||
|
if (!tDocLoader.observing) {
|
||||||
|
tDocLoader.observing = true;
|
||||||
|
tDocLoader.observer.observe(document, {subtree: true, childList: true});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
stop() {
|
||||||
|
tDocLoader.pause();
|
||||||
|
document.removeEventListener('DOMContentLoaded', onLoad);
|
||||||
|
},
|
||||||
|
pause() {
|
||||||
|
if (tDocLoader.observing) {
|
||||||
|
tDocLoader.observing = false;
|
||||||
|
tDocLoader.observer.disconnect();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// localize BODY
|
tNodeList(document.getElementsByTagName('*'));
|
||||||
const process = mutations => {
|
tDocLoader.start();
|
||||||
|
document.addEventListener('DOMContentLoaded', onLoad);
|
||||||
|
|
||||||
|
function process(mutations) {
|
||||||
for (const mutation of mutations) {
|
for (const mutation of mutations) {
|
||||||
tNodeList(mutation.addedNodes);
|
tNodeList(mutation.addedNodes);
|
||||||
}
|
}
|
||||||
};
|
tDocLoader.start();
|
||||||
const observer = new MutationObserver(process);
|
}
|
||||||
const onLoad = () => {
|
|
||||||
|
function onLoad() {
|
||||||
tDocLoader.stop();
|
tDocLoader.stop();
|
||||||
process(observer.takeRecords());
|
process(tDocLoader.observer.takeRecords());
|
||||||
if (cacheLength !== Object.keys(t.cache).length) {
|
if (cacheLength !== Object.keys(t.cache).length) {
|
||||||
localStorage.L10N = JSON.stringify(t.cache);
|
localStorage.L10N = JSON.stringify(t.cache);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
tDocLoader.start = () => {
|
}
|
||||||
observer.observe(document, {subtree: true, childList: true});
|
|
||||||
};
|
|
||||||
tDocLoader.stop = () => {
|
function tWordBreak(text) {
|
||||||
observer.disconnect();
|
// adds soft hyphens every 10 characters to ensure the long words break before breaking the layout
|
||||||
document.removeEventListener('DOMContentLoaded', onLoad);
|
return text.length <= 10 ? text : text.replace(/[\d\w\u0080-\uFFFF]{10}|((?!\s)\W){10}/g, '$&\u00AD');
|
||||||
};
|
|
||||||
tDocLoader.start();
|
|
||||||
document.addEventListener('DOMContentLoaded', onLoad);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -179,7 +179,7 @@ function createStyleElement({style, name}) {
|
||||||
}
|
}
|
||||||
const parts = createStyleElement.parts;
|
const parts = createStyleElement.parts;
|
||||||
parts.checker.checked = style.enabled;
|
parts.checker.checked = style.enabled;
|
||||||
parts.nameLink.textContent = style.name;
|
parts.nameLink.textContent = tWordBreak(style.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 || '';
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user