diff --git a/CHANGELOG.md b/CHANGELOG.md index b69d821f..6b66da41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Version History +## Version 2.6.0 (Dec 01, 2018) +* improve hiding of elements while hyphenating (issue #40) +* fix several issues with lang-fallbacks (issue #41 and #44) +* new feature: use selectors instead of classnames (issue #42) +* updated german patterns (issue #45) + ## Version 2.5.1 (Nov 04, 2018) * remove "Church Slavonic" patterns (see #38) * fix issue #39 diff --git a/Hyphenopoly.js b/Hyphenopoly.js index af3d267e..e9a20d1c 100644 --- a/Hyphenopoly.js +++ b/Hyphenopoly.js @@ -1,5 +1,5 @@ /** - * @license Hyphenopoly 2.5.1 - client side hyphenation for webbrowsers + * @license Hyphenopoly 2.6.0 - client side hyphenation for webbrowsers * ©2018 Mathias Nater, Zürich (mathiasnater at gmail dot com) * https://github.com/mnater/Hyphenopoly * @@ -98,26 +98,40 @@ }); Object.keys(H.setup).forEach(function copySettings(key) { - if (key === "classnames") { - const classNames = Object.keys(H.setup.classnames); + if (key === "selectors") { + const selectors = Object.keys(H.setup.selectors); Object.defineProperty( settings, - "classNames", - setProp(classNames, 2) + "selectors", + setProp(selectors, 2) ); - classNames.forEach(function copyClassnames(cn) { - const tmp = {}; - Object.keys(H.setup.classnames[cn]).forEach( - function copyClassSettings(k) { - tmp[k] = setProp(H.setup.classnames[cn][k], 2); + selectors.forEach(function copySelectors(sel) { + const tmp = empty(); + Object.keys(H.setup.selectors[sel]).forEach( + function copySelectorSettings(k) { + tmp[k] = setProp(H.setup.selectors[sel][k], 2); } ); Object.defineProperty( settings, - cn, + sel, setProp(Object.create(perClassDefaults, tmp), 2) ); }); + } else if (key === "dontHyphenate") { + const tmp = empty(); + Object.keys(H.setup.dontHyphenate).forEach( + function copyTagNames(k) { + tmp[k] = setProp(H.setup.dontHyphenate[k], 2); + } + ); + Object.defineProperty( + settings, + key, + setProp( + Object.create(generalDefaults.dontHyphenate, tmp), 3 + ) + ); } else { Object.defineProperty( settings, @@ -151,13 +165,13 @@ * Add element to elements * @param {object} el The element * @param {string} lang The language of the element - * @param {string} cn The classname of the element + * @param {string} sel The selector of the element * @returns {Object} An element-object */ - function add(el, lang, cn) { + function add(el, lang, sel) { const elo = { - "class": cn, - "element": el + "element": el, + "selector": sel }; if (!list[lang]) { list[lang] = []; @@ -232,40 +246,49 @@ } /** - * Sort out subclasses - * @param {Array} x Array of classnames - * @param {Array} y Array of classnames to sort out of x - * @returns {Array} Array of classes + * Check if node is matched by a given selector + * @param {Node} n The Node to check + * @param {String} sel Selector(s) + * @returns {Boolean} true if matched, false if not matched */ - function sortOutSubclasses(x, y) { - return (x[0] === "") - ? [] - : x.filter(function filter(i) { - return y.indexOf(i) !== -1; - }); + function nodeMatchedBy(n, sel) { + if (!n.matches) { + n.matches = n.msMatchesSelector || n.webkitMatchesSelector; + } + return n.matches(sel); } /** - * Collect elements that have a classname defined in C.classnames + * Collect elements that have a selector defined in C.selectors * and add them to elements. * @returns {undefined} */ function collectElements() { elements = makeElementCollection(); + const dontHyphenateSelector = (function createSel() { + let s = ".donthyphenate"; + let k = null; + for (k in C.dontHyphenate) { + if (C.dontHyphenate[k]) { + s += ", " + k; + } + } + return s; + }()); + const matchingSelectors = C.selectors.join(", ") + ", " + dontHyphenateSelector; + /** - * Recursively walk all elements in el, lending lang and className + * Recursively walk all elements in el, lending lang and selName * add them to elements if necessary. * @param {Object} el The element to scan * @param {string} pLang The language of the oarent element - * @param {string} cn The className of the parent element + * @param {string} sel The selector of the parent element * @param {boolean} isChild If el is a child element * @returns {undefined} */ - function processElements(el, pLang, cn, isChild) { + function processElements(el, pLang, sel, isChild) { let eLang = null; - let n = null; - let j = 0; isChild = isChild || false; if (el.lang && typeof el.lang === "string") { eLang = el.lang.toLowerCase(); @@ -275,7 +298,7 @@ eLang = getLang(el, true); } if (H.clientFeat.langs[eLang] === "H9Y") { - elements.add(el, eLang, cn); + elements.add(el, eLang, sel); if (!isChild && C.safeCopy) { registerOnCopy(el); } @@ -283,23 +306,18 @@ H.events.dispatch("error", {"msg": "Element with '" + eLang + "' found, but '" + eLang + ".hpb' not loaded. Check language tags!"}); } - n = el.childNodes[j]; - while (n) { + const cn = el.childNodes; + Array.prototype.forEach.call(cn, function eachChildNode(n) { if (n.nodeType === 1 && - !C.dontHyphenate[n.nodeName.toLowerCase()] && - n.className.indexOf(C.dontHyphenateClass) === -1) { - if (sortOutSubclasses(n.className.split(" "), C.classNames).length === 0) { - processElements(n, eLang, cn, true); - } + !nodeMatchedBy(n, matchingSelectors)) { + processElements(n, eLang, sel, true); } - j += 1; - n = el.childNodes[j]; - } + }); } - C.classNames.forEach(function eachClassName(cn) { - const nl = w.document.querySelectorAll("." + cn); + C.selectors.forEach(function eachSelector(sel) { + const nl = w.document.querySelectorAll(sel); Array.prototype.forEach.call(nl, function eachNode(n) { - processElements(n, getLang(n, true), cn, false); + processElements(n, getLang(n, true), sel, false); }); }); H.elementsReady = true; @@ -311,14 +329,14 @@ * Factory for hyphenatorFunctions for a specific language and class * @param {Object} lo Language-Object * @param {string} lang The language - * @param {string} cn The className + * @param {string} sel The selector * @returns {function} The hyphenate function */ - function createWordHyphenator(lo, lang, cn) { - const classSettings = C[cn]; + function createWordHyphenator(lo, lang, sel) { + const classSettings = C[sel]; const hyphen = classSettings.hyphen; - lo.cache[cn] = empty(); + lo.cache[sel] = empty(); /** * HyphenateFunction for compound words @@ -334,7 +352,7 @@ switch (classSettings.compound) { case "auto": parts = word.split("-"); - wordHyphenator = createWordHyphenator(lo, lang, cn); + wordHyphenator = createWordHyphenator(lo, lang, sel); while (i < parts.length) { if (parts[i].length >= classSettings.minWordLength) { parts[i] = wordHyphenator(parts[i]); @@ -345,7 +363,7 @@ break; case "all": parts = word.split("-"); - wordHyphenator = createWordHyphenator(lo, lang, cn); + wordHyphenator = createWordHyphenator(lo, lang, sel); while (i < parts.length) { if (parts[i].length >= classSettings.minWordLength) { parts[i] = wordHyphenator(parts[i]); @@ -366,7 +384,7 @@ * @returns {string} The hyphenated word */ function hyphenator(word) { - let hw = lo.cache[cn][word]; + let hw = lo.cache[sel][word]; if (!hw) { if (lo.exceptions[word]) { hw = lo.exceptions[word].replace( @@ -383,11 +401,11 @@ } else { hw = hyphenateCompound(word); } - lo.cache[cn][word] = hw; + lo.cache[sel][word] = hw; } return hw; } - wordHyphenatorPool[lang + "-" + cn] = hyphenator; + wordHyphenatorPool[lang + "-" + sel] = hyphenator; return hyphenator; } @@ -395,10 +413,10 @@ /** * Factory for function that handles orphans - * @param {string} cn The className + * @param {string} sel The selector * @returns {function} The function created */ - function createOrphanController(cn) { + function createOrphanController(sel) { /** * Function template * @param {string} ignore unused result of replace @@ -413,7 +431,7 @@ lastWord, trailingWhiteSpace ) { - const classSettings = C[cn]; + const classSettings = C[sel]; let h = classSettings.hyphen; if (".\\+*?[^]$(){}=!<>|:-".indexOf(classSettings.hyphen) !== -1) { h = "\\" + classSettings.hyphen; @@ -423,36 +441,36 @@ } return leadingWhiteSpace + lastWord.replace(new RegExp(h, "g"), "") + trailingWhiteSpace; } - orphanControllerPool[cn] = controlOrphans; + orphanControllerPool[sel] = controlOrphans; return controlOrphans; } /** * Hyphenate an entitiy (text string or Element-Object) * @param {string} lang - the language of the string - * @param {string} cn - the class of settings + * @param {string} sel - the selectorName of settings * @param {string} entity - the entity to be hyphenated - * @returns {string | null} hyphenated string according to setting of cn + * @returns {string | null} hyphenated str according to setting of sel */ - function hyphenate(lang, cn, entity) { + function hyphenate(lang, sel, entity) { const lo = H.languages[lang]; - const classSettings = C[cn]; + const classSettings = C[sel]; const minWordLength = classSettings.minWordLength; const normalize = C.normalize && Boolean(String.prototype.normalize); - const poolKey = lang + "-" + cn; + const poolKey = lang + "-" + sel; const wordHyphenator = (wordHyphenatorPool[poolKey]) ? wordHyphenatorPool[poolKey] - : createWordHyphenator(lo, lang, cn); - const orphanController = (orphanControllerPool[cn]) - ? orphanControllerPool[cn] - : createOrphanController(cn); - const re = lo.genRegExps[cn]; + : createWordHyphenator(lo, lang, sel); + const orphanController = (orphanControllerPool[sel]) + ? orphanControllerPool[sel] + : createOrphanController(sel); + const re = lo.genRegExps[sel]; /** - * Hyphenate text according to setting in cn + * Hyphenate text according to setting in sel * @param {string} text - the strint to be hyphenated - * @returns {string} hyphenated string according to setting of cn + * @returns {string} hyphenated string according to setting of sel */ function hyphenateText(text) { let tn = null; @@ -471,7 +489,7 @@ } /** - * Hyphenate element according to setting in cn + * Hyphenate element according to setting in sel * @param {object} el - the HTMLElement to be hyphenated * @returns {undefined} */ @@ -480,18 +498,15 @@ "el": el, "lang": lang }); - let i = 0; - let n = el.childNodes[i]; - while (n) { + const cn = el.childNodes; + Array.prototype.forEach.call(cn, function eachChildNode(n) { if ( n.nodeType === 3 && n.data.length >= minWordLength ) { n.data = hyphenateText(n.data); } - i += 1; - n = el.childNodes[i]; - } + }); elements.counter[0] -= 1; H.events.dispatch("afterElementHyphenation", { "el": el, @@ -508,9 +523,9 @@ } H.createHyphenator = function createHyphenator(lang) { - return function hyphenator(entity, cn) { - cn = cn || "hyphenate"; - return hyphenate(lang, cn, entity); + return function hyphenator(entity, sel) { + sel = sel || ".hyphenate"; + return hyphenate(lang, sel, entity); }; }; @@ -523,7 +538,7 @@ function hyphenateLangElements(lang, elArr) { if (elArr) { elArr.forEach(function eachElem(elo) { - hyphenate(lang, elo.class, elo.element); + hyphenate(lang, elo.selector, elo.element); }); } else { H.events.dispatch("error", {"msg": "engine for language '" + lang + "' loaded, but no elements found."}); @@ -539,18 +554,11 @@ * @returns {Object} Map of exceptions */ function convertExceptions(exc) { - const words = exc.split(", "); const r = empty(); - const l = words.length; - let i = 0; - let key = null; - while (i < l) { - key = words[i].replace(/-/g, ""); - if (!r[key]) { - r[key] = words[i]; - } - i += 1; - } + exc.split(", ").forEach(function eachExc(e) { + const key = e.replace(/-/g, ""); + r[key] = e; + }); return r; } @@ -597,8 +605,8 @@ lo.leftmin = leftmin; lo.rightmin = rightmin; lo.hyphenateFunction = hyphenateFunction; - C.classNames.forEach(function eachClassName(cn) { - const classSettings = C[cn]; + C.selectors.forEach(function eachSelector(sel) { + const classSettings = C[sel]; if (classSettings.leftminPerLang === 0) { Object.defineProperty( classSettings, @@ -646,7 +654,7 @@ * that follow a character that is not in the `alphabet`. * Word delimiters are not taken in account. */ - lo.genRegExps[cn] = new RegExp("[\\w" + alphabet + String.fromCharCode(8204) + "-]{" + classSettings.minWordLength + ",}", "gi"); + lo.genRegExps[sel] = new RegExp("[\\w" + alphabet + String.fromCharCode(8204) + "-]{" + classSettings.minWordLength + ",}", "gi"); }); lo.engineReady = true; } @@ -1039,7 +1047,9 @@ "hyphenopolyEnd", function def() { w.clearTimeout(C.timeOutHandler); - w.document.documentElement.style.visibility = "visible"; + if (H.c.hide !== "none") { + H.toggle("on"); + } }, false ); @@ -1056,16 +1066,14 @@ true ); - let eo = H.events.tempRegister.shift(); - while (eo) { + H.events.tempRegister.forEach(function eachEo(eo) { H.events.addListener(eo.name, eo.handler, false); - eo = H.events.tempRegister.shift(); - } + }); delete H.events.tempRegister; H.events.dispatch("hyphenopolyStart", {"msg": "Hyphenopoly started"}); - w.clearTimeout(H.setup.timeOutHandler); + w.clearTimeout(H.c.timeOutHandler); Object.defineProperty(C, "timeOutHandler", setProp( w.setTimeout(function ontimeout() { diff --git a/Hyphenopoly_Loader.js b/Hyphenopoly_Loader.js index b2a590e3..8999d68f 100644 --- a/Hyphenopoly_Loader.js +++ b/Hyphenopoly_Loader.js @@ -1,5 +1,5 @@ /** - * @license Hyphenopoly_Loader 2.5.1 - client side hyphenation + * @license Hyphenopoly_Loader 2.6.0 - client side hyphenation * ©2018 Mathias Nater, Zürich (mathiasnater at gmail dot com) * https://github.com/mnater/Hyphenopoly * @@ -45,21 +45,77 @@ "patterndir": "../Hyphenopoly/patterns/" }; } + if (H.setup) { - if (!H.setup.classnames) { - H.setup.classnames = {"hyphenate": {}}; + if (!H.setup.selectors) { + H.setup.selectors = empty(); + H.setup.selectors[".hyphenate"] = empty(); + } + if (H.setup.classnames) { + Object.keys(H.setup.classnames).forEach(function cn2sel(cn) { + H.setup.selectors["." + cn] = H.setup.classnames[cn]; + }); + H.setup.classnames = null; + delete H.setup.classnames; } if (!H.setup.timeout) { H.setup.timeout = 1000; } + if (!H.setup.hide) { + H.setup.hide = "all"; + } } else { H.setup = { - "classnames": {"hyphenate": {}}, + "hide": "all", + "selectors": {".hyphenate": {}}, "timeout": 1000 }; } + H.lcRequire = empty(); + Object.keys(H.require).forEach(function copyRequire(k) { + H.lcRequire[k.toLowerCase()] = H.require[k]; + }); + if (H.fallbacks) { + H.lcFallbacks = empty(); + Object.keys(H.fallbacks).forEach(function copyFallbacks(k) { + H.lcFallbacks[k.toLowerCase()] = H.fallbacks[k].toLowerCase(); + }); + } }()); + H.toggle = function toggle(state) { + if (state === "on") { + const stylesNode = d.getElementById("H9Y_Styles"); + if (stylesNode) { + stylesNode.parentNode.removeChild(stylesNode); + } + } else { + const sc = d.createElement("style"); + sc.id = "H9Y_Styles"; + switch (H.setup.hide) { + case "all": + sc.innerHTML = "html {visibility: hidden !important}"; + break; + case "element": + Object.keys(H.setup.selectors). + forEach(function eachSelector(sel) { + sc.innerHTML += sel + " {visibility: hidden !important}\n"; + }); + + break; + case "text": + Object.keys(H.setup.selectors). + forEach(function eachSelector(sel) { + sc.innerHTML += sel + " {color: transparent !important}\n"; + }); + break; + default: + sc.innerHTML = ""; + } + d.getElementsByTagName("head")[0].appendChild(sc); + } + }; + (function setupEvents() { // Events known to the system const definedEvents = empty(); @@ -90,7 +146,7 @@ define( "timeout", function def(e) { - d.documentElement.style.visibility = "visible"; + H.toggle("on"); window.console.info( "Hyphenopolys 'FOUHC'-prevention timed out after %dms", e.delay @@ -307,8 +363,8 @@ * @returns {undefined} */ function fetchBinary(p, f, n, m) { - if (!loadedBins[f]) { - loadedBins[f] = true; + if (!loadedBins[n]) { + loadedBins[n] = true; window.fetch(p + f).then( function resolve(response) { if (response.ok) { @@ -337,8 +393,8 @@ * @returns {undefined} */ function requestBinary(p, f, n, m) { - if (!loadedBins[f]) { - loadedBins[f] = true; + if (!loadedBins[n]) { + loadedBins[n] = true; const xhr = new XMLHttpRequest(); xhr.open("GET", p + f); xhr.onload = function onload() { @@ -349,7 +405,6 @@ xhr.send(); } } - if (H.clientFeat.wasm) { fetchBinary(path, fne, name, msg); } else { @@ -411,8 +466,8 @@ */ function loadRessources(lang) { let filename = lang + ".hpb"; - if (H.fallbacks && H.fallbacks[lang]) { - filename = H.fallbacks[lang] + ".hpb"; + if (H.lcFallbacks && H.lcFallbacks[lang]) { + filename = H.lcFallbacks[lang] + ".hpb"; } if (!H.binaries) { H.binaries = empty(); @@ -472,7 +527,7 @@ testDiv.lang = lang; testDiv.id = lang; testDiv.style.cssText = css; - testDiv.appendChild(d.createTextNode(H.require[lang])); + testDiv.appendChild(d.createTextNode(H.lcRequire[lang])); fakeBody.appendChild(testDiv); } @@ -524,7 +579,7 @@ * Hyphenopoly.hyphenators. * * Hyphenopoly.hyphenators. is a Promise that fullfills - * to hyphenate(lang, cn, entity) as soon as the ressources are loaded + * to hyphenate(entity, sel) as soon as the ressources are loaded * and the engine is ready. * If Promises aren't supported (e.g. IE11) a error message is produced. * @@ -544,7 +599,6 @@ } }, true); H.events.addListener("error", function handler(e) { - e.preventDefault(); if (e.key === lang || e.key === "hyphenEngine") { rj(e.msg); } @@ -568,8 +622,8 @@ } } - Object.keys(H.require).forEach(function doReqLangs(lang) { - if (H.require[lang] === "FORCEHYPHENOPOLY") { + Object.keys(H.lcRequire).forEach(function doReqLangs(lang) { + if (H.lcRequire[lang] === "FORCEHYPHENOPOLY") { H.clientFeat.polyfill = true; H.clientFeat.langs[lang] = "H9Y"; loadRessources(lang); @@ -586,8 +640,8 @@ }); const testContainer = tester.appendTests(d.documentElement); if (testContainer !== null) { - Object.keys(H.require).forEach(function checkReqLangs(lang) { - if (H.require[lang] !== "FORCEHYPHENOPOLY") { + Object.keys(H.lcRequire).forEach(function checkReqLangs(lang) { + if (H.lcRequire[lang] !== "FORCEHYPHENOPOLY") { const el = d.getElementById(lang); if (checkCSSHyphensSupport(el) && el.offsetHeight > 12) { H.clientFeat.langs[lang] = "CSS"; @@ -605,15 +659,21 @@ (function run() { if (H.clientFeat.polyfill) { - d.documentElement.style.visibility = "hidden"; - - H.setup.timeOutHandler = window.setTimeout(function timedOut() { - d.documentElement.style.visibility = "visible"; - H.events.dispatch("timeout", {"delay": H.setup.timeout}); - }, H.setup.timeout); + if (H.setup.hide === "all") { + H.toggle("off"); + } + if (H.setup.hide !== "none") { + H.setup.timeOutHandler = window.setTimeout(function timedOut() { + H.toggle("on"); + H.events.dispatch("timeout", {"delay": H.setup.timeout}); + }, H.setup.timeout); + } d.addEventListener( "DOMContentLoaded", function DCL() { + if (H.setup.hide !== "none" && H.setup.hide !== "all") { + H.toggle("off"); + } H.events.dispatch( "contentLoaded", {"msg": ["contentLoaded"]} diff --git a/README.md b/README.md index e6fde125..d9e8353d 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,11 @@ Hyphenopoly.js is a __JavaScript-polyfill for hyphenation in HTML__: it hyphenates text if the user agent does not support CSS-hyphenation at all or not for the required languages and it is a __Node.js-module__. The package consists of the following parts: -- _Hyphenopoly_Loader.js_ (~13KB unpacked, ~2.5KB minified and compressed): feature-checks the client and loads other resources if necessary. -- _Hyphenopoly.js_ (~30KB unpacked, ~4KB minified and compressed): does the whole DOM-foo and wraps (w)asm. +- _Hyphenopoly_Loader.js_ (~24KB unpacked, ~3KB minified and compressed): feature-checks the client and loads other resources if necessary. +- _Hyphenopoly.js_ (~41KB unpacked, ~4KB minified and compressed): does the whole DOM-foo and wraps (w)asm. - _hyphenEngine.wasm_ (~1KB uncompressed): wasm code for creating pattern trie and finding hyphenation points. -- _hyphenEngine.asm.js_ (~7KB uncompressed, ~1KB minified and compressed): fallback for clients that don't support wasm. -- _pattern.hpb_ (sizes differ! e.g. en-us.hpb: ~29KB): space saving binary format of the hyphenation patterns (including their license). +- _hyphenEngine.asm.js_ (~10KB uncompressed, ~1KB minified and compressed): fallback for clients that don't support wasm. +- _pattern.hpb_ (sizes differ! e.g. en-us.hpb: ~27KB uncompressed, ~16KB compressed): space saving binary format of the hyphenation patterns (including their license). - _hyphenopoly.module.js_: the node module # Usage (Browser) @@ -31,8 +31,8 @@ Also, don't forget to enable CSS hyphenation. "en-us": "Supercalifragilisticexpialidocious" }, setup: { - classnames: { - "container": {} + selectors: { + ".container": {} } } }; @@ -59,9 +59,10 @@ Also, don't forget to enable CSS hyphenation.

