PageSourceSearch

https://www.rheinpfalz.de/pu_rhp//scripts/93_Hyphenopoly_Loader.js

js rheinpfalz.de collected 2026-09-24 08:47:22 UTC 10,518 bytes, 349 lines download raw bytes

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.