https://iesvcentenario.org/plugins/content/admirorcolumnizer/admirorcolumnizer/scripts/Hyphenator.js
1/** @license Hyphenator 4.0.0 - client side hyphenation for webbrowsers 2 * Copyright (C) 2011 Mathias Nater, Zürich (mathias at mnn dot ch) 3 * Project and Source hosted on http://code.google.com/p/hyphenator/ 4 * 5 * This JavaScript code is free software: you can redistribute 6 * it and/or modify it under the terms of the GNU Lesser 7 * General Public License (GNU LGPL) as published by the Free Software 8 * Foundation, either version 3 of the License, or (at your option) 9 * any later version. The code is distributed WITHOUT ANY WARRANTY; 10 * without even the implied warranty of MERCHANTABILITY or FITNESS 11 * FOR A PARTICULAR PURPOSE. See the GNU GPL for more details. 12 * 13 * As additional permission under GNU GPL version 3 section 7, you 14 * may distribute non-source (e.g., minimized or compacted) forms of 15 * that code without the copy of the GNU GPL normally required by 16 * section 4, provided you include this license notice and a URL 17 * through which recipients can access the Corresponding Source. 18 * 19 * 20 * Hyphenator.js contains code from Bram Steins hypher.js-Project: 21 * https://github.com/bramstein/Hypher 22 * 23 * Code from this project is marked in the source and belongs 24 * to the following license: 25 * 26 * Copyright (c) 2011, Bram Stein 27 * All rights reserved. 28 * 29 * Redistribution and use in source and binary forms, with or without 30 * modification, are permitted provided that the following conditions 31 * are met: 32 * 33 * 1. Redistributions of source code must retain the above copyright 34 * notice, this list of conditions and the following disclaimer. 35 * 2. Redistributions in binary form must reproduce the above copyright 36 * notice, this list of conditions and the following disclaimer in the 37 * documentation and/or other materials provided with the distribution. 38 * 3. The name of the author may not be used to endorse or promote products 39 * derived from this software without specific prior written permission. 40 * 41 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED 42 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 43 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 44 * EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 45 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 46 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 47 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 48 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 49 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 50 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 51 * 52 */ 53 54/* 55 * Comments are jsdoctoolkit formatted. See http://code.google.com/p/jsdoc-toolkit/ 56 */ 57 58/* The following comment is for JSLint: */ 59/*global window, ActiveXObject, unescape */ 60/*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, regexp: true, sub: true, newcap: true, immed: true, evil: true, eqeqeq: false */ 61 62 63/** 64 * @constructor 65 * @description Provides all functionality to do hyphenation, except the patterns that are loaded 66 * externally. 67 * @author Mathias Nater, <a href = "mailto:[email protected]">[email protected]</a> 68 * @version X.Y.Z 69 * @namespace Holds all methods and properties 70 * @example 71 * <script src = "Hyphenator.js" type = "text/javascript"></script> 72 * <script type = "text/javascript"> 73 * Hyphenator.run(); 74 * </script> 75 */ 76var Hyphenator = (function (window) { 77 78 var 79 /** 80 * @name Hyphenator-supportedLang 81 * @description 82 * A key-value object that stores supported languages. 83 * The key is the bcp47 code of the language and the value 84 * is the (abbreviated) filename of the pattern file. 85 * @type {Object.<string, string>} 86 * @private 87 * @example 88 * Check if language lang is supported: 89 * if (supportedLang.hasOwnProperty(lang)) 90 */ 91 supportedLang = { 92 'sr-yu': 'sr-yu.js', 93 'be': 'be.js', 94 'ca': 'ca.js', 95 'cs': 'cs.js', 96 'da': 'da.js', 97 'bn': 'bn.js', 98 'de': 'de.js', 99 'el': 'el-monoton.js', 100 'el-monoton': 'el-monoton.js', 101 'el-polyton': 'el-polyton.js', 102 'en': 'en-us.js', 103 'en-gb': 'en-gb.js', 104 'en-us': 'en-us.js', 105 'es': 'es.js', 106 'fi': 'fi.js', 107 'fr': 'fr.js', 108 'grc': 'grc.js', 109 'gu': 'gu.js', 110 'hi': 'hi.js', 111 'hu': 'hu.js', 112 'hy': 'hy.js', 113 'it': 'it.js', 114 'kn': 'kn.js', 115 'la': 'la.js', 116 'lt': 'lt.js', 117 'lv': 'lv.js', 118 'ml': 'ml.js', 119 'nb': 'nb-no.js', 120 'no': 'nb-no.js', 121 'nb-no': 'nb-no.js', 122 'nl': 'nl.js', 123 'or': 'or.js', 124 'pa': 'pa.js', 125 'pl': 'pl.js', 126 'pt': 'pt.js', 127 'ru': 'ru.js', 128 'sk': 'sk.js', 129 'sl': 'sl.js', 130 'sv': 'sv.js', 131 'ta': 'ta.js', 132 'te': 'te.js',
133 'tr': 'tr.js', 134 'uk': 'uk.js' 135 }, 136 137 /** 138 * @name Hyphenator-languageHint 139 * @description 140 * An automatically generated string to be displayed in a prompt if the language can't be guessed. 141 * The string is generated using the supportedLang-object. 142 * @see Hyphenator-supportedLang 143 * @type {string} 144 * @private 145 * @see Hyphenator-autoSetMainLanguage 146 */ 147 148 languageHint = (function () { 149 var k, r = ''; 150 for (k in supportedLang) { 151 if (supportedLang.hasOwnProperty(k)) { 152 r += k + ', '; 153 } 154 } 155 r = r.substring(0, r.length - 2); 156 return r; 157 }()), 158 159 /** 160 * @name Hyphenator-prompterStrings 161 * @description 162 * A key-value object holding the strings to be displayed if the language can't be guessed 163 * If you add hyphenation patterns change this string. 164 * @type {Object.<string,string>} 165 * @private 166 * @see Hyphenator-autoSetMainLanguage 167 */ 168 prompterStrings = { 169 'be': 'Ðова гÑÑага ÑайÑа не можа бÑÑÑ Ð²ÑзнаÑÐ°Ð½Ñ Ð°ÑÑамаÑÑÑна. ÐÐ°Ð»Ñ Ð»Ð°Ñка пакажÑÑе мовÑ:', 170 'cs': 'Jazyk této internetové stránky nebyl automaticky rozpoznán. UrÄete prosÃm jejà jazyk:', 171 'da': 'Denne websides sprog kunne ikke bestemmes. Angiv venligst sprog:', 172 'de': 'Die Sprache dieser Webseite konnte nicht automatisch bestimmt werden. Bitte Sprache angeben:', 173 'en': 'The language of this website could not be determined automatically. Please indicate the main language:', 174 'es': 'El idioma del sitio no pudo determinarse autom%E1ticamente. Por favor, indique el idioma principal:', 175 'fi': 'Sivun kielt%E4 ei tunnistettu automaattisesti. M%E4%E4rit%E4 sivun p%E4%E4kieli:', 176 'fr': 'La langue de ce site n%u2019a pas pu %EAtre d%E9termin%E9e automatiquement. Veuillez indiquer une langue, s.v.p.%A0:', 177 'hu': 'A weboldal nyelvét nem sikerült automatikusan megállapÃtani. Kérem adja meg a nyelvet:', 178 'hy': 'ÕÕ°Õ¡Õ»Õ¸Õ²Õ¾Õ¥Ö Õ°Õ¡ÕµÕ¿Õ¶Õ¡Õ¢Õ¥ÖÕ¥Õ¬ Õ¡ÕµÕ½ Õ¯Õ¡ÕµÖÕ« Õ¬Õ¥Õ¦Õ¸ÖÕ¶Ö Ô½Õ¶Õ¤ÖÕ¸ÖÕ´ Õ¥Õ¶Ö Õ¶Õ·Õ¥Ö Õ°Õ«Õ´Õ¶Õ¡Õ¯Õ¡Õ¶ Õ¬Õ¥Õ¦Õ¸ÖÕ¶Õ', 179 'it': 'Lingua del sito sconosciuta. Indicare una lingua, per favore:', 180 'kn': 'à²à²¾à²² ತಾಣದ à²à²¾à²·à³à²¯à²¨à³à²¨à³ ನಿರà³à²§à²°à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²à³à²¤à³à²¤à²¿à²²à³à²². ದಯವಿà²à³à²à³ ಮà³à²à³à²¯ à²à²¾à²·à³à²¯à²¨à³à²¨à³ ಸà³à²à²¿à²¸à²¿:', 181 'lt': 'Nepavyko automatiÅ¡kai nustatyti Å¡ios svetainÄs kalbos. PraÅ¡ome įvesti kalbÄ :', 182 'lv': 'Å Ä«s lapas valodu nevarÄja noteikt automÄtiski. LÅ«dzu norÄdiet pamata valodu:', 183 'ml': 'à´ à´µàµ%u0D2C%u0D4D%u200Cà´¸àµà´±àµà´±à´¿à´¨àµà´±àµ à´à´¾à´· à´à´£àµà´àµà´ªà´¿à´à´¿à´¯àµà´àµà´à´¾%u0D28%u0D4D%u200D à´à´´à´¿à´àµà´à´¿à´²àµà´². à´à´¾à´· à´à´¤à´¾à´£àµà´¨àµà´¨àµ തിരà´àµà´àµà´àµà´àµà´àµà´:', 184 'nl': 'De taal van deze website kan niet automatisch worden bepaald. Geef de hoofdtaal op:', 185 'no': 'Nettstedets sprÃ¥k kunne ikke finnes automatisk. Vennligst oppgi sprÃ¥k:', 186 'pt': 'A lÃngua deste site não pôde ser determinada automaticamente. Por favor indique a lÃngua principal:', 187 'ru': 'ЯзÑк ÑÑого ÑайÑа не Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¾Ð¿Ñеделен авÑомаÑиÑеÑки. ÐожалÑйÑÑа ÑкажиÑе ÑзÑк:', 188 'sl': 'Jezika te spletne strani ni bilo mogoÄe samodejno doloÄiti. Prosim navedite jezik:', 189 'sv': 'Spr%E5ket p%E5 den h%E4r webbplatsen kunde inte avg%F6ras automatiskt. V%E4nligen ange:', 190 'tr': 'Bu web sitesinin dili otomatik olarak tespit edilememiÅtir. Lütfen dökümanın dilini seçiniz%A0:', 191 'uk': 'Ðова ÑÑого веб-ÑайÑÑ Ð½Ðµ може бÑÑи визнаÑена авÑомаÑиÑно. ÐÑÐ´Ñ Ð»Ð°Ñка, вкажÑÑÑ Ð³Ð¾Ð»Ð¾Ð²Ð½Ñ Ð¼Ð¾Ð²Ñ:' 192 }, 193 194 /** 195 * @name Hyphenator-basePath 196 * @description 197 * A string storing the basepath from where Hyphenator.js was loaded. 198 * This is used to load the patternfiles. 199 * The basepath is determined dynamically by searching all script-tags for Hyphenator.js 200 * If the path cannot be determined http://hyphenator.googlecode.com/svn/trunk/ is used as fallback. 201 * @type {string} 202 * @private 203 * @see Hyphenator-loadPatterns 204 */ 205 basePath = (function () { 206 var s = document.getElementsByTagName('script'), i = 0, p, src, t; 207 while (!!(t = s[i++])) { 208 if (!t.src) { 209 continue; 210 } 211 src = t.src; 212 p = src.indexOf('Hyphenator.js'); 213 if (p !== -1) { 214 return src.substring(0, p); 215 } 216 } 217 return 'http://hyphenator.googlecode.com/svn/trunk/'; 218 }()), 219 220 /** 221 * @name Hyphenator-isLocal 222 * @description 223 * isLocal is true, if Hyphenator is loaded from the same domain, as the webpage, but false, if 224 * it's loaded from an external source (i.e. directly from google.code) 225 */ 226 isLocal = (function () { 227 var re = false;
228 if (window.location.href.indexOf(basePath) !== -1) { 229 re = true; 230 } 231 return re; 232 }()), 233 234 /** 235 * @name Hyphenator-documentLoaded 236 * @description 237 * documentLoaded is true, when the DOM has been loaded. This is set by runOnContentLoaded 238 */ 239 documentLoaded = false, 240 documentCount = 0, 241 242 /** 243 * @name Hyphenator-persistentConfig 244 * @description 245 * if persistentConfig is set to true (defaults to false), config options and the state of the 246 * toggleBox are stored in DOM-storage (according to the storage-setting). So they haven't to be 247 * set for each page. 248 */ 249 persistentConfig = false, 250 251 /** 252 * @name Hyphenator-contextWindow 253 * @description 254 * contextWindow stores the window for the document to be hyphenated. 255 * If there are frames this will change. 256 * So use contextWindow instead of window! 257 */ 258 contextWindow = window, 259 260 /** 261 * @name Hyphenator-doFrames 262 * @description 263 * switch to control if frames/iframes should be hyphenated, too 264 * defaults to false (frames are a bag of hurt!) 265 */ 266 doFrames = false, 267 268 /** 269 * @name Hyphenator-dontHyphenate 270 * @description 271 * A key-value object containing all html-tags whose content should not be hyphenated 272 * @type {Object.<string,boolean>} 273 * @private 274 * @see Hyphenator-hyphenateElement 275 */ 276 dontHyphenate = {'script': true, 'code': true, 'pre': true, 'img': true, 'br': true, 'samp': true, 'kbd': true, 'var': true, 'abbr': true, 'acronym': true, 'sub': true, 'sup': true, 'button': true, 'option': true, 'label': true, 'textarea': true, 'input': true, 'math': true, 'svg': true}, 277 278 /** 279 * @name Hyphenator-enableCache 280 * @description 281 * A variable to set if caching is enabled or not 282 * @type boolean 283 * @default true 284 * @private 285 * @see Hyphenator.config 286 * @see hyphenateWord 287 */ 288 enableCache = true, 289 290 /** 291 * @name Hyphenator-storageType 292 * @description 293 * A variable to define what html5-DOM-Storage-Method is used ('none', 'local' or 'session') 294 * @type {string} 295 * @default 'none' 296 * @private 297 * @see Hyphenator.config 298 */ 299 storageType = 'local', 300 301 /** 302 * @name Hyphenator-storage 303 * @description 304 * An alias to the storage-Method defined in storageType. 305 * Set by Hyphenator.run() 306 * @type {Object|undefined} 307 * @default null 308 * @private 309 * @see Hyphenator.run 310 */ 311 storage, 312 313 /** 314 * @name Hyphenator-enableReducedPatternSet 315 * @description 316 * A variable to set if storing the used patterns is set 317 * @type boolean 318 * @default false 319 * @private 320 * @see Hyphenator.config 321 * @see hyphenateWord 322 * @see Hyphenator.getRedPatternSet 323 */ 324 enableReducedPatternSet = false, 325 326 /** 327 * @name Hyphenator-enableRemoteLoading 328 * @description 329 * A variable to set if pattern files should be loaded remotely or not 330 * @type boolean 331 * @default true 332 * @private 333 * @see Hyphenator.config 334 * @see Hyphenator-loadPatterns 335 */ 336 enableRemoteLoading = true, 337 338 /** 339 * @name Hyphenator-displayToggleBox 340 * @description 341 * A variable to set if the togglebox should be displayed or not 342 * @type boolean 343 * @default false 344 * @private 345 * @see Hyphenator.config 346 * @see Hyphenator-toggleBox 347 */ 348 displayToggleBox = false, 349 350 /** 351 * @name Hyphenator-css3 352 * @description 353 * A variable to set if css3 hyphenation should be used 354 * @type boolean 355 * @default false 356 * @private 357 * @see Hyphenator.config 358 */ 359 css3 = false, 360 /** 361 * @name Hyphenator-css3_hsupport 362 * @description 363 * A generated object containing information for CSS3-hyphenation support 364 * { 365 * support: boolean, 366 * property: <the property name to access hyphen-settings>, 367 * languages: <an object containing supported languages> 368 * } 369 * @type object 370 * @default undefined 371 * @private 372 * @see Hyphenator-css3_gethsupport 373 */ 374 css3_h9n, 375 /** 376 * @name Hyphenator-css3_gethsupport 377 * @description 378 * This function sets Hyphenator-css3_h9n for the current UA 379 * @type function 380 * @private 381 * @see Hyphenator-css3_h9n 382 */ 383 css3_gethsupport = function () { 384 var s, 385 ua = navigator.userAgent, 386 r = { 387 support: false, 388 property: '', 389 languages: {} 390 }; 391 if (window.getComputedStyle) { 392 s = window.getComputedStyle(window.document.getElementsByTagName('body')[0]); 393 } else { 394 //ancient Browser don't support CSS3 anyway 395 css3_h9n = r; 396 return; 397 } 398 if (ua.indexOf('Chrome') !== -1) { 399 //Chrome actually knows -webkit-hyphens but does no hyphenation 400 r.support = false;
401 } else if ((ua.indexOf('Safari') !== -1) && (s['-webkit-hyphens'] !== undefined)) { 402 r.support = true; 403 r.property = '-webkit-hyphens'; 404 if (ua.indexOf('Mobile') !== -1) { 405 //iOS only hyphenates in systemlanguage 406 r.languages[navigator.language.split('-')[0]] = true; 407 } else { 408 //Desktop Safari only hyphenates some languages: 409 r.languages = { 410 de: true, 411 en: true, 412 es: true, 413 fr: true, 414 it: true, 415 nl: true, 416 ru: true, 417 zh: true 418 }; 419 } 420 } else if ((ua.indexOf('Firefox') !== -1) && (s['MozHyphens'] !== undefined)) { 421 r.support = true; 422 r.property = 'MozHyphens'; 423 r.languages = { 424 en: true 425 }; 426 } 427 css3_h9n = r; 428 }, 429 430 /** 431 * @name Hyphenator-hyphenateClass 432 * @description 433 * A string containing the css-class-name for the hyphenate class 434 * @type {string} 435 * @default 'hyphenate' 436 * @private 437 * @example 438 * <p class = "hyphenate">Text</p> 439 * @see Hyphenator.config 440 */ 441 hyphenateClass = 'hyphenate', 442 443 /** 444 * @name Hyphenator-dontHyphenateClass 445 * @description 446 * A string containing the css-class-name for elements that should not be hyphenated 447 * @type {string} 448 * @default 'donthyphenate' 449 * @private 450 * @example 451 * <p class = "donthyphenate">Text</p> 452 * @see Hyphenator.config 453 */ 454 dontHyphenateClass = 'donthyphenate', 455 456 /** 457 * @name Hyphenator-min 458 * @description 459 * A number wich indicates the minimal length of words to hyphenate. 460 * @type {number} 461 * @default 6 462 * @private 463 * @see Hyphenator.config 464 */ 465 min = 6, 466 467 /** 468 * @name Hyphenator-orphanControl 469 * @description 470 * Control how the last words of a line are handled: 471 * level 1 (default): last word is hyphenated 472 * level 2: last word is not hyphenated 473 * level 3: last word is not hyphenated and last space is non breaking 474 * @type {number} 475 * @default 1 476 * @private 477 */ 478 orphanControl = 1, 479 480 /** 481 * @name Hyphenator-isBookmarklet 482 * @description 483 * Indicates if Hyphanetor runs as bookmarklet or not. 484 * @type boolean 485 * @default false 486 * @private 487 */ 488 isBookmarklet = (function () { 489 var loc = null, re = false, jsArray = document.getElementsByTagName('script'), i, l; 490 for (i = 0, l = jsArray.length; i < l; i++) { 491 if (!!jsArray[i].getAttribute('src')) { 492 loc = jsArray[i].getAttribute('src'); 493 } 494 if (!loc) { 495 continue; 496 } else if (loc.indexOf('Hyphenator.js?bm=true') !== -1) { 497 re = true; 498 } 499 } 500 return re; 501 }()), 502 503 /** 504 * @name Hyphenator-mainLanguage 505 * @description 506 * The general language of the document. In contrast to {@link Hyphenator-defaultLanguage}, 507 * mainLanguage is defined by the client (i.e. by the html or by a prompt). 508 * @type {string|null} 509 * @private 510 * @see Hyphenator-autoSetMainLanguage 511 */ 512 mainLanguage = null, 513 514 /** 515 * @name Hyphenator-defaultLanguage 516 * @description 517 * The language defined by the developper. This language setting is defined by a config option. 518 * It is overwritten by any html-lang-attribute and only taken in count, when no such attribute can 519 * be found (i.e. just before the prompt). 520 * @type {string|null} 521 * @private 522 * @see Hyphenator-autoSetMainLanguage 523 */ 524 defaultLanguage = '', 525 526 527 /** 528 * @name Hyphenator-elements 529 * @description 530 * An array holding all elements that have to be hyphenated. This var is filled by 531 * {@link Hyphenator-gatherDocumentInfos} 532 * @type {Array} 533 * @private 534 */ 535 elements = (function () { 536 var Element = function (element, data) { 537 this.element = element; 538 this.hyphenated = false; 539 this.treated = false; //collected but not hyphenated (dohyphenation is off) 540 this.data = data; 541 }, 542 ElementCollection = function () { 543 this.count = 0; 544 this.hyCount = 0; 545 this.list = {}; 546 }; 547 ElementCollection.prototype = { 548 add: function (el, lang, data) { 549 if (!this.list.hasOwnProperty(lang)) { 550 this.list[lang] = []; 551 } 552 this.list[lang].push(new Element(el, data)); 553 this.count += 1; 554 }, 555 each: function (fn) { 556 var k; 557 for (k in this.list) { 558 if (this.list.hasOwnProperty(k)) { 559 fn(k, this.list[k]); 560 } 561 } 562 } 563 }; 564 return new ElementCollection(); 565 }()), 566 567 568 /** 569 * @name Hyphenator-exceptions 570 * @description
571 * An object containing exceptions as comma separated strings for each language. 572 * When the language-objects are loaded, their exceptions are processed, copied here and then deleted. 573 * @see Hyphenator-prepareLanguagesObj 574 * @type {Object} 575 * @private 576 */ 577 exceptions = {}, 578 579 /** 580 * @name Hyphenator-docLanguages 581 * @description 582 * An object holding all languages used in the document. This is filled by 583 * {@link Hyphenator-gatherDocumentInfos} 584 * @type {Object} 585 * @private 586 */ 587 docLanguages = {}, 588 589 /** 590 * @name Hyphenator-state 591 * @description 592 * A number that inidcates the current state of the script 593 * 0: not initialized 594 * 1: loading patterns 595 * 2: ready 596 * 3: hyphenation done 597 * 4: hyphenation removed 598 * @type {number} 599 * @private 600 */ 601 state = 0, 602 603 /** 604 * @name Hyphenator-url 605 * @description 606 * A string containing a RegularExpression to match URL's 607 * @type {string} 608 * @private 609 */ 610 url = '(\\w*:\/\/)?((\\w*:)?(\\w*)@)?((([\\d]{1,3}\\.){3}([\\d]{1,3}))|((www\\.|[a-zA-Z]\\.)?[a-zA-Z0-9\\-\\.]+\\.([a-z]{2,4})))(:\\d*)?(\/[\\w#!:\\.?\\+=&%@!\\-]*)*', 611 // protocoll usr pwd ip or host tld port path 612 /** 613 * @name Hyphenator-mail 614 * @description 615 * A string containing a RegularExpression to match mail-adresses 616 * @type {string} 617 * @private 618 */ 619 mail = '[\\w-\\.]+@[\\w\\.]+', 620 621 /** 622 * @name Hyphenator-urlRE 623 * @description 624 * A RegularExpressions-Object for url- and mail adress matching 625 * @type {RegExp} 626 * @private 627 */ 628 urlOrMailRE = new RegExp('(' + url + ')|(' + mail + ')', 'i'), 629 630 /** 631 * @name Hyphenator-zeroWidthSpace 632 * @description 633 * A string that holds a char. 634 * Depending on the browser, this is the zero with space or an empty string. 635 * zeroWidthSpace is used to break URLs 636 * @type {string} 637 * @private 638 */ 639 zeroWidthSpace = (function () { 640 var zws, ua = navigator.userAgent.toLowerCase(); 641 zws = String.fromCharCode(8203); //Unicode zero width space 642 if (ua.indexOf('msie 6') !== -1) { 643 zws = ''; //IE6 doesn't support zws 644 } 645 if (ua.indexOf('opera') !== -1 && ua.indexOf('version/10.00') !== -1) { 646 zws = ''; //opera 10 on XP doesn't support zws 647 } 648 return zws; 649 }()), 650 651 /** 652 * @name Hyphenator-createElem 653 * @description 654 * A function alias to document.createElementNS or document.createElement 655 * @type {function(string, Object)} 656 * @private 657 */ 658 createElem = function (tagname, context) { 659 context = context || contextWindow; 660 if (document.createElementNS) { 661 return context.document.createElementNS('http://www.w3.org/1999/xhtml', tagname); 662 } else if (document.createElement) { 663 return context.document.createElement(tagname); 664 } 665 }, 666 667 /** 668 * @name Hyphenator-onHyphenationDone 669 * @description 670 * A method to be called, when the last element has been hyphenated or the hyphenation has been 671 * removed from the last element. 672 * @see Hyphenator.config 673 * @type {function()} 674 * @private 675 */ 676 onHyphenationDone = function () {}, 677 678 /** 679 * @name Hyphenator-onError 680 * @description 681 * A function that can be called upon an error. 682 * @see Hyphenator.config 683 * @type {function(Object)} 684 * @private 685 */ 686 onError = function (e) { 687 window.alert("Hyphenator.js says:\n\nAn Error ocurred:\n" + e.message); 688 }, 689 690 /** 691 * @name Hyphenator-selectorFunction 692 * @description 693 * A function that has to return a HTMLNodeList of Elements to be hyphenated. 694 * By default it uses the classname ('hyphenate') to select the elements. 695 * @see Hyphenator.config 696 * @type {function()} 697 * @private 698 */ 699 selectorFunction = function () { 700 var tmp, el = [], i, l; 701 if (document.getElementsByClassName) { 702 el = contextWindow.document.getElementsByClassName(hyphenateClass); 703 } else { 704 tmp = contextWindow.document.getElementsByTagName('*'); 705 l = tmp.length; 706 for (i = 0; i < l; i++) 707 {
708 if (tmp[i].className.indexOf(hyphenateClass) !== -1 && tmp[i].className.indexOf(dontHyphenateClass) === -1) { 709 el.push(tmp[i]); 710 } 711 } 712 } 713 return el; 714 }, 715 716 /** 717 * @name Hyphenator-intermediateState 718 * @description 719 * The value of style.visibility of the text while it is hyphenated. 720 * @see Hyphenator.config 721 * @type {string} 722 * @private 723 */ 724 intermediateState = 'hidden', 725 726 /** 727 * @name Hyphenator-unhide 728 * @description 729 * How hidden elements unhide: either simultaneous (default: 'wait') or progressively. 730 * 'wait' makes Hyphenator.js to wait until all elements are hyphenated (one redraw) 731 * With 'progressiv' Hyphenator.js unhides elements as soon as they are hyphenated. 732 * @see Hyphenator.config 733 * @type {string} 734 * @private 735 */ 736 unhide = 'wait', 737 738 /** 739 * @name Hyphenator-hyphen 740 * @description 741 * A string containing the character for in-word-hyphenation 742 * @type {string} 743 * @default the soft hyphen 744 * @private 745 * @see Hyphenator.config 746 */ 747 hyphen = String.fromCharCode(173), 748 749 /** 750 * @name Hyphenator-urlhyphen 751 * @description 752 * A string containing the character for url/mail-hyphenation 753 * @type {string} 754 * @default the zero width space 755 * @private 756 * @see Hyphenator.config 757 * @see Hyphenator-zeroWidthSpace 758 */ 759 urlhyphen = zeroWidthSpace, 760 761 /** 762 * @name Hyphenator-safeCopy 763 * @description 764 * Defines wether work-around for copy issues is active or not 765 * Not supported by Opera (no onCopy handler) 766 * @type boolean 767 * @default true 768 * @private 769 * @see Hyphenator.config 770 * @see Hyphenator-registerOnCopy 771 */ 772 safeCopy = true, 773 774 775 /* 776 * runOnContentLoaded is based od jQuery.bindReady() 777 * see 778 * jQuery JavaScript Library v1.3.2 779 * http://jquery.com/ 780 * 781 * Copyright (c) 2009 John Resig 782 * Dual licensed under the MIT and GPL licenses. 783 * http://docs.jquery.com/License 784 * 785 * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009) 786 * Revision: 6246 787 */ 788 /** 789 * @name Hyphenator-runOnContentLoaded 790 * @description 791 * A crossbrowser solution for the DOMContentLoaded-Event based on jQuery 792 * <a href = "http://jquery.com/</a> 793 * I added some functionality: e.g. support for frames and iframes⦠794 * @param {Object} w the window-object 795 * @param {function()} f the function to call onDOMContentLoaded 796 * @private 797 */ 798 runOnContentLoaded = function (w, f) { 799 var DOMContentLoaded = function () {}, toplevel, hyphRunForThis = {}; 800 if (documentLoaded && !hyphRunForThis[w.location.href]) { 801 f(); 802 hyphRunForThis[w.location.href] = true; 803 return; 804 } 805 function init(context) { 806 contextWindow = context || window; 807 if (!hyphRunForThis[contextWindow.location.href] && (!documentLoaded || contextWindow != window.parent)) { 808 documentLoaded = true; 809 f(); 810 hyphRunForThis[contextWindow.location.href] = true; 811 } 812 } 813 814 function doScrollCheck() { 815 try { 816 // If IE is used, use the trick by Diego Perini 817 // http://javascript.nwbox.com/IEContentLoaded/ 818 document.documentElement.doScroll("left"); 819 } catch (error) { 820 setTimeout(doScrollCheck, 1); 821 return; 822 } 823 824 // and execute any waiting functions 825 init(window); 826 } 827 828 function doOnLoad() { 829 var i, haveAccess, fl = window.frames.length; 830 if (doFrames && fl > 0) { 831 for (i = 0; i < fl; i++) { 832 haveAccess = undefined; 833 //try catch isn't enough for webkit 834 try { 835 //opera throws only on document.toString-access 836 haveAccess = window.frames[i].document.toString(); 837 } catch (e) { 838 haveAccess = undefined; 839 } 840 if (!!haveAccess) { 841 init(window.frames[i]); 842 } 843 } 844 contextWindow = window; 845 f(); 846 hyphRunForThis[window.location.href] = true; 847 } else { 848 init(window); 849 } 850 } 851 852 // Cleanup functions for the document ready method 853 if (document.addEventListener) { 854 DOMContentLoaded = function () { 855 document.removeEventListener("DOMContentLoaded", DOMContentLoaded, false); 856 if (doFrames && window.frames.length > 0) { 857 //we are in a frameset, so do nothing but wait for onload to fire 858 return; 859 } else { 860 init(window); 861 } 862 }; 863 864 } else if (document.attachEvent) { 865 DOMContentLoaded = function () { 866 // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). 867 if (document.readyState === "complete") { 868 document.detachEvent("onreadystatechange", DOMContentLoaded); 869 if (doFrames && window.frames.length > 0) { 870 //we are in a frameset, so do nothing but wait for onload to fire 871 return; 872 } else { 873 init(window); 874 } 875 } 876 }; 877 } 878 879 // Mozilla, Opera and webkit nightlies currently support this event 880 if (document.addEventListener) { 881 // Use the handy event callback 882 document.addEventListener("DOMContentLoaded", DOMContentLoaded, false); 883 884 // A fallback to window.onload, that will always work 885 window.addEventListener("load", doOnLoad, false); 886 887 // If IE event model is used 888 } else if (document.attachEvent) { 889 // ensure firing before onload, 890 // maybe late but safe also for iframes 891 document.attachEvent("onreadystatechange", DOMContentLoaded); 892 893 // A fallback to window.onload, that will always work 894 window.attachEvent("onload", doOnLoad); 895 896 // If IE and not a frame 897 // continually check to see if the document is ready 898 toplevel = false;
899 try { 900 toplevel = window.frameElement === null; 901 } catch (e) {} 902 903 if (document.documentElement.doScroll && toplevel) { 904 doScrollCheck(); 905 } 906 } 907 908 }, 909 910 911 912 /** 913 * @name Hyphenator-getLang 914 * @description 915 * Gets the language of an element. If no language is set, it may use the {@link Hyphenator-mainLanguage}. 916 * @param {Object} el The first parameter is an DOM-Element-Object 917 * @param {boolean} fallback The second parameter is a boolean to tell if the function should return the {@link Hyphenator-mainLanguage} 918 * if there's no language found for the element. 919 * @private 920 */ 921 getLang = function (el, fallback) { 922 if (!!el.getAttribute('lang')) { 923 return el.getAttribute('lang').toLowerCase(); 924 } 925 // The following doesn't work in IE due to a bug when getAttribute('xml:lang') in a table 926 /*if (!!el.getAttribute('xml:lang')) { 927 return el.getAttribute('xml:lang').substring(0, 2); 928 }*/ 929 //instead, we have to do this (thanks to borgzor): 930 try { 931 if (!!el.getAttribute('xml:lang')) { 932 return el.getAttribute('xml:lang').toLowerCase(); 933 } 934 } catch (ex) {} 935 if (el.tagName !== 'HTML') { 936 return getLang(el.parentNode, true); 937 } 938 if (fallback) { 939 return mainLanguage; 940 } 941 return null; 942 }, 943 944 /** 945 * @name Hyphenator-autoSetMainLanguage 946 * @description 947 * Retrieves the language of the document from the DOM. 948 * The function looks in the following places: 949 * <ul> 950 * <li>lang-attribute in the html-tag</li> 951 * <li><meta http-equiv = "content-language" content = "xy" /></li> 952 * <li><meta name = "DC.Language" content = "xy" /></li> 953 * <li><meta name = "language" content = "xy" /></li> 954 * </li> 955 * If nothing can be found a prompt using {@link Hyphenator-languageHint} and {@link Hyphenator-prompterStrings} is displayed. 956 * If the retrieved language is in the object {@link Hyphenator-supportedLang} it is copied to {@link Hyphenator-mainLanguage} 957 * @private 958 */ 959 autoSetMainLanguage = function (w) { 960 w = w || contextWindow; 961 var el = w.document.getElementsByTagName('html')[0], 962 m = w.document.getElementsByTagName('meta'), 963 i, text, e, ul; 964 mainLanguage = getLang(el, false); 965 if (!mainLanguage) { 966 for (i = 0; i < m.length; i++) { 967 //<meta http-equiv = "content-language" content="xy"> 968 if (!!m[i].getAttribute('http-equiv') && (m[i].getAttribute('http-equiv').toLowerCase() === 'content-language')) { 969 mainLanguage = m[i].getAttribute('content').toLowerCase(); 970 } 971 //<meta name = "DC.Language" content="xy"> 972 if (!!m[i].getAttribute('name') && (m[i].getAttribute('name').toLowerCase() === 'dc.language')) { 973 mainLanguage = m[i].getAttribute('content').toLowerCase(); 974 } 975 //<meta name = "language" content = "xy"> 976 if (!!m[i].getAttribute('name') && (m[i].getAttribute('name').toLowerCase() === 'language')) { 977 mainLanguage = m[i].getAttribute('content').toLowerCase(); 978 } 979 } 980 } 981 //get lang for frame from enclosing document 982 if (!mainLanguage && doFrames && contextWindow != window.parent) { 983 autoSetMainLanguage(window.parent); 984 } 985 //fallback to defaultLang if set 986 if (!mainLanguage && defaultLanguage !== '') { 987 mainLanguage = defaultLanguage; 988 } 989 //ask user for lang 990 if (!mainLanguage) { 991 text = ''; 992 ul = navigator.language ? navigator.language : navigator.userLanguage; 993 ul = ul.substring(0, 2); 994 if (prompterStrings.hasOwnProperty(ul)) { 995 text = prompterStrings[ul]; 996 } else { 997 text = prompterStrings.en; 998 } 999 text += ' (ISO 639-1)\n\n' + languageHint; 1000 mainLanguage = window.prompt(unescape(text), ul).toLowerCase(); 1001 } 1002 if (!supportedLang.hasOwnProperty(mainLanguage)) { 1003 if (supportedLang.hasOwnProperty(mainLanguage.split('-')[0])) { //try subtag 1004 mainLanguage = mainLanguage.split('-')[0]; 1005 } else { 1006 e = new Error('The language "' + mainLanguage + '" is not yet supported.'); 1007 throw e; 1008 } 1009 } 1010 }, 1011 1012 /** 1013 * @name Hyphenator-gatherDocumentInfos 1014 * @description 1015 * This method runs through the DOM and executes the process()-function on: 1016 * - every node returned by the {@link Hyphenator-selectorFunction}. 1017 * The process()-function copies the element to the elements-variable, sets its visibility 1018 * to intermediateState, retrieves its language and recursivly desce
1018nds the DOM-tree until 1019 * the child-Nodes aren't of type 1 1020 * @private 1021 */ 1022 gatherDocumentInfos = function () { 1023 var elToProcess, tmp, i = 0, 1024 process = function (el, hide, lang) { 1025 var n, i = 0, hyphenatorSettings = {}; 1026 1027 if (el.lang && typeof(el.lang) === 'string') { 1028 lang = el.lang.toLowerCase(); //copy attribute-lang to internal lang 1029 } else if (lang) { 1030 lang = lang.toLowerCase(); 1031 } else { 1032 lang = getLang(el, true); 1033 } 1034 1035 //if css3-hyphenation is supported: use it! 1036 if (css3 && css3_h9n.support && !!css3_h9n.languages[lang]) { 1037 el.style[css3_h9n.property] = "auto"; 1038 el.style['-webkit-locale'] = "'" + lang + "'"; 1039 } else { 1040 if (intermediateState === 'hidden') { 1041 if (!!el.getAttribute('style')) { 1042 hyphenatorSettings.hasOwnStyle = true; 1043 } else { 1044 hyphenatorSettings.hasOwnStyle = false; 1045 } 1046 hyphenatorSettings.isHidden = true; 1047 el.style.visibility = 'hidden'; 1048 } 1049 if (supportedLang[lang]) { 1050 docLanguages[lang] = true; 1051 } else { 1052 if (supportedLang.hasOwnProperty(lang.split('-')[0])) { //try subtag 1053 lang = lang.split('-')[0]; 1054 hyphenatorSettings.language = lang; 1055 } else if (!isBookmarklet) { 1056 onError(new Error('Language ' + lang + ' is not yet supported.')); 1057 } 1058 } 1059 elements.add(el, lang, hyphenatorSettings); 1060 } 1061 while (!!(n = el.childNodes[i++])) { 1062 if (n.nodeType === 1 && !dontHyphenate[n.nodeName.toLowerCase()] && 1063 n.className.indexOf(dontHyphenateClass) === -1 && !(n in elToProcess)) { 1064 process(n, false, lang); 1065 } 1066 } 1067 }; 1068 if (css3) { 1069 css3_gethsupport(); 1070 } 1071 if (isBookmarklet) { 1072 elToProcess = contextWindow.document.getElementsByTagName('body')[0]; 1073 process(elToProcess, false, mainLanguage); 1074 } else { 1075 elToProcess = selectorFunction(); 1076 while (!!(tmp = elToProcess[i++])) 1077 { 1078 process(tmp, true, ''); 1079 } 1080 } 1081 if (elements.count === 0) { 1082 //nothing to hyphenate or all hyphenated b css3 1083 state = 3; 1084 onHyphenationDone(); 1085 } 1086 }, 1087 1088 1089 /** 1090 * @name Hyphenator-createTrie 1091 * @description 1092 * converts patterns of the given language in a trie 1093 * @private 1094 * @param {string} lang the language whose patterns shall be converted 1095 */ 1096 convertPatterns = function (lang) { 1097 /** @license BSD licenced code 1098 * The following code is based on code from hypher.js and adapted for Hyphenator.js 1099 * Copyright (c) 2011, Bram Stein 1100 */ 1101 var size = 0, 1102 tree = { 1103 tpoints: [] 1104 }, 1105 patterns, pattern, i, j, k, 1106 patternObject = Hyphenator.languages[lang].patterns, 1107 c, chars, points, t, p, codePoint, 1108 getPoints = (function () { 1109 //IE<9 doesn't act like other browsers 1110 if ('in3se'.split(/\D/).length === 1) { 1111 return function (pattern) { 1112 var chars = pattern.split(''), c, i, r = [], 1113 numb3rs = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}, lastWasNum = false; 1114 i = 0; 1115 while (!!(c = chars[i])) { 1116 if (numb3rs.hasOwnProperty(c)) { 1117 r.push(c); 1118 i += 2; 1119 lastWasNum = true; 1120 } else { 1121 r.push(''); 1122 i += 1; 1123 lastWasNum = false; 1124 } 1125 } 1126 if (!lastWasNum) { 1127 r.push(''); 1128 } 1129 return r; 1130 }; 1131 } else { 1132 return function (pattern) { 1133 return pattern.split(/\D/); 1134 }; 1135 } 1136 }()); 1137 1138 for (size in patternObject) { 1139 if (patternObject.hasOwnProperty(size)) { 1140 patterns = patternObject[size].match(new RegExp('.{1,' + (+size) + '}', 'g')); 1141 i = 0; 1142 while (!!(pattern = patterns[i++])) { 1143 chars = pattern.replace(/[\d]/g, '').split(''); 1144 points = getPoints(pattern); 1145 t = tree; 1146 1147 j = 0; 1148 while (!!(c = chars[j++])) { 1149 codePoint = c.charCodeAt(0); 1150 1151 if (!t[codePoint]) { 1152 t[codePoint] = {}; 1153 } 1154 t = t[codePoint]; 1155 } 1156 1157 t.tpoints = []; 1158 for (k = 0; k < points.length; k++) { 1159 p = points[k]; 1160 t.tpoints.push((p == "") ? 0 : p); 1161 } 1162 } 1163 } 1164 } 1165 Hyphenator.languages[lang].patterns = tree; 1166 /** 1167 * end of BSD licenced code from hypher.js 1168 */ 1169 }, 1170 1171 recreatePattern = function (pattern, nodePoints) { 1172 var r = [], c = pattern.split(''), i; 1173 for (i = 0; i < nodePoints.length; i++) { 1174 if (nodePoints[i] !== 0) { 1175 r.push(nodePoints[i]); 1176 } 1177 if (c[i]) { 1178 r.push(c[i]); 1179 } 1180 } 1181 return r.join(''); 1182 }, 1183 1184 /** 1185 * @name Hyphenator-convertExceptionsToObject 1186 * @description 1187 * Converts a list of comma seprated exceptions to an object: 1188 * 'Fortran,Hy-phen-a-tion' -> {'Fortran':'Fortran','Hyphenation':'Hy-phen-a-tion'} 1189 * @private 1190 * @param {string} exc a comma separated string of exceptions (without spaces) 1191 */ 1192 convertExceptionsToObject = function (exc) { 1193 var w = exc.split(', '), 1194 r = {}, 1195 i, l, key; 1196 for (i = 0, l = w.length; i < l; i++) { 1197 key = w[i].replace(/-/g, ''); 1198 if (!r.hasOwnProperty(key)) { 1199 r[key] = w[i]; 1200 } 1201 } 1202 return r; 1203 }, 1204 1205 /** 1206 * @name Hyphenator-loadPatterns 1207 * @description 1208 * Adds a <script>-Tag to the DOM to load an externeal .js-file containing patterns and settings for the given language. 1209 * If the given language is not in the {@link Hyphenator-supportedLang}-Object it returns. 1210 * One may ask why we are not using AJAX to load the patterns. The XMLHttpRequest-Object 1211 * has a same-origin-policy. This makes the isBookmarklet-functionality impossible. 1212 * @param {string} lang The language to load the patterns for 1213 * @private 1214 * @see Hyphenator-basePath 1215 */ 1216 loadPatterns = function (lang) { 1217 var url, xhr, head, script; 1218 if (supportedLang[lang] && !Hyphenator.languages[lang]) { 1219 url = basePath + 'patterns/' + supportedLang[lang]; 1220 } else { 1221 return; 1222 } 1223 if (isLocal && !isBookmarklet) { 1224 //check if 'url' is available: 1225 xhr = null; 1226 if (typeof XMLHttpRequest !== 'undefined') { 1227 xhr = new XMLHttpRequest(); 1228 } 1229 if (!xhr) { 1230 try { 1231 xhr = new ActiveXObject("Msxml2.XMLHTTP"); 1232 } catch (e) { 1233 xhr = null; 1234 } 1235 } 1236 if (xhr) { 1237 xhr.open('HEAD', url, false); 1238 xhr.setRequestHeader('Cache-Control', 'no-cache'); 1239 xhr.send(null); 1240 if (xhr.status === 404) { 1241 onError(new Error('Could not load\n' + url)); 1242 delete docLanguages[lang]; 1243 return; 1244 } 1245 } 1246 } 1247 if (createElem) { 1248 head = window.document.getElementsByTagName('head').item(0); 1249 script = createElem('script', window); 1250 script.src = url; 1251 script.type = 'text/javascript'; 1252 head.appendChild(script); 1253 } 1254 }, 1255 1256 /** 1257 * @name Hyphenator-prepareLanguagesObj 1258 * @description 1259 * Adds a cache to each language and converts the exceptions-list to an object. 1260 * If storage is active the object is stored there. 1261 * @private 1262 * @param {string} lang the language ob the lang-obj 1263 */ 1264 prepareLanguagesObj = function (lang) { 1265 var lo = Hyphenator.languages[lang], wrd; 1266 if (!lo.prepared) { 1267 if (enableCache) { 1268 lo.cache = {}; 1269 //Export 1270 lo['cache'] = lo.cache; 1271 } 1272 if (enableReducedPatternSet) { 1273 lo.redPatSet = {}; 1274 } 1275 //add exceptions from the pattern file to the local 'exceptions'-obj 1276 if (lo.hasOwnProperty('exceptions')) { 1277 Hyphenator.addExceptions(lang, lo.exceptions); 1278 delete lo.exceptions; 1279 } 1280 //copy global exceptions to the language specific exceptions 1281 if (exceptions.hasOwnProperty('global')) { 1282 if (exceptions.hasOwnProperty(lang)) { 1283 exceptions[lang] += ', ' + exceptions.global; 1284 } else { 1285 exceptions[lang] = exceptions.global; 1286 } 1287 } 1288 //move exceptions from the the local 'exceptions'-obj to the 'language'-object 1289 if (exceptions.hasOwnProperty(lang)) { 1290 lo.exceptions = convertExceptionsToObject(exceptions[lang]); 1291 delete exceptions[lang]; 1292 } else { 1293 lo.exceptions = {}; 1294 } 1295 convertPatterns(lang); 1296 wrd = '[\\w' + lo.specialChars + '@' + String.fromCharCode(173) + String.fromCharCode(8204) + '-]{' + min + ',}'; 1297 lo.genRegExp = new RegExp('(' + url + ')|(' + mail + ')|(' + wrd + ')', 'gi'); 1298 lo.prepared = true; 1299 } 1300 if (!!storage) { 1301 try { 1302 storage.setItem('Hyphenator_' + lang, window.JSON.stringify(lo)); 1303 } catch (e) { 1304 //onError(e); 1305 } 1306 } 1307 1308 }, 1309 1310 /** 1311 * @name Hyphenator-prepare 1312 * @description 1313 * This funtion prepares the Hyphenator-Object: If RemoteLoading is turned off, it assumes
1314 * that the patternfiles are loaded, all conversions are made and the callback is called. 1315 * If storage is active the object is retrieved there. 1316 * If RemoteLoading is on (default), it loads the pattern files and waits until they are loaded, 1317 * by repeatedly checking Hyphenator.languages. If a patterfile is loaded the patterns are 1318 * converted to their object style and the lang-object extended. 1319 * Finally the callback is called. 1320 * @private 1321 */ 1322 prepare = function (callback) { 1323 var lang, interval, tmp1, tmp2; 1324 if (!enableRemoteLoading) { 1325 for (lang in Hyphenator.languages) { 1326 if (Hyphenator.languages.hasOwnProperty(lang)) { 1327 prepareLanguagesObj(lang); 1328 } 1329 } 1330 state = 2; 1331 callback('*'); 1332 return; 1333 } 1334 // get all languages that are used and preload the patterns 1335 state = 1; 1336 for (lang in docLanguages) { 1337 if (docLanguages.hasOwnProperty(lang)) { 1338 if (!!storage && storage.getItem('Hyphenator_' + lang)) { 1339 Hyphenator.languages[lang] = window.JSON.parse(storage.getItem('Hyphenator_' + lang)); 1340 if (exceptions.hasOwnProperty('global')) { 1341 tmp1 = convertExceptionsToObject(exceptions.global); 1342 for (tmp2 in tmp1) { 1343 if (tmp1.hasOwnProperty(tmp2)) { 1344 Hyphenator.languages[lang].exceptions[tmp2] = tmp1[tmp2]; 1345 } 1346 } 1347 } 1348 //Replace exceptions since they may have been changed: 1349 if (exceptions.hasOwnProperty(lang)) { 1350 tmp1 = convertExceptionsToObject(exceptions[lang]); 1351 for (tmp2 in tmp1) { 1352 if (tmp1.hasOwnProperty(tmp2)) { 1353 Hyphenator.languages[lang].exceptions[tmp2] = tmp1[tmp2]; 1354 } 1355 } 1356 delete exceptions[lang]; 1357 } 1358 //Replace genRegExp since it may have been changed: 1359 tmp1 = '[\\w' + Hyphenator.languages[lang].specialChars + '@' + String.fromCharCode(173) + String.fromCharCode(8204) + '-]{' + min + ',}'; 1360 Hyphenator.languages[lang].genRegExp = new RegExp('(' + url + ')|(' + mail + ')|(' + tmp1 + ')', 'gi'); 1361 1362 delete docLanguages[lang]; 1363 callback(lang); 1364 continue; 1365 } else { 1366 loadPatterns(lang); 1367 } 1368 } 1369 } 1370 // else async wait until patterns are loaded, then hyphenate 1371 interval = window.setInterval(function () { 1372 var finishedLoading = true, lang; 1373 for (lang in docLanguages) { 1374 if (docLanguages.hasOwnProperty(lang)) { 1375 finishedLoading = false; 1376 if (!!Hyphenator.languages[lang]) { 1377 delete docLanguages[lang]; 1378 //do conversion while other patterns are loading: 1379 prepareLanguagesObj(lang); 1380 callback(lang); 1381 } 1382 } 1383 } 1384 if (finishedLoading) { 1385 //console.log('callig callback for ' + contextWindow.location.href); 1386 window.clearInterval(interval); 1387 state = 2; 1388 } 1389 }, 100); 1390 }, 1391 1392 /** 1393 * @name Hyphenator-switchToggleBox 1394 * @description 1395 * Creates or hides the toggleBox: a small button to turn off/on hyphenation on a page. 1396 * @see Hyphenator.config 1397 * @private 1398 */ 1399 toggleBox = function () { 1400 var myBox, bdy, myIdAttribute, myTextNode, myClassAttribute, 1401 text = (Hyphenator.doHyphenation ? 'Hy-phen-a-tion' : 'Hyphenation'); 1402 if (!!(myBox = contextWindow.document.getElementById('HyphenatorToggleBox'))) { 1403 myBox.firstChild.data = text; 1404 } else { 1405 bdy = contextWindow.document.getElementsByTagName('body')[0]; 1406 myBox = createElem('div', contextWindow); 1407 myIdAttribute = contextWindow.document.createAttribute('id'); 1408 myIdAttribute.nodeValue = 'HyphenatorToggleBox'; 1409 myClassAttribute = contextWindow.document.createAttribute('class'); 1410 myClassAttribute.nodeValue = dontHyphenateClass; 1411 myTextNode = contextWindow.document.createTextNode(text); 1412 myBox.appendChild(myTextNode); 1413 myBox.setAttributeNode(myIdAttribute); 1414 myBox.setAttributeNode(myClassAttribute); 1415 myBox.onclick = Hyphenator.toggleHyphenation; 1416 myBox.style.position = 'absolute'; 1417 myBox.style.top = '0px'; 1418 myBox.style.right = '0px'; 1419 myBox.style.margin = '0'; 1420 myBox.style.backgroundColor = '#AAAAAA'; 1421 myBox.style.color = '#FFFFFF'; 1422 myBox.style.font = '6pt Arial'; 1423 myBox.style.letterSpacing = '0.2em'; 1424 myBox.style.padding = '3px'; 1425 myBox.style.cursor = 'pointer'; 1426 myBox.style.WebkitBorderBottomLeftRadius = '4px'; 1427 myBox.style.MozBorderRadiusBottomleft = '4px'; 1428 bdy.appendChild(myBox); 1429 } 1430 }, 1431 1432 1433 /** 1434 * @name Hyphenator-hyphenateWord 1435 * @description 1436 * This function is the heart of Hyphenator.js. It returns a hyphenated word. 1437 * 1438 * If there's already a {@link Hyphenator-hypen} in the word, the word is returned as it is. 1439 * If the word is in the exceptions list or in the cache, it is retrieved from it. 1440 * If there's a '-' put a zeroWidthSpace after the '-' and hyphenate the parts. 1441 * @param {string} lang The language of the word 1442 * @param {string} word The word 1443 * @returns string The hyphenated word 1444 * @public 1445 */ 1446 hyphenateWord = function (lang, word) { 1447 var lo = Hyphenator.languages[lang], parts, l, subst, 1448 w, characters, originalCharacters, wordLength, i, j, k, node, points = [], 1449 characterPoints = [], nodePoints, nodePointsLength, m = Math.max, trie, 1450 result = [''], pattern; 1451 if (word === '') { 1452 return ''; 1453 } 1454 if (word.indexOf(hyphen) !== -1) { 1455 //word already contains shy; -> leave at it is! 1456 return word; 1457 } 1458 if (enableCache && lo.cache.hasOwnProperty(word)) { //the word is in the cache 1459 return lo.cache[word]; 1460 } 1461 if (lo.exceptions.hasOwnProperty(word)) { //the word is in the exceptions list 1462 return lo.exceptions[word].replace(/-/g, hyphen); 1463 } 1464 if (word.indexOf('-') !== -1) { 1465 //word contains '-' -> hyphenate the parts separated with '-' 1466 parts = word.split('-'); 1467 for (i = 0, l = parts.length; i < l; i++) { 1468 parts[i] = hyphenateWord(lang, parts[i]); 1469 } 1470 return parts.join('-'); 1471 } 1472 w = word = '_' + word + '_'; 1473 if (!!lo.charSubstitution) { 1474 for (subst in lo.charSubstitution) { 1475 if (lo.charSubstitution.hasOwnProperty(subst)) { 1476 w = w.replace(new RegExp(subst, 'g'), lo.charSubstitution[subst]); 1477 } 1478 } 1479 } 1480 if (word.indexOf("'") !== -1) { 1481 w = w.replace("'", "â");
1481 //replace APOSTROPHE with RIGHT SINGLE QUOTATION MARK (since the latter is used in the patterns) 1482 } 1483 /** @license BSD licenced code 1484 * The following code is based on code from hypher.js 1485 * Copyright (c) 2011, Bram Stein 1486 */ 1487 characters = w.toLowerCase().split(''); 1488 originalCharacters = word.split(''); 1489 wordLength = characters.length; 1490 trie = lo.patterns; 1491 for (i = 0; i < wordLength; i += 1) { 1492 points[i] = 0; 1493 characterPoints[i] = characters[i].charCodeAt(0); 1494 } 1495 for (i = 0; i < wordLength; i += 1) { 1496 pattern = ''; 1497 node = trie; 1498 for (j = i; j < wordLength; j += 1) { 1499 node = node[characterPoints[j]]; 1500 if (node) { 1501 if (enableReducedPatternSet) { 1502 pattern += String.fromCharCode(characterPoints[j]); 1503 } 1504 nodePoints = node.tpoints; 1505 if (nodePoints) { 1506 if (enableReducedPatternSet) { 1507 if (!lo.redPatSet) { 1508 lo.redPatSet = {}; 1509 } 1510 lo.redPatSet[pattern] = recreatePattern(pattern, nodePoints); 1511 } 1512 for (k = 0, nodePointsLength = nodePoints.length; k < nodePointsLength; k += 1) { 1513 points[i + k] = m(points[i + k], nodePoints[k]); 1514 } 1515 } 1516 } else { 1517 break; 1518 } 1519 } 1520 } 1521 for (i = 1; i < wordLength - 1; i += 1) { 1522 if (i > lo.leftmin && i < (wordLength - lo.rightmin) && points[i] % 2) { 1523 result.push(originalCharacters[i]); 1524 } else { 1525 result[result.length - 1] += originalCharacters[i]; 1526 } 1527 } 1528 return result.join(hyphen); 1529 /** 1530 * end of BSD licenced code from hypher.js 1531 */ 1532 }, 1533 1534 /** 1535 * @name Hyphenator-hyphenateURL 1536 * @description 1537 * Puts {@link Hyphenator-urlhyphen} after each no-alphanumeric char that my be in a URL. 1538 * @param {string} url to hyphenate 1539 * @returns string the hyphenated URL 1540 * @public 1541 */ 1542 hyphenateURL = function (url) { 1543 return url.replace(/([:\/\.\?#&_,;!@]+)/gi, '$&' + urlhyphen); 1544 }, 1545 1546 /** 1547 * @name Hyphenator-removeHyphenationFromElement 1548 * @description 1549 * Removes all hyphens from the element. If there are other elements, the function is 1550 * called recursively. 1551 * Removing hyphens is usefull if you like to copy text. Some browsers are buggy when the copy hyphenated texts. 1552 * @param {Object} el The element where to remove hyphenation. 1553 * @public 1554 */ 1555 removeHyphenationFromElement = function (el) { 1556 var h, i = 0, n; 1557 switch (hyphen) { 1558 case '|': 1559 h = '\\|'; 1560 break; 1561 case '+': 1562 h = '\\+'; 1563 break; 1564 case '*': 1565 h = '\\*'; 1566 break; 1567 default: 1568 h = hyphen; 1569 } 1570 while (!!(n = el.childNodes[i++])) { 1571 if (n.nodeType === 3) { 1572 n.data = n.data.replace(new RegExp(h, 'g'), ''); 1573 n.data = n.data.replace(new RegExp(zeroWidthSpace, 'g'), ''); 1574 } else if (n.nodeType === 1) { 1575 removeHyphenationFromElement(n); 1576 } 1577 } 1578 }, 1579 1580 1581 /** 1582 * @name Hyphenator-registerOnCopy 1583 * @description 1584 * Huge work-around for browser-inconsistency when it comes to 1585 * copying of hyphenated text. 1586 * The idea behind this code has been provided by http://github.com/aristus/sweet-justice 1587 * sweet-justice is under BSD-License 1588 * @private 1589 */ 1590 registerOnCopy = function (el) { 1591 var body = el.ownerDocument.getElementsByTagName('body')[0], 1592 shadow, 1593 selection, 1594 range, 1595 rangeShadow, 1596 restore, 1597 oncopyHandler = function (e) { 1598 e = e || window.event; 1599 var target = e.target || e.srcElement, 1600 currDoc = target.ownerDocument, 1601 body = currDoc.getElementsByTagName('body')[0], 1602 targetWindow = 'defaultView' in currDoc ? currDoc.defaultView : currDoc.parentWindow; 1603 if (target.tagName && dontHyphenate[target.tagName.toLowerCase()]) { 1604 //Safari needs this 1605 return; 1606 } 1607 //create a hidden shadow element 1608 shadow = currDoc.createElement('div'); 1609 //Moving the element out of the screen doesn't work for IE9 (https://connect.microsoft.com/IE/feedback/details/663981/) 1610 //shadow.style.overflow = 'hidden'; 1611 //shadow.style.position = 'absolute'; 1612 //shadow.style.top = '-5000px'; 1613 //shadow.style.height = '1px'; 1614 //doing this instead: 1615 shadow.style.color = window.getComputedStyle ? targetWindow.getComputedStyle(body).backgroundColor : '#FFFFFF'; 1616 shadow.style.fontSize = '0px'; 1617 body.appendChild(shadow); 1618 if (!!window.getSelection) { 1619 //FF3, Webkit, IE9 1620 e.stopPropagation(); 1621 selection = targetWindow.getSelection(); 1622 range = selection.getRangeAt(0); 1623 shadow.appendChild(range.cloneContents()); 1624 removeHyphenationFromElement(shadow); 1625 selection.selectAllChildren(shadow); 1626 restore = function () { 1627 shadow.parentNode.removeChild(shadow); 1628 selection.removeAllRanges(); //IE9 needs that 1629 selection.addRange(range); 1630 }; 1631 } else { 1632 // IE<9 1633 e.cancelBubble = true; 1634 selection = targetWindow.document.selection; 1635 range = selection.createRange(); 1636 shadow.innerHTML = range.htmlText; 1637 removeHyphenationFromElement(shadow); 1638 rangeShadow = body.createTextRange(); 1639 rangeShadow.moveToElementText(shadow); 1640 rangeShadow.select(); 1641 restore = function () { 1642 shadow.parentNode.removeChild(shadow); 1643 if (range.text !== "") { 1644 range.select(); 1645 } 1646 }; 1647 } 1648 window.setTimeout(restore, 0); 1649 }; 1650 if (!body) { 1651 return; 1652 } 1653 el = el || body; 1654 if (window.addEventListener) { 1655 el.addEventListener("copy", oncopyHandler, true); 1656 } else { 1657 el.attachEvent("oncopy", oncopyHandler); 1658 } 1659 }, 1660 1661 /** 1662 * @name Hyphenator-unhideElement 1663 * @description 1664 * Unhides an element and removes the visibility attr if set by hyphenator 1665 * @param Object The Element object from ElementCollection 1666 * @private 1667 */ 1668 unhideElement = function (elo) { 1669 var el = elo.element, 1670 hyphenatorSettings = elo.data; 1671 el.style.visibility = 'visible'; 1672 elo.data.isHidden = false;
1673 if (!hyphenatorSettings.hasOwnStyle) { 1674 el.setAttribute('style', ''); // without this, removeAttribute doesn't work in Safari (thanks to molily) 1675 el.removeAttribute('style'); 1676 } else { 1677 if (el.style.removeProperty) { 1678 el.style.removeProperty('visibility'); 1679 } else if (el.style.removeAttribute) { // IE 1680 el.style.removeAttribute('visibility'); 1681 } 1682 } 1683 }, 1684 1685 /** 1686 * @name Hyphenator-checkIfAllDone 1687 * @description 1688 * Checks if all Elements are hyphenated, unhides them and fires onHyphenationDone() 1689 * @private 1690 */ 1691 checkIfAllDone = function () { 1692 var allDone = true; 1693 elements.each(function (lang, list) { 1694 var i, l = list.length; 1695 for (i = 0; i < l; i++) { 1696 allDone = allDone && list[i].hyphenated; 1697 if (intermediateState === 'hidden' && unhide === 'wait') { 1698 unhideElement(list[i]); 1699 } 1700 } 1701 }); 1702 if (allDone) { 1703 state = 3; 1704 onHyphenationDone(); 1705 } 1706 }, 1707 1708 1709 /** 1710 * @name Hyphenator-hyphenateElement 1711 * @description 1712 * Takes the content of the given element and - if there's text - replaces the words 1713 * by hyphenated words. If there's another element, the function is called recursively. 1714 * When all words are hyphenated, the visibility of the element is set to 'visible'. 1715 * @param {Object} el The element to hyphenate 1716 * @private 1717 */ 1718 hyphenateElement = function (lang, elo) { 1719 var hyphenatorSettings = elo.data, 1720 el = elo.element, 1721 hyphenate, n, i, 1722 controlOrphans = function (part) { 1723 var h, r; 1724 switch (hyphen) { 1725 case '|': 1726 h = '\\|'; 1727 break; 1728 case '+': 1729 h = '\\+'; 1730 break; 1731 case '*': 1732 h = '\\*'; 1733 break; 1734 default: 1735 h = hyphen; 1736 } 1737 if (orphanControl >= 2) { 1738 //remove hyphen points from last word 1739 r = part.split(' '); 1740 r[1] = r[1].replace(new RegExp(h, 'g'), ''); 1741 r[1] = r[1].replace(new RegExp(zeroWidthSpace, 'g'), ''); 1742 r = r.join(' '); 1743 } 1744 if (orphanControl === 3) { 1745 //replace spaces by non breaking spaces 1746 r = r.replace(/[ ]+/g, String.fromCharCode(160)); 1747 } 1748 return r; 1749 }; 1750 if (Hyphenator.languages.hasOwnProperty(lang)) { 1751 hyphenate = function (word) { 1752 if (!Hyphenator.doHyphenation) { 1753 return word; 1754 } else if (urlOrMailRE.test(word)) { 1755 return hyphenateURL(word); 1756 } else { 1757 return hyphenateWord(lang, word); 1758 } 1759 }; 1760 if (safeCopy && (el.tagName.toLowerCase() !== 'body')) { 1761 registerOnCopy(el); 1762 } 1763 i = 0; 1764 while (!!(n = el.childNodes[i++])) { 1765 if (n.nodeType === 3 && n.data.length >= min) { //type 3 = #text -> hyphenate! 1766 n.data = n.data.replace(Hyphenator.languages[lang].genRegExp, hyphenate); 1767 if (orphanControl !== 1) { 1768 n.data = n.data.replace(/[\S]+ [\S]+$/, controlOrphans); 1769 } 1770 } 1771 } 1772 } 1773 if (hyphenatorSettings.isHidden && intermediateState === 'hidden' && unhide === 'progressive') { 1774 unhideElement(elo); 1775 } 1776 elo.hyphenated = true; 1777 elements.hyCount += 1; 1778 if (elements.count <= elements.hyCount) { 1779 checkIfAllDone(); 1780 } 1781 }, 1782 1783 1784 /** 1785 * @name Hyphenator-hyphenateLanguageElements 1786 * @description 1787 * Calls hyphenateElement() for all elements of the specified language. 1788 * If the language is '*' then all elements are hyphenated. 1789 * This is done with a setTimout 1790 * to prevent a "long running Script"-alert when hyphenating large pages. 1791 * Therefore a tricky bind()-function was necessary. 1792 * @private 1793 */ 1794 hyphenateLanguageElements = function (lang) { 1795 function bind(fun, arg1, arg2) { 1796 return function () { 1797 return fun(arg1, arg2); 1798 }; 1799 } 1800 var el, i, l; 1801 if (lang === '*') { 1802 elements.each(function (lang, langels) { 1803 var i, l = langels.length; 1804 for (i = 0; i < l; i++) { 1805 window.setTimeout(bind(hyphenateElement, lang, langels[i]), 0); 1806 } 1807 }); 1808 } else { 1809 if (elements.list.hasOwnProperty(lang)) { 1810 l = elements.list[lang].length; 1811 for (i = 0; i < l; i++) { 1812 window.setTimeout(bind(hyphenateElement, lang, elements.list[lang][i]), 0); 1813 } 1814 } 1815 } 1816 }, 1817 1818 /** 1819 * @name Hyphenator-removeHyphenationFromDocument 1820 * @description 1821 * Does what it says ;-) 1822 * @private 1823 */ 1824 removeHyphenationFromDocument = function () { 1825 elements.each(function (lang, elo) { 1826 var i, l = elo.length, el; 1827 for (i = 0; i < l; i++) { 1828 removeHyphenationFromElement(elo[i].element); 1829 elo[i].hyphenated = false;
1830 } 1831 }); 1832 state = 4; 1833 }, 1834 1835 /** 1836 * @name Hyphenator-createStorage 1837 * @description 1838 * inits the private var storage depending of the setting in storageType 1839 * and the supported features of the system. 1840 * @private 1841 */ 1842 createStorage = function () { 1843 try { 1844 if (storageType !== 'none' && 1845 typeof(window.localStorage) !== 'undefined' && 1846 typeof(window.sessionStorage) !== 'undefined' && 1847 typeof(window.JSON.stringify) !== 'undefined' && 1848 typeof(window.JSON.parse) !== 'undefined') { 1849 switch (storageType) { 1850 case 'session': 1851 storage = window.sessionStorage; 1852 break; 1853 case 'local': 1854 storage = window.localStorage; 1855 break; 1856 default: 1857 storage = undefined; 1858 break; 1859 } 1860 } 1861 } catch (f) { 1862 //FF throws an error if DOM.storage.enabled is set to false 1863 } 1864 }, 1865 1866 /** 1867 * @name Hyphenator-storeConfiguration 1868 * @description 1869 * Stores the current config-options in DOM-Storage 1870 * @private 1871 */ 1872 storeConfiguration = function () { 1873 if (!storage) { 1874 return; 1875 } 1876 var settings = { 1877 'STORED': true, 1878 'classname': hyphenateClass, 1879 'donthyphenateclassname': dontHyphenateClass, 1880 'minwordlength': min, 1881 'hyphenchar': hyphen, 1882 'urlhyphenchar': urlhyphen, 1883 'togglebox': toggleBox, 1884 'displaytogglebox': displayToggleBox, 1885 'remoteloading': enableRemoteLoading, 1886 'enablecache': enableCache, 1887 'onhyphenationdonecallback': onHyphenationDone, 1888 'onerrorhandler': onError, 1889 'intermediatestate': intermediateState, 1890 'selectorfunction': selectorFunction, 1891 'safecopy': safeCopy, 1892 'doframes': doFrames, 1893 'storagetype': storageType, 1894 'orphancontrol': orphanControl, 1895 'dohyphenation': Hyphenator.doHyphenation, 1896 'persistentconfig': persistentConfig, 1897 'defaultlanguage': defaultLanguage 1898 }; 1899 storage.setItem('Hyphenator_config', window.JSON.stringify(settings)); 1900 }, 1901 1902 /** 1903 * @name Hyphenator-restoreConfiguration 1904 * @description 1905 * Retrieves config-options from DOM-Storage and does configuration accordingly 1906 * @private 1907 */ 1908 restoreConfiguration = function () { 1909 var settings; 1910 if (storage.getItem('Hyphenator_config')) { 1911 settings = window.JSON.parse(storage.getItem('Hyphenator_config')); 1912 Hyphenator.config(settings); 1913 } 1914 }; 1915 1916 return { 1917 1918 /** 1919 * @name Hyphenator.version 1920 * @memberOf Hyphenator 1921 * @description 1922 * String containing the actual version of Hyphenator.js 1923 * [major release].[minor releas].[bugfix release] 1924 * major release: new API, new Features, big changes 1925 * minor release: new languages, improvements 1926 * @public 1927 */ 1928 version: '4.0.0', 1929 1930 /** 1931 * @name Hyphenator.doHyphenation 1932 * @description 1933 * If doHyphenation is set to false (defaults to true), hyphenateDocument() isn't called. 1934 * All other actions are performed. 1935 */ 1936 doHyphenation: true, 1937 1938 /** 1939 * @name Hyphenator.languages 1940 * @memberOf Hyphenator 1941 * @description 1942 * Objects that holds key-value pairs, where key is the language and the value is the 1943 * language-object loaded from (and set by) the pattern file. 1944 * The language object holds the following members: 1945 * <table> 1946 * <tr><th>key</th><th>desc></th></tr> 1947 * <tr><td>leftmin</td><td>The minimum of chars to remain on the old line</td></tr> 1948 * <tr><td>rightmin</td><td>The minimum of chars to go on the new line</td></tr> 1949 * <tr><td>shortestPattern</td><td>The shortes pattern (numbers don't count!)</td></tr> 1950 * <tr><td>longestPattern</td><td>The longest pattern (numbers don't count!)</td></tr> 1951 * <tr><td>specialChars</td><td>Non-ASCII chars in the alphabet.</td></tr> 1952 * <tr><td>patterns</td><td>the patterns</td></tr> 1953 * </table> 1954 * And optionally (or after prepareLanguagesObj() has been called): 1955 * <table> 1956 * <tr><td>exceptions</td><td>Excpetions for the secified language</td></tr> 1957 * </table> 1958 * @public 1959 */ 1960 languages: {}, 1961 1962 1963 /** 1964 * @name Hyphenator.config 1965 * @description 1966 * Config function that takes an object as an argument. The object contains key-value-pairs 1967 * containig Hyphenator-settings. This is a shortcut for calling Hyphenator.set...-Methods. 1968 * @param {Object} obj <table> 1969 * <tr><th>key</th><th>values</th><th>default</th></tr> 1970 * <tr><td>classname</td><td>string</td><td>'hyphenate'</td></tr> 1971 * <tr><td>donthyphenateclassname</td><td>string</td><td>''</td></tr> 1972 * <tr><td>minwordlength</td><td>integer</td><td>6</td></tr> 1973 * <tr><td>
1973hyphenchar</td><td>string</td><td>'&shy;'</td></tr> 1974 * <tr><td>urlhyphenchar</td><td>string</td><td>'zero with space'</td></tr> 1975 * <tr><td>togglebox</td><td>function</td><td>see code</td></tr> 1976 * <tr><td>displaytogglebox</td><td>boolean</td><td>false</td></tr> 1977 * <tr><td>remoteloading</td><td>boolean</td><td>true</td></tr> 1978 * <tr><td>enablecache</td><td>boolean</td><td>true</td></tr> 1979 * <tr><td>enablereducedpatternset</td><td>boolean</td><td>false</td></tr> 1980 * <tr><td>onhyphenationdonecallback</td><td>function</td><td>empty function</td></tr> 1981 * <tr><td>onerrorhandler</td><td>function</td><td>alert(onError)</td></tr> 1982 * <tr><td>intermediatestate</td><td>string</td><td>'hidden'</td></tr> 1983 * <tr><td>selectorfunction</td><td>function</td><td>[â¦]</td></tr> 1984 * <tr><td>safecopy</td><td>boolean</td><td>true</td></tr> 1985 * <tr><td>doframes</td><td>boolean</td><td>false</td></tr> 1986 * <tr><td>storagetype</td><td>string</td><td>'none'</td></tr> 1987 * </table> 1988 * @public 1989 * @example <script src = "Hyphenator.js" type = "text/javascript"></script> 1990 * <script type = "text/javascript"> 1991 * Hyphenator.config({'minwordlength':4,'hyphenchar':'|'}); 1992 * Hyphenator.run(); 1993 * </script> 1994 */ 1995 config: function (obj) { 1996 var assert = function (name, type) { 1997 if (typeof obj[name] === type) { 1998 return true; 1999 } else { 2000 onError(new Error('Config onError: ' + name + ' must be of type ' + type)); 2001 return false; 2002 } 2003 }, 2004 key; 2005 2006 if (obj.hasOwnProperty('storagetype')) { 2007 if (assert('storagetype', 'string')) { 2008 storageType = obj.storagetype; 2009 } 2010 if (!storage) { 2011 createStorage(); 2012 } 2013 } 2014 if (!obj.hasOwnProperty('STORED') && storage && obj.hasOwnProperty('persistentconfig') && obj.persistentconfig === true) { 2015 restoreConfiguration(); 2016 } 2017 2018 for (key in obj) { 2019 if (obj.hasOwnProperty(key)) { 2020 switch (key) { 2021 case 'STORED': 2022 break; 2023 case 'classname': 2024 if (assert('classname', 'string')) { 2025 hyphenateClass = obj[key]; 2026 } 2027 break; 2028 case 'donthyphenateclassname': 2029 if (assert('donthyphenateclassname', 'string')) { 2030 dontHyphenateClass = obj[key]; 2031 } 2032 break; 2033 case 'minwordlength': 2034 if (assert('minwordlength', 'number')) { 2035 min = obj[key]; 2036 } 2037 break; 2038 case 'hyphenchar': 2039 if (assert('hyphenchar', 'string')) { 2040 if (obj.hyphenchar === '­') { 2041 obj.hyphenchar = String.fromCharCode(173); 2042 } 2043 hyphen = obj[key]; 2044 } 2045 break; 2046 case 'urlhyphenchar': 2047 if (obj.hasOwnProperty('urlhyphenchar')) { 2048 if (assert('urlhyphenchar', 'string')) { 2049 urlhyphen = obj[key]; 2050 } 2051 } 2052 break; 2053 case 'togglebox': 2054 if (assert('togglebox', 'function')) { 2055 toggleBox = obj[key]; 2056 } 2057 break; 2058 case 'displaytogglebox': 2059 if (assert('displaytogglebox', 'boolean')) { 2060 displayToggleBox = obj[key]; 2061 } 2062 break; 2063 case 'remoteloading': 2064 if (assert('remoteloading', 'boolean')) { 2065 enableRemoteLoading = obj[key]; 2066 } 2067 break; 2068 case 'enablecache': 2069 if (assert('enablecache', 'boolean')) { 2070 enableCache = obj[key]; 2071 } 2072 break; 2073 case 'enablereducedpatternset': 2074 if (assert('enablereducedpatternset', 'boolean')) { 2075 enableReducedPatternSet = obj[key]; 2076 } 2077 break; 2078 case 'onhyphenationdonecallback': 2079 if (assert('onhyphenationdonecallback', 'function')) { 2080 onHyphenationDone = obj[key]; 2081 } 2082 break; 2083 case 'onerrorhandler': 2084 if (assert('onerrorhandler', 'function')) { 2085 onError = obj[key]; 2086 } 2087 break; 2088 case 'intermediatestate': 2089 if (assert('intermediatestate', 'string')) { 2090 intermediateState = obj[key]; 2091 } 2092 break; 2093 case 'selectorfunction': 2094 if (assert('selectorfunction', 'function')) { 2095 selectorFunction = obj[key]; 2096 } 2097 break; 2098 case 'safecopy': 2099 if (assert('safecopy', 'boolean')) { 2100 safeCopy = obj[key]; 2101 } 2102 break; 2103 case 'doframes': 2104 if (assert('doframes', 'boolean')) { 2105 doFrames = obj[key]; 2106 } 2107 break; 2108 case 'storagetype': 2109 if (assert('storagetype', 'string')) { 2110 storageType = obj[key]; 2111 } 2112 break; 2113 case 'orphancontrol': 2114 if (assert('orphancontrol', 'number')) { 2115 orphanControl = obj[key]; 2116 } 2117 break; 2118 case 'dohyphenation': 2119 if (assert('dohyphenation', 'boolean')) { 2120 Hyphenator.doHyphenation = obj[key]; 2121 } 2122 break; 2123 case 'persistentconfig': 2124 if (assert('persistentconfig', 'boolean')) { 2125 persistentConfig = obj[key]; 2126 } 2127 break; 2128 case 'defaultlanguage': 2129 if (assert('defaultlanguage', 'string')) { 2130 defaultLanguage = obj[key]; 2131 } 2132 break; 2133 case 'useCSS3hyphenation': 2134 if (assert('useCSS3hyphenation', 'boolean')) { 2135 css3 = obj[key]; 2136 } 2137 break; 2138 case 'unhide': 2139 if (assert('unhide', 'string')) { 2140 unhide = obj[key]; 2141 } 2142 break; 2143 default: 2144 onError(new Error('Hyphenator.config: property ' + key + ' not known.')); 2145 } 2146 } 2147 } 2148 if (storage && persistentConfig) { 2149 storeConfiguration(); 2150 } 2151 }, 2152 2153 /** 2154 * @name Hyphenator.run
2155 * @description 2156 * Bootstrap function that starts all hyphenation processes when called. 2157 * @public 2158 * @example <script src = "Hyphenator.js" type = "text/javascript"></script> 2159 * <script type = "text/javascript"> 2160 * Hyphenator.run(); 2161 * </script> 2162 */ 2163 run: function () { 2164 documentCount = 0; 2165 var process = function () { 2166 try { 2167 if (contextWindow.document.getElementsByTagName('frameset').length > 0) { 2168 return; //we are in a frameset 2169 } 2170 documentCount++; 2171 autoSetMainLanguage(undefined); 2172 gatherDocumentInfos(); 2173 //console.log('preparing for ' + contextWindow.location.href); 2174 prepare(hyphenateLanguageElements); 2175 if (displayToggleBox) { 2176 toggleBox(); 2177 } 2178 } catch (e) { 2179 onError(e); 2180 } 2181 }, i, haveAccess, fl = window.frames.length; 2182 2183 if (!storage) { 2184 createStorage(); 2185 } 2186 if (!documentLoaded && !isBookmarklet) { 2187 runOnContentLoaded(window, process); 2188 } 2189 if (isBookmarklet || documentLoaded) { 2190 if (doFrames && fl > 0) { 2191 for (i = 0; i < fl; i++) { 2192 haveAccess = undefined; 2193 //try catch isn't enough for webkit 2194 try { 2195 //opera throws only on document.toString-access 2196 haveAccess = window.frames[i].document.toString(); 2197 } catch (e) { 2198 haveAccess = undefined; 2199 } 2200 if (!!haveAccess) { 2201 contextWindow = window.frames[i]; 2202 process(); 2203 } 2204 } 2205 } 2206 contextWindow = window; 2207 process(); 2208 } 2209 }, 2210 2211 /** 2212 * @name Hyphenator.addExceptions 2213 * @description 2214 * Adds the exceptions from the string to the appropriate language in the 2215 * {@link Hyphenator-languages}-object 2216 * @param {string} lang The language 2217 * @param {string} words A comma separated string of hyphenated words WITH spaces. 2218 * @public 2219 * @example <script src = "Hyphenator.js" type = "text/javascript"></script> 2220 * <script type = "text/javascript"> 2221 * Hyphenator.addExceptions('de','ziem-lich, Wach-stube'); 2222 * Hyphenator.run(); 2223 * </script> 2224 */ 2225 addExceptions: function (lang, words) { 2226 if (lang === '') { 2227 lang = 'global'; 2228 } 2229 if (exceptions.hasOwnProperty(lang)) { 2230 exceptions[lang] += ", " + words; 2231 } else { 2232 exceptions[lang] = words; 2233 } 2234 }, 2235 2236 /** 2237 * @name Hyphenator.hyphenate 2238 * @public 2239 * @description 2240 * Hyphenates the target. The language patterns must be loaded. 2241 * If the target is a string, the hyphenated string is returned, 2242 * if it's an object, the values are hyphenated directly. 2243 * @param {string|Object} target the target to be hyphenated 2244 * @param {string} lang the language of the target 2245 * @returns string 2246 * @example <script src = "Hyphenator.js" type = "text/javascript"></script> 2247 * <script src = "patterns/en.js" type = "text/javascript"></script> 2248 * <script type = "text/javascript"> 2249 * var t = Hyphenator.hyphenate('Hyphenation', 'en'); //Hy|phen|ation 2250 * </script> 2251 */ 2252 hyphenate: function (target, lang) { 2253 var hyphenate, n, i; 2254 if (Hyphenator.languages.hasOwnProperty(lang)) { 2255 if (!Hyphenator.languages[lang].prepared) { 2256 prepareLanguagesObj(lang); 2257 } 2258 hyphenate = function (word) { 2259 if (urlOrMailRE.test(word)) { 2260 return hyphenateURL(word); 2261 } else { 2262 return hyphenateWord(lang, word); 2263 } 2264 }; 2265 if (typeof target === 'string' || target.constructor === String) { 2266 return target.replace(Hyphenator.languages[lang].genRegExp, hyphenate); 2267 } else if (typeof target === 'object') { 2268 i = 0; 2269 while (!!(n = target.childNodes[i++])) { 2270 if (n.nodeType === 3 && n.data.length >= min) { //type 3 = #text -> hyphenate! 2271 n.data = n.data.replace(Hyphenator.languages[lang].genRegExp, hyphenate); 2272 } else if (n.nodeType === 1) { 2273 if (n.lang !== '') { 2274 Hyphenator.hyphenate(n, n.lang); 2275 } else { 2276 Hyphenator.hyphenate(n, lang); 2277 } 2278 } 2279 } 2280 } 2281 } else { 2282 onError(new Error('Language "' + lang + '" is not loaded.')); 2283 } 2284 }, 2285 2286 /** 2287 * @name Hyphenator.getRedPatternSet
2288 * @description 2289 * Returns {@link Hyphenator-isBookmarklet}. 2290 * @param {string} lang the language patterns are stored for 2291 * @returns object {'patk': pat} 2292 * @public 2293 */ 2294 getRedPatternSet: function (lang) { 2295 return Hyphenator.languages[lang].redPatSet; 2296 }, 2297 2298 /** 2299 * @name Hyphenator.isBookmarklet 2300 * @description 2301 * Returns {@link Hyphenator-isBookmarklet}. 2302 * @returns boolean 2303 * @public 2304 */ 2305 isBookmarklet: function () { 2306 return isBookmarklet; 2307 }, 2308 2309 getConfigFromURI: function () { 2310 var loc = null, re = {}, jsArray = document.getElementsByTagName('script'), i, j, l, s, gp, option; 2311 for (i = 0, l = jsArray.length; i < l; i++) { 2312 if (!!jsArray[i].getAttribute('src')) { 2313 loc = jsArray[i].getAttribute('src'); 2314 } 2315 if (!loc) { 2316 continue; 2317 } else { 2318 s = loc.indexOf('Hyphenator.js?'); 2319 if (s === -1) { 2320 continue; 2321 } 2322 gp = loc.substring(s + 14).split('&'); 2323 for (j = 0; j < gp.length; j++) { 2324 option = gp[j].split('='); 2325 if (option[0] === 'bm') { 2326 continue; 2327 } 2328 if (option[1] === 'true') { 2329 re[option[0]] = true; 2330 continue; 2331 } 2332 if (option[1] === 'false') { 2333 re[option[0]] = false; 2334 continue; 2335 } 2336 if (isFinite(option[1])) { 2337 re[option[0]] = parseInt(option[1], 10); 2338 continue; 2339 } 2340 if (option[0] === 'onhyphenationdonecallback') { 2341 re[option[0]] = new Function('', option[1]); 2342 continue; 2343 } 2344 re[option[0]] = option[1]; 2345 } 2346 break; 2347 } 2348 } 2349 return re; 2350 }, 2351 2352 /** 2353 * @name Hyphenator.toggleHyphenation 2354 * @description 2355 * Checks the current state of the ToggleBox and removes or does hyphenation. 2356 * @public 2357 */ 2358 toggleHyphenation: function () { 2359 if (Hyphenator.doHyphenation) { 2360 removeHyphenationFromDocument(); 2361 Hyphenator.doHyphenation = false; 2362 storeConfiguration(); 2363 toggleBox(); 2364 } else { 2365 hyphenateLanguageElements('*'); 2366 Hyphenator.doHyphenation = true; 2367 storeConfiguration(); 2368 toggleBox(); 2369 } 2370 } 2371 }; 2372}(window)); 2373 2374//Export properties/methods (for google closure compiler) 2375Hyphenator['languages'] = Hyphenator.languages; 2376Hyphenator['config'] = Hyphenator.config; 2377Hyphenator['run'] = Hyphenator.run; 2378Hyphenator['addExceptions'] = Hyphenator.addExceptions; 2379Hyphenator['hyphenate'] = Hyphenator.hyphenate; 2380Hyphenator['getRedPatternSet'] = Hyphenator.getRedPatternSet; 2381Hyphenator['isBookmarklet'] = Hyphenator.isBookmarklet; 2382Hyphenator['getConfigFromURI'] = Hyphenator.getConfigFromURI; 2383Hyphenator['toggleHyphenation'] = Hyphenator.toggleHyphenation; 2384window['Hyphenator'] = Hyphenator; 2385 2386if (Hyphenator.isBookmarklet()) { 2387 Hyphenator.config({displaytogglebox: true, intermediatestate: 'visible', doframes: true}); 2388 Hyphenator.config(Hyphenator.getConfigFromURI()); 2389 Hyphenator.run(); 2390}
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.