Example 1

-

Qua de causa Helvetii quoque reliquos Gallos virtute praecedunt, quod fere cotidianis proeliis cum Germanis contendunt, cum aut suis finibus eos prohibent aut ipsi in eorum finibus bellum gerunt.

-

For which reason the Helvetii also surpass the rest of the Gauls in valor, as they contend with the Germans in almost daily battles, when they either repel them from their own territories, or themselves wage war on their frontiers.

-

Aus diesem Grund übertreffen auch die Helvetier die übrigen Gallier an Tapferkeit, weil sie sich in fast täglichen Gefechten mit den Germanen messen, wobei sie diese entweder von ihrem Gebiet fernhalten oder selbst in deren Gebiet kämpfen.

+

Qua de causa Helvetii quoque reliquos Gallos virtute praecedunt, quod fere cotidianis proeliis cum Germanis contendunt, cum aut suis finibus eos prohibent aut ipsi in eorum finibus bellum gerunt.

+

For which reason the Helvetii also surpass the rest of the Gauls in valor, as they contend with the Germans in almost daily battles, when they either repel them from their own territories, or themselves wage war on their frontiers.

+

Aus diesem Grund übertreffen auch die Helvetier die übrigen Gallier an Tapferkeit, weil sie sich in fast täglichen Gefechten mit den Germanen messen, wobei sie diese entweder von ihrem Gebiet fernhalten oder selbst in deren Gebiet kämpfen.

