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