1/** 2 * @license Hyphenopoly_Loader 4.12.0 - client side hyphenation 3 * ©2021 Mathias Nater, Güttingen (mathiasnater at gmail dot com) 4 * https://github.com/mnater/Hyphenopoly 5 * 6 * Released under the MIT license 7 * http://mnater.github.io/Hyphenopoly/LICENSE 8 */ 9/* globals Hyphenopoly:readonly */ 10((w, d, H, o) => { 11 "use strict"; 12 13 /** 14 * Shortcut for new Map 15 * @param {any} init - initialiser for new Map 16 * @returns {Map} 17 */ 18 const mp = (init) => { 19 return new Map(init); 20 }; 21 22 /** 23 * Sets default properties for an Object 24 * @param {object} obj - The object to set defaults to 25 * @param {object} defaults - The defaults to set 26 * @returns {object} 27 */ 28 const setDefaults = (obj, defaults) => { 29 if (obj) { 30 o.entries(defaults).forEach(([k, v]) => { 31 // eslint-disable-next-line security/detect-object-injection 32 obj[k] = obj[k] || v; 33 }); 34 return obj; 35 } 36 return defaults; 37 }; 38 39 const store = sessionStorage; 40 const scriptName = "Hyphenopoly_Loader.js"; 41 const lcRequire = mp(); 42 43 const shortcuts = { 44 "ac": "appendChild", 45 "ce": "createElement", 46 "ct": "createTextNode" 47 }; 48 49 /** 50 * Set H.cf (Hyphenopoly.clientFeatures) either by reading out previously 51 * computed settings from sessionStorage or creating a template object. 52 * This is in an iife to keep complexity low. 53 */ 54 (() => { 55 if (H.cacheFeatureTests && store.getItem(scriptName)) { 56 H.cf = JSON.parse(store.getItem(scriptName)); 57 H.cf.langs = mp(H.cf.langs); 58 } else { 59 H.cf = { 60 "langs": mp(), 61 "pf": false 62 }; 63 } 64 })(); 65 66 /** 67 * Set H.paths and some H.s (setup) fields to defaults or 68 * overwrite with user settings. 69 * These is an iife to keep complexity low. 70 */ 71 (() => { 72 const thisScript = d.currentScript.src; 73 const maindir = thisScript.slice(0, (thisScript.lastIndexOf("/") + 1)); 74 const patterndir = maindir + "patterns/"; 75 H.paths = setDefaults(H.paths, { 76 maindir, 77 patterndir 78 }); 79 80 H.s = setDefaults(H.setup, { 81 "CORScredentials": "include", 82 "hide": "all", 83 "selectors": {".hyphenate": {}}, 84 "timeout": 1000 85 }); 86 // Change mode string to mode int 87 H.s.hide = ["all", "element", "text"].indexOf(H.s.hide); 88 })(); 89 90 /** 91 * Copy required languages to local lcRequire (lowercaseRequire) and 92 * eventually fallbacks to local lcFallbacks (lowercaseFallbacks). 93 * This is in an iife to keep complexity low. 94 */ 95 (() => { 96 const fallbacks = mp(o.entries(H.fallbacks || {})); 97 o.entries(H.require).forEach(([lang, wo]) => { 98 lcRequire.set(lang.toLowerCase(), { 99 "fn": fallbacks.get(lang) || lang, 100 wo 101 }); 102 }); 103 })(); 104 105 /** 106 * Create deferred Promise 107 * 108 * Kudos to http://lea.verou.me/2016/12/resolve-promises-externally-with- 109 * this-one-weird-trick/ 110 * @return {promise} 111 */ 112 const defProm = () => { 113 let res = null; 114 let rej = null; 115 const promise = new Promise((resolve, reject) => { 116 res = resolve; 117 rej = reject; 118 }); 119 promise.resolve = res; 120 promise.reject = rej; 121 122 return promise; 123 }; 124 125 let stylesNode = null; 126 127 /** 128 * Define function H.hide. 129 * This function hides (state = 1) or unhides (state = 0) 130 * the whole document (mode == 0) or 131 * each selected element (mode == 1) or 132 * text of each selected element (mode == 2) or 133 * nothing (mode == -1) 134 * @param {integer} state - State 135 * @param {integer} mode - Mode 136 */ 137 H.hide = (state, mode) => { 138 if (state === 0) { 139 if (stylesNode) { 140 stylesNode.remove(); 141 } 142 } else { 143 const vis = "{visibility:hidden!important}"; 144 stylesNode = d[shortcuts.ce]("style"); 145 let myStyle = ""; 146 if (mode === 0) { 147 myStyle = "html" + vis; 148 } else {
149 o.keys(H.s.selectors).forEach((sel) => { 150 if (mode === 1) { 151 myStyle += sel + vis; 152 } else { 153 myStyle += sel + "{color:transparent!important}"; 154 } 155 }); 156 } 157 stylesNode[shortcuts.ac](d[shortcuts.ct](myStyle)); 158 d.head[shortcuts.ac](stylesNode); 159 } 160 }; 161 162 const tester = (() => { 163 let fakeBody = null; 164 return { 165 166 /** 167 * Append fakeBody with tests to document 168 * @returns {Object|null} The body element or null, if no tests 169 */ 170 "ap": () => { 171 if (fakeBody) { 172 d.documentElement[shortcuts.ac](fakeBody); 173 return fakeBody; 174 } 175 return null; 176 }, 177 178 /** 179 * Remove fakeBody 180 * @returns {undefined} 181 */ 182 "cl": () => { 183 if (fakeBody) { 184 fakeBody.remove(); 185 } 186 }, 187 188 /** 189 * Create and append div with CSS-hyphenated word 190 * @param {string} lang Language 191 * @returns {undefined} 192 */ 193 "cr": (lang) => { 194 if (H.cf.langs.has(lang)) { 195 return; 196 } 197 fakeBody = fakeBody || d[shortcuts.ce]("body"); 198 const testDiv = d[shortcuts.ce]("div"); 199 const ha = "hyphens:auto"; 200 testDiv.lang = lang; 201 testDiv.style.cssText = `visibility:hidden;-webkit-${ha};-ms-${ha};${ha};width:48px;font-size:12px;line-height:12px;border:none;padding:0;word-wrap:normal`; 202 testDiv[shortcuts.ac]( 203 d[shortcuts.ct](lcRequire.get(lang).wo.toLowerCase()) 204 ); 205 fakeBody[shortcuts.ac](testDiv); 206 } 207 }; 208 })(); 209 210 /** 211 * Checks if hyphens (ev.prefixed) is set to auto for the element. 212 * @param {Object} elm - the element 213 * @returns {Boolean} result of the check 214 */ 215 const checkCSSHyphensSupport = (elmStyle) => { 216 const h = elmStyle.hyphens || 217 elmStyle.webkitHyphens || 218 elmStyle.msHyphens; 219 return (h === "auto"); 220 }; 221 222 H.res = { 223 "he": mp() 224 }; 225 const fw = mp(); 226 227 /** 228 * Load hyphenEngines 229 * 230 * Make sure each .wasm is loaded exactly once, even for fallbacks 231 * fw: fetched wasm (maps filename to language) 232 * he: hyphenEngines (maps lang to wasm and counter) 233 * c (counter) is needed in Hyphenopoly.js to decide 234 * if wasm needs to be cloned 235 * @param {string} lang The language 236 * @returns {undefined} 237 */ 238 const loadhyphenEngine = (lang) => { 239 const filename = lcRequire.get(lang).fn + ".wasm"; 240 H.cf.pf = true; 241 H.cf.langs.set(lang, "H9Y"); 242 if (fw.has(filename)) { 243 const hyphenEngineWrapper = H.res.he.get(fw.get(filename)); 244 hyphenEngineWrapper.c = true; 245 H.res.he.set(lang, hyphenEngineWrapper); 246 } else { 247 H.res.he.set( 248 lang, 249 { 250 "w": w.fetch(H.paths.patterndir + filename, {"credentials": H.s.CORScredentials}) 251 } 252 ); 253 fw.set(filename, lang); 254 } 255 }; 256 lcRequire.forEach((value, lang) => { 257 if (value.wo === "FORCEHYPHENOPOLY" || H.cf.langs.get(lang) === "H9Y") { 258 loadhyphenEngine(lang); 259 } else { 260 tester.cr(lang); 261 } 262 }); 263 const testContainer = tester.ap(); 264 if (testContainer) { 265 testContainer.querySelectorAll("div").forEach((n) => { 266 if (checkCSSHyphensSupport(n.style) && n.offsetHeight > 12) { 267 H.cf.langs.set(n.lang, "CSS"); 268 } else { 269 loadhyphenEngine(n.lang); 270 } 271 }); 272 tester.cl(); 273 } 274 const he = H.handleEvent; 275 if (H.cf.pf) { 276 H.res.DOM = new Promise((res) => { 277 if (d.readyState === "loading") { 278 d.addEventListener( 279 "DOMContentLoaded", 280 res, 281 { 282 "once": true, 283 "passive": true 284 } 285 ); 286 } else { 287 res(); 288 } 289 }); 290 const hide = H.s.hide; 291 if (hide === 0) { 292 H.hide(1, 0); 293 } 294 if (hide !== -1) { 295 H.timeOutHandler = w.setTimeout(() => { 296 H.hide(0, null); 297 // eslint-disable-next-line no-console 298 console.info(scriptName + " timed out."); 299 }, H.s.timeout); 300 } 301 H.res.DOM.then(() => { 302 if (hide > 0) { 303 H.hide(1, hide); 304 } 305 }); 306 // Load main script 307 const script = d[shortcuts.ce]("script"); 308 script.src = H.paths.maindir + "Hyphenopoly.js"; 309 d.head[shortcuts.ac](script); 310 H.hy6ors = mp();
vendor: 1,056 bytes, lines 311-349
311 H.cf.langs.forEach((langDef, lang) => { 312 if (langDef === "H9Y") { 313 H.hy6ors.set(lang, defProm()); 314 } 315 }); 316 H.hy6ors.set("HTML", defProm()); 317 H.hyphenators = new Proxy(H.hy6ors, { 318 "get": (target, key) => { 319 return target.get(key); 320 }, 321 "set": () => { 322 // Inhibit setting of hyphenators 323 return true; 324 } 325 }); 326 (() => { 327 if (he && he.polyfill) { 328 he.polyfill(); 329 } 330 })(); 331 } else { 332 (() => { 333 if (he && he.tearDown) { 334 he.tearDown(); 335 } 336 w.Hyphenopoly = null; 337 })(); 338 } 339 (() => { 340 if (H.cacheFeatureTests) { 341 store.setItem(scriptName, JSON.stringify( 342 { 343 "langs": [...H.cf.langs.entries()], 344 "pf": H.cf.pf 345 } 346 )); 347 } 348 })(); 349})(window, document, Hyphenopoly, Object);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.