+
``` @@ -76,7 +77,7 @@ Hyphenopoly_Loader.js needs some information to run. This information is provide ### require The `Hyphenopoly` object must have exactly one property called `require` which itself is an object containing at least one nameValuePair where the name is a language code string (Some patterns are region-specific. See the patterns directory for supported languages. E.g. just using `en` won't work, use either `en-us`or `en-gb`) and the value is a long word string in that language (preferably more than 12 characters long). -Hyphenator_Loader.js will feature test the client (aka browser, aka user agent) for CSS-hyphens support for the given languages with the given words respectively. In the example above it will test if the client supports CSS-hyphenation for latin. If your page contains more than just one language just add more lines. +Hyphenator_Loader.js will feature test the client (aka browser, aka user agent) for CSS-hyphens support for the given languages with the given words respectively. In the example above it will test if the client supports CSS-hyphenation for latin, german and us-english. If you want to force the usage of Hyphenopoly.js for a language (e.g. for testing purposes) write `"FORCEHYPHENOPOLY"` instead of the long word. diff --git a/example1.html b/example1.html index f6154fd9..8900d63d 100644 --- a/example1.html +++ b/example1.html @@ -15,8 +15,8 @@ maindir: "./" }, setup: { - classnames: { - "container": { + selectors: { + ".container": { } } } @@ -44,8 +44,9 @@

Example 1

-

Qua de causa Helvetii quoque reliquos Gallos virtute praecedunt, quod fere cotidianis proeliis cum Germanis contendunt, cum aut suis finibus eos prohibent aut ipsi in eorum finibus bellum gerunt.

-

For which reason the Helvetii also surpass the rest of the Gauls in valor, as they contend with the Germans in almost daily battles, when they either repel them from their own territories, or themselves wage war on their frontiers.

-

Aus diesem Grund übertreffen auch die Helvetier die übrigen Gallier an Tapferkeit, weil sie sich in fast täglichen Gefechten mit den Germanen messen, wobei sie diese entweder von ihrem Gebiet fernhalten oder selbst in deren Gebiet kämpfen.

+

Qua de causa Helvetii quoque reliquos Gallos virtute praecedunt, quod fere cotidianis proeliis cum Germanis contendunt, cum aut suis finibus eos prohibent aut ipsi in eorum finibus bellum gerunt.

+

For which reason the Helvetii also surpass the rest of the Gauls in valor, as they contend with the Germans in almost daily battles, when they either repel them from their own territories, or themselves wage war on their frontiers.

+

Aus diesem Grund übertreffen auch die Helvetier die übrigen Gallier an Tapferkeit, weil sie sich in fast täglichen Gefechten mit den Germanen messen, wobei sie diese entweder von ihrem Gebiet fernhalten oder selbst in deren Gebiet kämpfen.

+
- \ No newline at end of file + diff --git a/hyphenEngine.asm.js b/hyphenEngine.asm.js index b0762835..cf2e3345 100644 --- a/hyphenEngine.asm.js +++ b/hyphenEngine.asm.js @@ -1,5 +1,5 @@ /** - * @license hyphenEngine.asm.js 2.5.1 - client side hyphenation for webbrowsers + * @license hyphenEngine.asm.js 2.6.0 - client side hyphenation for webbrowsers * ©2018 Mathias Nater, Zürich (mathiasnater at gmail dot com) * https://github.com/mnater/Hyphenopoly * diff --git a/hyphenopoly.module.js b/hyphenopoly.module.js index 64a112be..768cf6c3 100644 --- a/hyphenopoly.module.js +++ b/hyphenopoly.module.js @@ -1,5 +1,5 @@ /** - * @license Hyphenopoly.module.js 2.5.1 - hyphenation for node + * @license Hyphenopoly.module.js 2.6.0 - hyphenation for node * ©2018 Mathias Nater, Zürich (mathiasnater at gmail dot com) * https://github.com/mnater/Hyphenopoly * diff --git a/package.json b/package.json index 04f72e45..57236b7e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hyphenopoly", - "version": "2.5.1", + "version": "2.6.0", "description": "Hyphenation for node and Polyfill for client-side hyphenation.", "keywords": [ "hyphenation", @@ -43,9 +43,9 @@ }, "dependencies": {}, "devDependencies": { - "eslint": "^5.6.1", - "tap": "^12.0.1", - "terser": "^3.9.2" + "eslint": "^5.9.0", + "tap": "^12.1.0", + "terser": "^3.10.13" }, "eslintConfig": { "parserOptions": { diff --git a/patterns/de.hpb b/patterns/de.hpb index 0e2ad0b6..ec9eac0c 100644 Binary files a/patterns/de.hpb and b/patterns/de.hpb differ diff --git a/testsuite/test10.html b/testsuite/test10.html index 928270fa..85c91155 100644 --- a/testsuite/test10.html +++ b/testsuite/test10.html @@ -13,6 +13,7 @@ patterndir: "../patterns/" }, setup: { + hide: "element", classnames: { "class1": { hyphen: "·" @@ -35,8 +36,8 @@ var ref = ""; var result = true; while (i <= tests) { - test = document.getElementById("test" + i).innerText; - ref = document.getElementById("ref" + i).innerText; + test = document.getElementById("test" + i).textContent; + ref = document.getElementById("ref" + i).textContent; if (test === ref) { document.getElementById("result").innerHTML += "

" + i + " passed

"; result = result && true; @@ -98,7 +99,7 @@

Test 010


1: class1

Silbentrennung: Die Worttrennung, auch Silbentrennung genannt, bezeichnet in der Orthographie die Art und Weise, wie die Wörter insbesondere am Zeilenende getrennt werden können.

-

Sil·ben·tren·nung: Die Wort­tren­nung, auch Sil­ben­tren­nung ge­nannt, be­zeich­net in der Or­tho­gra­phie die Art und Weise, wie die Wör­ter ins­be­son­de­re am Zei­len­en­de ge­trennt wer­den kön­nen.

+

Sil·ben·tren·nung: Die Wort­tren­nung, auch Sil­ben­tren­nung ge­nannt, be­zeich­net in der Or­tho­gra­phie die Art und Weise, wie die Wör­ter ins­be­son­de­re am Zei­len­en­de ge­trennt wer­den kön­nen.


Test Ref
diff --git a/testsuite/test12.html b/testsuite/test12.html index 425c0b92..42bb775c 100644 --- a/testsuite/test12.html +++ b/testsuite/test12.html @@ -14,9 +14,9 @@ }, setup: { dontHyphenate: { - code: true, kbd: false, - button: false + button: false, + span: true }, classnames: { "hyphenate": { @@ -94,8 +94,8 @@

Test 012

Check dontHyphenate-Elements


-

Silbentrennung Silbentrennung Silbentrennung

-

Sil•ben•tren•nung Silbentrennung Sil•ben•tren•nung

+

Silbentrennung Silbentrennung Silbentrennung Silbentrennung

+

Sil•ben•tren•nung Silbentrennung Sil•ben•tren•nung Silbentrennung


Test Ref
diff --git a/testsuite/test18.html b/testsuite/test18.html index c7e7455d..ae328dfa 100644 --- a/testsuite/test18.html +++ b/testsuite/test18.html @@ -38,10 +38,10 @@ test = document.getElementById("test" + i).innerHTML; ref = document.getElementById("ref" + i).innerHTML; if (test === ref) { - document.getElementById("result").innerHTML += "

" + i + " passed

"; + document.getElementById("result").innerHTML += "" + i + " "; result = result || true; } else { - document.getElementById("result").innerHTML += "

" + i + " failed

"; + document.getElementById("result").innerHTML += "" + i + " "; result = result || false; } i += 1; @@ -80,13 +80,6 @@ .ref { background-color: #FEEFC0; } - - .hyphenate { - hyphens: auto; - -ms-hyphens: auto; - -moz-hyphens: auto; - -webkit-hyphens: auto; - } diff --git a/testsuite/test26.html b/testsuite/test26.html index 2c89e494..5bca61ea 100644 --- a/testsuite/test26.html +++ b/testsuite/test26.html @@ -13,9 +13,12 @@ patterndir: "../patterns/" }, setup: { - classnames: { - "hyphenate": { + selectors: { + ".hyphenate": { hyphen: "•" + }, + ".usePipe": { + hyphen: "|" } } }, @@ -27,36 +30,21 @@ }*/ function hyphenate_de(text) { Hyphenopoly.hyphenators.de.then(function (dehyph) { - document.getElementById("test2").innerText = dehyph(text); + document.getElementById("test2").innerText = dehyph(text, ".usePipe"); assertAll(); }); } hyphenate_de("Silbentrennung verbessert den Blocksatz."); }, error: function (e) { - if (e.msg.indexOf("Promises not supported in this engine.") !== -1) { - assertError(); - } + assertError(e); } } }; - function assertError() { - var tests = 1; - var i = 1; - var test = ""; - var ref = ""; + function assertError(e) { var result = false; - while (i <= tests) { - test = document.getElementById("test" + i).innerHTML; - ref = document.getElementById("ref" + i).innerHTML; - if (test === ref) { - document.getElementById("result").innerHTML += "

" + i + " passed

"; - result = result || true; - } else { - document.getElementById("result").innerHTML += "

" + i + " failed

"; - result = result || false; - } - i += 1; + if (e.msg.indexOf("Promises not supported in this engine") !== -1) { + result = true; } if (parent != window) { parent.postMessage(JSON.stringify({ @@ -127,7 +115,7 @@

Test 026

Silbentrennungsalgorithmus

Sil•ben•tren•nungs•al•go•rith•mus

-

Sil•ben•tren•nung ver•bes•sert den Block•satz.

+

Sil|ben|tren|nung ver|bes|sert den Block|satz.


Test Ref
diff --git a/testsuite/test27.html b/testsuite/test27.html index b037bf28..036b10bf 100644 --- a/testsuite/test27.html +++ b/testsuite/test27.html @@ -35,39 +35,24 @@ hyphenate_fur("Il furlan e je une lenghe romanze de famee des lenghis retichis, che e je fevelade soredut intal Friûl, ma ancje vie pal mont. Cualchi volte al ven clamât Ladin orientâl, parcè che al à diviers ponts in comun cul ladin, ma si è svilupât in un altri mût cul passâ dal timp, sot de influence des lenghis ator dal Friûl"); }, error: function (e) { - if (e.msg.indexOf("Promises not supported in this engine.") !== -1) { - assertError(); - } + assertError(e); } } }; - function assertError() { - var tests = 1; - var i = 1; - var test = ""; - var ref = ""; - var result = false; - while (i <= tests) { - test = document.getElementById("test" + i).innerHTML; - ref = document.getElementById("ref" + i).innerHTML; - if (test === ref) { - document.getElementById("result").innerHTML += "

" + i + " passed

"; - result = result || true; - } else { - document.getElementById("result").innerHTML += "

" + i + " failed

"; - result = result || false; + function assertError(e) { + var result = false; + if (e.msg.indexOf("Promises not supported in this engine") !== -1) { + result = true; + } + if (parent != window) { + parent.postMessage(JSON.stringify({ + desc: document.getElementById("desc").innerHTML, + index: 27, + result: (result ? "passed" : "failed") + }), window.location.href); } - i += 1; - } - if (parent != window) { - parent.postMessage(JSON.stringify({ - desc: document.getElementById("desc").innerHTML, - index: 26, - result: (result ? "passed" : "failed") - }), window.location.href); } - } function assertAll() { var tests = 1; var i = 1; diff --git a/testsuite/test28.html b/testsuite/test28.html new file mode 100644 index 00000000..b4a161d7 --- /dev/null +++ b/testsuite/test28.html @@ -0,0 +1,116 @@ + + + + + Test 028 + + + + + + + + +

Test 028

+

See what hiding does (change mode and reload to see flicker)

+ +

+
+

Hyphenation

+

Hyphenation

+ +
+ + + \ No newline at end of file diff --git a/testsuite/test29.html b/testsuite/test29.html new file mode 100644 index 00000000..a069253f --- /dev/null +++ b/testsuite/test29.html @@ -0,0 +1,118 @@ + + + + + Test 029 + + + + + + + +

Test 029

+

Check case-insensitiveness of lang attributes and fallbacks.

+
R:
+
+

1: en-us

+

A hyphenation algorithm is a set of rules that decides at which points a word can be broken over two lines with a hyphen.

+

A hy|phen|ation al|go|rithm is a set of rules that de|cides at which points a word can be bro|ken over two lines with a hy|phen.

+ +

2: en-US

+

A hyphenation algorithm is a set of rules that decides at which points a word can be broken over two lines with a hyphen.

+

A hy|phen|ation al|go|rithm is a set of rules that de|cides at which points a word can be bro|ken over two lines with a hy|phen.

+ +

3: en-au (fallback to en-gb)

+

A hyphenation algorithm is a set of rules that decides at which points a word can be broken over two lines with a hyphen.

+

A hy|phen|a|tion al|gorithm is a set of rules that de|cides at which points a word can be broken over two lines with a hy|phen.

+ +

4: en-AU (fallback to en-gb)

+

A hyphenation algorithm is a set of rules that decides at which points a word can be broken over two lines with a hyphen.

+

A hy|phen|a|tion al|gorithm is a set of rules that de|cides at which points a word can be broken over two lines with a hy|phen.

+ +

5: de

+

Die Worttrennung, auch Silbentrennung genannt, bezeichnet in der Orthographie die Art und Weise, wie die Wörter insbesondere am Zeilenende getrennt werden können.

+

Die Wort|tren|nung, auch Sil|ben|tren|nung ge|nannt, be|zeich|net in der Or|tho|gra|phie die Art und Weise, wie die Wör|ter ins|be|son|de|re am Zei|len|en|de ge|trennt wer|den kön|nen.

+ +

6: de-CH (fallback to de)

+

Die Worttrennung, auch Silbentrennung genannt, bezeichnet in der Orthographie die Art und Weise, wie die Wörter insbesondere am Zeilenende getrennt werden können.

+

Die Wort|tren|nung, auch Sil|ben|tren|nung ge|nannt, be|zeich|net in der Or|tho|gra|phie die Art und Weise, wie die Wör|ter ins|be|son|de|re am Zei|len|en|de ge|trennt wer|den kön|nen.

+
+
Test Ref
+ + \ No newline at end of file diff --git a/testsuite/test30.html b/testsuite/test30.html new file mode 100644 index 00000000..2650e1cc --- /dev/null +++ b/testsuite/test30.html @@ -0,0 +1,111 @@ + + + + + Test 030 + + + + + + + +

Test 030

+

Select elements with selectors instead of classes.

+
R:
+
+

1: use classname to select

+

A hyphenation algorithm is a set of rules that decides at which points a word can be broken over two lines with a hyphen.

+

A hy|phen|ation al|go|rithm is a set of rules that de|cides at which points a word can be bro|ken over two lines with a hy|phen.

+

2: use id to select

+

A hyphenation algorithm is a set of rules that decides at which points a word can be broken over two lines with a hyphen.

+

A hy•phen•ation al•go•rithm is a set of rules that de•cides at which points a word can be bro•ken over two lines with a hy•phen.

+

3: use element and id to select

+

A hyphenation algorithm is a set of rules that decides at which points a word can be broken over two lines with a hyphen.

+

A hy·phen·ation al·go·rithm is a set of rules that de·cides at which points a word can be bro·ken over two lines with a hy·phen.

+

4: use siblings to select

+

A hyphenation algorithm is a set of rules that decides at which points a word can be broken over two lines with a hyphen.

+

A hy⁄phen⁄ation al⁄go⁄rithm is a set of rules that de⁄cides at which points a word can be bro⁄ken over two lines with a hy⁄phen.

+
+
Test Ref
+ + \ No newline at end of file diff --git a/testsuite/test5.html b/testsuite/test5.html index 36d3c0b0..b99a159f 100644 --- a/testsuite/test5.html +++ b/testsuite/test5.html @@ -28,10 +28,14 @@ "ca": "FORCEHYPHENOPOLY", "sk": "FORCEHYPHENOPOLY", "eo": "FORCEHYPHENOPOLY", + "sr-latn": "FORCEHYPHENOPOLY", "ro": "FORCEHYPHENOPOLY", "et": "FORCEHYPHENOPOLY", "ga": "FORCEHYPHENOPOLY" }, + fallbacks: { + "sr-latn": "sh-latn" + }, paths: { maindir: "../", patterndir: "../patterns/" @@ -58,20 +62,18 @@ var ref = ""; var result = true; while (i <= tests) { - if (i !== 23) { - test = document.getElementById("test" + i).innerHTML; - ref = document.getElementById("ref" + i).innerHTML; - if (test === ref) { - document.getElementById("result").innerHTML += "" + (function (i) { - return (i < 10) ? "0" + i : i; - }(i)) + " "; - result = result && true; - } else { - document.getElementById("result").innerHTML += "" + (function (i) { - return (i < 10) ? "0" + i : i; - }(i)) + " "; - result = false; - } + test = document.getElementById("test" + i).innerHTML; + ref = document.getElementById("ref" + i).innerHTML; + if (test === ref) { + document.getElementById("result").innerHTML += "" + (function (i) { + return (i < 10) ? "0" + i : i; + }(i)) + " "; + result = result && true; + } else { + document.getElementById("result").innerHTML += "" + (function (i) { + return (i < 10) ? "0" + i : i; + }(i)) + " "; + result = false; } i += 1; } @@ -106,7 +108,7 @@

Test 005

Hyphenate a paragraph for each supported language in latin-script.

-
+
R:

1: cs

Typografie je umělecko-technický obor, který se zabývá písmem.

@@ -181,9 +183,9 @@

21: sk

22: eo

Tipografio unuavice estas la kreo de komunikaĵo per reproduktebla skribo, sed duavice ankaŭ la dezajno de tia skriba komunikaĵo per linioj, areoj kaj la specifa aranĝo de literoj.

Ti|po|gra|fio unu|a|vi|ce estas la kreo de ko|mu|ni|k|aĵo per re|pro|duk|t|ebla skri|bo, sed du|a|vi|ce ankaŭ la de|zaj|no de tia skri|ba ko|mu|ni|k|aĵo per li|ni|oj, areoj kaj la spe|ci|fa aran|ĝo de li|te|roj.

- +

Ti|po|gra|fi|ja se bavi iz|bo|rom i or|ga|ni|za|ci|jom obli|ka slova i dru|gih gra|fič|kih ka|rak|te|ri|sti|ka štam|pa|ne stra|ne.

24: ro

Tipografia reprezintă arta și tehnica tipăritului, a formei și aranjării literelor pe un document scris.

Ti|po|gra|fia re|pre|zin|tă arta și teh|ni|ca ti|pă|ri|tu|lui, a for|mei și aran|jă|rii li|te|re|lor pe un do|cu|ment scris.

diff --git a/testsuite/testdriver.js b/testsuite/testdriver.js index a9ae1d92..e99915e9 100644 --- a/testsuite/testdriver.js +++ b/testsuite/testdriver.js @@ -32,7 +32,10 @@ {exec: true, path: "test24.html"}, {exec: true, path: "test25.html"}, {exec: true, path: "test26.html"}, - {exec: true, path: "test27.html"} + {exec: true, path: "test27.html"}, + {exec: true, path: "test28.html"}, + {exec: true, path: "test29.html"}, + {exec: true, path: "test30.html"} ]; var testframe = document.getElementById("testframe"); var currentTest = 1;