1/*! 2 * Hyphenator 2.5.0 - client side hyphenation for webbrowsers 3 * Copyright (C) 2010 Mathias Nater, Zürich (mathias at mnn dot ch) 4 * Project and Source hosted on http://code.google.com/p/hyphenator/ 5 * 6 * This JavaScript code is free software: you can redistribute 7 * it and/or modify it under the terms of the GNU Lesser 8 * General Public License (GNU LGPL) as published by the Free Software 9 * Foundation, either version 3 of the License, or (at your option) 10 * any later version. The code is distributed WITHOUT ANY WARRANTY; 11 * without even the implied warranty of MERCHANTABILITY or FITNESS 12 * FOR A PARTICULAR PURPOSE. See the GNU GPL for more details. 13 * 14 * As additional permission under GNU GPL version 3 section 7, you 15 * may distribute non-source (e.g., minimized or compacted) forms of 16 * that code without the copy of the GNU GPL normally required by 17 * section 4, provided you include this license notice and a URL 18 * through which recipients can access the Corresponding Source. 19 */ 20 21/* 22 * Comments are jsdoctoolkit formatted. See jsdoctoolkit.org 23 */ 24 25/* The following comment is for JSLint: */ 26/*global window, ActiveXObject, unescape */ 27/*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, newcap: true, immed: true */ 28 29/** 30 * @fileOverview 31 * A script that does hyphenation in (X)HTML files 32 * @author Mathias Nater, <a href = "mailto:mathias@mnn.ch">mathias@mnn.ch</a> 33 * @version 2.5.0 34 */ 35 36/** 37 * @constructor 38 * @description Provides all functionality to do hyphenation, except the patterns that are loaded 39 * externally. 40 * @namespace Holds all methods and properties 41 * @example 42 * <script src = "Hyphenator.js" type = "text/javascript"></script> 43 * <script type = "text/javascript"> 44 * Hyphenator.run(); 45 * </script> 46 */ 47var Hyphenator = (function () { 48 49 50 /** 51 * @name Hyphenator-languageHint 52 * @fieldOf Hyphenator 53 * @description 54 * A string to be displayed in a prompt if the language can't be guessed. 55 * If you add hyphenation patterns change this string. 56 * Internally, this string is used to define languages that are supported by Hyphenator. 57 * @see Hyphenator-supportedLang 58 * @type string 59 * @private 60 * @see Hyphenator-autoSetMainLanguage 61 */ 62 var languageHint = 'en, am', 63 64 /** 65 * @name Hyphenator-supportedLang 66 * @fieldOf Hyphenator 67 * @description 68 * A generated key-value object that stores supported languages. 69 * The languages are retrieved from {@link Hyphenator-languageHint}. 70 * @type object 71 * @private 72 * @example 73 * Check if language lang is supported: 74 * if (supportedLang[lang]) 75 */ 76 supportedLang = (function () { 77 var k, i = 0, a = languageHint.split(', '), r = {}; 78 while (!!(k = a[i++])) { 79 r[k] = true; 80 } 81 return r; 82 }()), 83 84 /** 85 * @name Hyphenator-prompterStrings 86 * @fieldOf Hyphenator 87 * @description 88 * A key-value object holding the strings to be displayed if the language can't be guessed 89 * If you add hyphenation patterns change this string. 90 * @type object 91 * @private 92 * @see Hyphenator-autoSetMainLanguage 93 */ 94 prompterStrings = { 95 'en': 'The language of this website could not be determined automatically. Please indicate the main language:', 96 'am': 'x' 97 }, 98 99 /** 100 * @name Hyphenator-basePath 101 * @fieldOf Hyphenator 102 * @description 103 * A string storing the basepath from where Hyphenator.js was loaded. 104 * This is used to load the patternfiles. 105 * The basepath is determined dynamically by searching all script-tags for Hyphenator.js 106 * If the path cannot be determined http://hyphenator.googlecode.com/svn/trunk/ is used as fallback. 107 * @type string 108 * @private 109 * @see Hyphenator-loadPatterns 110 */ 111 basePath = (function () { 112 var s = document.getElementsByTagName('script'), i = 0, p, src, t; 113 while (!!(t = s[i++])) { 114 if (!t.src) { 115 continue; 116 } 117 src = t.src; 118 p = src.indexOf('Hyphenator.js'); 119 if (p !== -1) { 120 return src.substring(0, p); 121 } 122 } 123 return 'http://hyphenator.googlecode.com/svn/trunk/'; 124 }()), 125 126 /** 127 * @name Hyphenator-isLocal 128 * @fieldOf Hyphenator 129 * @description 130 * isLocal is true, if Hyphenator is loaded from the same domain, as the webpage, but false, if 131 * it's loaded from an external source (i.e. directly from google.code) 132 */ 133 isLocal = (function () { 134 var re = false; 135 if (window.location.href.indexOf(basePath) !== -1) { 136 re = true; 137 } 138 return re; 139 }()), 140 141 /** 142 * @name Hyphenator-documentLoaded 143 * @fieldOf Hyphenator 144 * @description 145 * documentLoaded is true, when the DOM has been loaded. This is set by runOnContentLoaded 146 */ 147 documentLoaded = false, 148 149 /** 150 * @name Hyphenator-dontHyphenate 151 * @fieldOf Hyphenator 152 * @description 153 * A key-value object containing all html-tags whose content should not be hyphenated 154 * @type object 155 * @private 156 * @see Hyphenator-hyphenateElement 157 */ 158 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}, 159 160 /** 161 * @name Hyphenator-enableCache 162 * @fieldOf Hyphenator 163 * @description 164 * A variable to set if caching is enabled or not 165 * @type boolean 166 * @default true 167 * @private 168 * @see Hyphenator.config 169 * @see hyphenateWord 170 */ 171 enableCache = true, 172 173 /** 174 * @name Hyphenator-enableReducedPatternSet 175 * @fieldOf Hyphenator 176 * @description 177 * A variable to set if storing the used patterns is set 178 * @type boolean 179 * @default false 180 * @private 181 * @see Hyphenator.config 182 * @see hyphenateWord 183 * @see Hyphenator.getRedPatternSet 184 */ 185 enableReducedPatternSet = false, 186 187 /** 188 * @name Hyphenator-enableRemoteLoading 189 * @fieldOf Hyphenator 190 * @description 191 * A variable to set if pattern files should be loaded remotely or not 192 * @type boolean 193 * @default true 194 * @private 195 * @see Hyphenator.config 196 * @see Hyphenator-loadPatterns 197 */ 198 enableRemoteLoading = true, 199 200 /** 201 * @name Hyphenator-displayToggleBox 202 * @fieldOf Hyphenator 203 * @description 204 * A variable to set if the togglebox should be displayed or not 205 * @type boolean 206 * @default false 207 * @private 208 * @see Hyphenator.config 209 * @see Hyphenator-toggleBox 210 */ 211 displayToggleBox = false, 212 213 /** 214 * @name Hyphenator-hyphenateClass 215 * @fieldOf Hyphenator 216 * @description 217 * A string containing the css-class-name for the hyphenate class 218 * @type string 219 * @default 'hyphenate' 220 * @private 221 * @example 222 * <p class = "hyphenate">Text</p> 223 * @see Hyphenator.config 224 */ 225 hyphenateClass = 'hyphenate', 226 227 /** 228 * @name Hyphenator-dontHyphenateClass 229 * @fieldOf Hyphenator 230 * @description 231 * A string containing the css-class-name for elements that should not be hyphenated 232 * @type string 233 * @default 'donthyphenate' 234 * @private 235 * @example 236 * <p class = "donthyphenate">Text</p> 237 * @see Hyphenator.config 238 */ 239 dontHyphenateClass = 'donthyphenate', 240 241 /** 242 * @name Hyphenator-min 243 * @fieldOf Hyphenator 244 * @description 245 * A number wich indicates the minimal length of words to hyphenate. 246 * @type number 247 * @default 6 248 * @private 249 * @see Hyphenator.config 250 */ 251 min = 6, 252 253 /** 254 * @name Hyphenator-isBookmarklet 255 * @fieldOf Hyphenator 256 * @description 257 * Indicates if Hyphanetor runs as bookmarklet or not. 258 * @type boolean 259 * @default false 260 * @private 261 */ 262 isBookmarklet = (function () { 263 var loc = null, re = false, jsArray = document.getElementsByTagName('script'), i, l; 264 for (i = 0, l = jsArray.length; i < l; i++) { 265 if (!!jsArray[i].getAttribute('src')) { 266 loc = jsArray[i].getAttribute('src'); 267 } 268 if (!loc) { 269 continue; 270 } else if (loc.indexOf('Hyphenator.js?bm=true') !== -1) { 271 re = true; 272 } 273 } 274 return re; 275 }()), 276 277 /** 278 * @name Hyphenator-mainLanguage 279 * @fieldOf Hyphenator 280 * @description 281 * The general language of the document 282 * @type number 283 * @private 284 * @see Hyphenator-autoSetMainLanguage 285 */ 286 mainLanguage = null, 287 288 /** 289 * @name Hyphenator-elements 290 * @fieldOf Hyphenator 291 * @description 292 * An array holding all elements that have to be hyphenated. This var is filled by 293 * {@link Hyphenator-gatherDocumentInfos} 294 * @type array 295 * @private 296 */ 297 elements = [], 298 299 /** 300 * @name Hyphenator-exceptions 301 * @fieldOf Hyphenator 302 * @description 303 * An object containing exceptions as comma separated strings for each language. 304 * When the language-objects are loaded, their exceptions are processed, copied here and then deleted. 305 * @see Hyphenator-prepareLanguagesObj 306 * @type object 307 * @private 308 */ 309 exceptions = {}, 310 311 /** 312 * @name Hyphenator-docLanguages 313 * @fieldOf Hyphenator 314 * @description 315 * An object holding all languages used in the document. This is filled by 316 * {@link Hyphenator-gatherDocumentInfos} 317 * @type object 318 * @private 319 */ 320 docLanguages = {}, 321 322 323 /** 324 * @name Hyphenator-state 325 * @fieldOf Hyphenator 326 * @description 327 * A number that inidcates the current state of the script 328 * 0: not initialized 329 * 1: loading patterns 330 * 2: ready 331 * 3: hyphenation done 332 * 4: hyphenation removed 333 * @type number 334 * @private 335 */ 336 state = 0, 337 338 /** 339 * @name Hyphenator-url 340 * @fieldOf Hyphenator 341 * @description 342 * A string containing a RegularExpression to match URL's 343 * @type string 344 * @private 345 */ 346 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#!:\\.?\\+=&%@!\\-]*)*', 347 // protocoll usr pwd ip or host tld port path 348 /** 349 * @name Hyphenator-mail 350 * @fieldOf Hyphenator 351 * @description 352 * A string containing a RegularExpression to match mail-adresses 353 * @type string 354 * @private 355 */ 356 mail = '[\\w-\\.]+@[\\w\\.]+', 357 358 /** 359 * @name Hyphenator-urlRE 360 * @fieldOf Hyphenator 361 * @description 362 * A RegularExpressions-Object for url- and mail adress matching 363 * @type object 364 * @private 365 */ 366 urlOrMailRE = new RegExp('(' + url + ')|(' + mail + ')', 'i'), 367 368 /** 369 * @name Hyphenator-zeroWidthSpace 370 * @fieldOf Hyphenator 371 * @description 372 * A string that holds a char. 373 * Depending on the browser, this is the zero with space or an empty string. 374 * zeroWidthSpace is used to break URLs 375 * @type string 376 * @private 377 */ 378 zeroWidthSpace = (function () { 379 var zws, ua = navigator.userAgent.toLowerCase(); 380 zws = String.fromCharCode(8203); //Unicode zero width space 381 if (ua.indexOf('msie 6') !== -1) { 382 zws = ''; //IE6 doesn't support zws 383 } 384 if (ua.indexOf('opera') !== -1 && ua.indexOf('version/10.00') !== -1) { 385 zws = ''; //opera 10 on XP doesn't support zws 386 } 387 return zws; 388 //return '[zws]'; 389 }()), 390 391 /** 392 * @name Hyphenator-createElem 393 * @fieldOf Hyphenator 394 * @description 395 * A function alias to document.createElementNS or document.createElement 396 * @type function 397 * @private 398 */ 399 createElem = function (tagname) { 400 if (document.createElementNS) { 401 return document.createElementNS('http://www.w3.org/1999/xhtml', tagname); 402 } else if (document.createElement) { 403 return document.createElement(tagname); 404 } 405 }, 406 407 /** 408 * @name Hyphenator-onHyphenationDone 409 * @fieldOf Hyphenator 410 * @description 411 * A method to be called, when the last element has been hyphenated or the hyphenation has been 412 * removed from the last element. 413 * @see Hyphenator.config 414 * @type function 415 * @private 416 */ 417 onHyphenationDone = function () {}, 418 419 /** 420 * @name Hyphenator-onError 421 * @fieldOf Hyphenator 422 * @description 423 * A function that can be called upon an error. 424 * @see Hyphenator.config 425 * @type function 426 * @private 427 */ 428 onError = function (e) { 429 window.alert("Hyphenator.js says:\n\nAn Error ocurred:\n" + e.message); 430 }, 431 432 /** 433 * @name Hyphenator-selectorFunction 434 * @fieldOf Hyphenator 435 * @description 436 * A function that has to return a HTMLNodeList of Elements to be hyphenated. 437 * By default it uses the classname ('hyphenate') to select the elements. 438 * @see Hyphenator.config 439 * @type function 440 * @private 441 */ 442 selectorFunction = function () { 443 var tmp, el = [], i, l; 444 if (document.getElementsByClassName) { 445 el = document.getElementsByClassName(hyphenateClass); 446 } else { 447 tmp = document.getElementsByTagName('*'); 448 l = tmp.length; 449 for (i = 0; i < l; i++) 450 { 451 if (tmp[i].className.indexOf(hyphenateClass) !== -1 && tmp[i].className.indexOf(dontHyphenateClass) === -1) { 452 el.push(tmp[i]); 453 } 454 } 455 } 456 return el; 457 }, 458 459 /** 460 * @name Hyphenator-intermediateState 461 * @fieldOf Hyphenator 462 * @description 463 * The value of style.visibility of the text while it is hyphenated. 464 * @see Hyphenator.config 465 * @type string 466 * @private 467 */ 468 intermediateState = 'hidden', 469 470 /** 471 * @name Hyphenator-hyphen 472 * @fieldOf Hyphenator 473 * @description 474 * A string containing the character for in-word-hyphenation 475 * @type string 476 * @default the soft hyphen 477 * @private 478 * @see Hyphenator.config 479 */ 480 hyphen = String.fromCharCode(173), 481 482 /** 483 * @name Hyphenator-urlhyphen 484 * @fieldOf Hyphenator 485 * @description 486 * A string containing the character for url/mail-hyphenation 487 * @type string 488 * @default the zero width space 489 * @private 490 * @see Hyphenator.config 491 * @see Hyphenator-zeroWidthSpace 492 */ 493 urlhyphen = zeroWidthSpace, 494 495 /** 496 * @name Hyphenator-Expando 497 * @methodOf Hyphenator 498 * @description 499 * This custom object stores data for elements: storing data directly in elements 500 * (DomElement.customData = foobar;) isn't a good idea. It would lead to conflicts 501 * in form elements, when the form has a child with name="foobar". Therefore, this 502 * solution follows the approach of jQuery: the data is stored in an object and 503 * referenced by a unique attribute of the element. The attribute has a name that 504 * is built by the prefix "HyphenatorExpando_" and a random number, so if the very 505 * very rare case occurs, that there's already an attribute with the same name, a 506 * simple reload is enough to make it function. 507 * @private 508 */ 509 Expando = (function () { 510 var container = {}, 511 name = "HyphenatorExpando_" + Math.random(), 512 uuid = 0; 513 return { 514 getDataForElem : function (elem) { 515 return container[elem[name]]; 516 }, 517 setDataForElem : function (elem, data) { 518 var id; 519 if (elem[name] && elem[name] !== '') { 520 id = elem[name]; 521 } else { 522 id = uuid++; 523 elem[name] = id; 524 } 525 container[id] = data; 526 }, 527 appendDataForElem : function (elem, data) { 528 var k; 529 for (k in data) { 530 if (data.hasOwnProperty(k)) { 531 container[elem[name]][k] = data[k]; 532 } 533 } 534 }, 535 delDataOfElem : function (elem) { 536 delete container[elem[name]]; 537 } 538 }; 539 }()), 540 541 /* 542 * runOnContentLoaded is based od jQuery.bindReady() 543 * see 544 * jQuery JavaScript Library v1.3.2 545 * http://jquery.com/ 546 * 547 * Copyright (c) 2009 John Resig 548 * Dual licensed under the MIT and GPL licenses. 549 * http://docs.jquery.com/License 550 * 551 * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009) 552 * Revision: 6246 553 */ 554 /** 555 * @name Hyphenator-runOnContentLoaded 556 * @methodOf Hyphenator 557 * @description 558 * A crossbrowser solution for the DOMContentLoaded-Event based on jQuery 559 * <a href = "http://jquery.com/</a> 560 * @param object the window-object 561 * @param function-object the function to call onDOMContentLoaded 562 * @private 563 */ 564 runOnContentLoaded = function (w, f) { 565 var DOMContentLoaded, toplevel; 566 if (documentLoaded) { 567 f(); 568 return; 569 } 570 function init() { 571 if (!documentLoaded) { 572 documentLoaded = true; 573 f(); 574 } 575 } 576 577 function doScrollCheck() { 578 try { 579 // If IE is used, use the trick by Diego Perini 580 // http://javascript.nwbox.com/IEContentLoaded/ 581 document.documentElement.doScroll("left"); 582 } catch (error) { 583 setTimeout(doScrollCheck, 1); 584 return; 585 } 586 587 // and execute any waiting functions 588 init(); 589 } 590 591 592 // Cleanup functions for the document ready method 593 if (document.addEventListener) { 594 DOMContentLoaded = function () { 595 document.removeEventListener("DOMContentLoaded", DOMContentLoaded, false); 596 init(); 597 }; 598 599 } else if (document.attachEvent) { 600 DOMContentLoaded = function () { 601 // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). 602 if (document.readyState === "complete") { 603 document.detachEvent("onreadystatechange", DOMContentLoaded); 604 init(); 605 } 606 }; 607 } 608 609 // Mozilla, Opera and webkit nightlies currently support this event 610 if (document.addEventListener) { 611 // Use the handy event callback 612 document.addEventListener("DOMContentLoaded", DOMContentLoaded, false); 613 614 // A fallback to window.onload, that will always work 615 window.addEventListener("load", init, false); 616 617 // If IE event model is used 618 } else if (document.attachEvent) { 619 // ensure firing before onload, 620 // maybe late but safe also for iframes 621 document.attachEvent("onreadystatechange", DOMContentLoaded); 622 623 // A fallback to window.onload, that will always work 624 window.attachEvent("onload", init); 625 626 // If IE and not a frame 627 // continually check to see if the document is ready 628 toplevel = false; 629 try { 630 toplevel = window.frameElement === null; 631 } catch (e) {} 632 633 if (document.documentElement.doScroll && toplevel) { 634 doScrollCheck(); 635 } 636 } 637 638 }, 639 640 641 642 /** 643 * @name Hyphenator-getLang 644 * @methodOf Hyphenator 645 * @description 646 * Gets the language of an element. If no language is set, it may use the {@link Hyphenator-mainLanguage}. 647 * @param object The first parameter is an DOM-Element-Object 648 * @param boolean The second parameter is a boolean to tell if the function should return the {@link Hyphenator-mainLanguage} 649 * if there's no language found for the element. 650 * @private 651 */ 652 getLang = function (el, fallback) { 653 if (!!el.getAttribute('lang')) { 654 return el.getAttribute('lang').substring(0, 2).toLowerCase(); 655 } 656 // The following doesn't work in IE due to a bug when getAttribute('xml:lang') in a table 657 /*if (!!el.getAttribute('xml:lang')) { 658 return el.getAttribute('xml:lang').substring(0, 2); 659 }*/ 660 //instead, we have to do this (thanks to borgzor): 661 try { 662 if (!!el.getAttribute('xml:lang')) { 663 return el.getAttribute('xml:lang').substring(0, 2).toLowerCase(); 664 } 665 } catch (ex) {} 666 if (el.tagName !== 'HTML') { 667 return getLang(el.parentNode, true); 668 } 669 if (fallback) { 670 return mainLanguage; 671 } 672 return null; 673 }, 674 675 /** 676 * @name Hyphenator-autoSetMainLanguage 677 * @methodOf Hyphenator 678 * @description 679 * Retrieves the language of the document from the DOM. 680 * The function looks in the following places: 681 * <ul> 682 * <li>lang-attribute in the html-tag</li> 683 * <li><meta http-equiv = "content-language" content = "xy" /></li> 684 * <li><meta name = "DC.Language" content = "xy" /></li> 685 * <li><meta name = "language" content = "xy" /></li> 686 * </li> 687 * If nothing can be found a prompt using {@link Hyphenator-languageHint} and {@link Hyphenator-prompterStrings} is displayed. 688 * If the retrieved language is in the object {@link Hyphenator-supportedLang} it is copied to {@link Hyphenator-mainLanguage} 689 * @private 690 */ 691 autoSetMainLanguage = function () { 692 var el = document.getElementsByTagName('html')[0], 693 m = document.getElementsByTagName('meta'), 694 i, text, lang, e, ul; 695 mainLanguage = getLang(el); 696 if (!mainLanguage) { 697 for (i = 0; i < m.length; i++) { 698 //<meta http-equiv = "content-language" content="xy"> 699 if (!!m[i].getAttribute('http-equiv') && (m[i].getAttribute('http-equiv') === 'content-language')) { 700 mainLanguage = m[i].getAttribute('content').substring(0, 2).toLowerCase(); 701 } 702 //<meta name = "DC.Language" content="xy"> 703 if (!!m[i].getAttribute('name') && (m[i].getAttribute('name') === 'DC.language')) { 704 mainLanguage = m[i].getAttribute('content').substring(0, 2).toLowerCase(); 705 } 706 //<meta name = "language" content = "xy"> 707 if (!!m[i].getAttribute('name') && (m[i].getAttribute('name') === 'language')) { 708 mainLanguage = m[i].getAttribute('content').substring(0, 2).toLowerCase(); 709 } 710 } 711 } 712 if (!mainLanguage) { 713 text = ''; 714 ul = navigator.language ? navigator.language : navigator.userLanguage; 715 ul = ul.substring(0, 2); 716 if (prompterStrings.hasOwnProperty(ul)) { 717 text = prompterStrings[ul]; 718 } else { 719 text = prompterStrings.en; 720 } 721 text += ' (ISO 639-1)\n\n' + languageHint; 722 lang = window.prompt(unescape(text), ul).toLowerCase(); 723 if (supportedLang[lang]) { 724 mainLanguage = lang; 725 } else { 726 e = new Error('The language "' + lang + '" is not yet supported.'); 727 throw e; 728 } 729 } 730 }, 731 732 /** 733 * @name Hyphenator-gatherDocumentInfos 734 * @methodOf Hyphenator 735 * @description 736 * This method runs through the DOM and executes the process()-function on: 737 * - every node returned by the {@link Hyphenator-selectorFunction}. 738 * The process()-function copies the element to the elements-variable, sets its visibility 739 * to intermediateState, retrieves its language and recursivly descends the DOM-tree until 740 * the child-Nodes aren't of type 1 741 * @private 742 */ 743 gatherDocumentInfos = function () { 744 var elToProcess, tmp, i = 0, 745 process = function (el, hide, lang) { 746 var n, i = 0, hyphenatorSettings = {}; 747 if (hide && intermediateState === 'hidden') { 748 if (!!el.getAttribute('style')) { 749 hyphenatorSettings.hasOwnStyle = true; 750 } else { 751 hyphenatorSettings.hasOwnStyle = false; 752 } 753 hyphenatorSettings.isHidden = true; 754 el.style.visibility = 'hidden'; 755 } 756 if (el.lang && typeof(el.lang) === 'string') { 757 hyphenatorSettings.language = el.lang.toLowerCase(); //copy attribute-lang to internal lang 758 } else if (lang) { 759 hyphenatorSettings.language = lang.toLowerCase(); 760 } else { 761 hyphenatorSettings.language = getLang(el, true); 762 } 763 lang = hyphenatorSettings.language; 764 if (supportedLang[lang]) { 765 docLanguages[lang] = true; 766 } else { 767 if (!Hyphenator.isBookmarklet()) { 768 onError(new Error('Language ' + lang + ' is not yet supported.')); 769 } 770 } 771 Expando.setDataForElem(el, hyphenatorSettings); 772 elements.push(el); 773 while (!!(n = el.childNodes[i++])) { 774 if (n.nodeType === 1 && !dontHyphenate[n.nodeName.toLowerCase()] && 775 n.className.indexOf(dontHyphenateClass) === -1 && !(n in elToProcess)) { 776 process(n, false, lang); 777 } 778 } 779 }; 780 if (Hyphenator.isBookmarklet()) { 781 elToProcess = document.getElementsByTagName('body')[0]; 782 process(elToProcess, false, mainLanguage); 783 } else { 784 elToProcess = selectorFunction(); 785 while (!!(tmp = elToProcess[i++])) 786 { 787 process(tmp, true); 788 } 789 } 790 if (!Hyphenator.languages.hasOwnProperty(mainLanguage)) { 791 docLanguages[mainLanguage] = true; 792 } else if (!Hyphenator.languages[mainLanguage].prepared) { 793 docLanguages[mainLanguage] = true; 794 } 795 if (elements.length > 0) { 796 Expando.appendDataForElem(elements[elements.length - 1], {isLast : true}); 797 } 798 }, 799 800 /** 801 * @name Hyphenator-convertPatterns 802 * @methodOf Hyphenator 803 * @description 804 * Converts the patterns from string '_a6' to object '_a':'_a6'. 805 * The result is stored in the {@link Hyphenator-patterns}-object. 806 * @private 807 * @param string the language whose patterns shall be converted 808 */ 809 convertPatterns = function (lang) { 810 var plen, anfang, pats, pat, key, tmp = {}; 811 pats = Hyphenator.languages[lang].patterns; 812 for (plen in pats) { 813 if (pats.hasOwnProperty(plen)) { 814 plen = parseInt(plen, 10); 815 anfang = 0; 816 while (!!(pat = pats[plen].substr(anfang, plen))) { 817 key = pat.replace(/\d/g, ''); 818 tmp[key] = pat; 819 anfang += plen; 820 } 821 } 822 } 823 Hyphenator.languages[lang].patterns = tmp; 824 Hyphenator.languages[lang].patternsConverted = true; 825 }, 826 827 /** 828 * @name Hyphenator-convertExceptionsToObject 829 * @methodOf Hyphenator 830 * @description 831 * Converts a list of comma seprated exceptions to an object: 832 * 'Fortran,Hy-phen-a-tion' -> {'Fortran':'Fortran','Hyphenation':'Hy-phen-a-tion'} 833 * @private 834 * @param string a comma separated string of exceptions (without spaces) 835 */ 836 convertExceptionsToObject = function (exc) { 837 var w = exc.split(', '), 838 r = {}, 839 i, l, key; 840 for (i = 0, l = w.length; i < l; i++) { 841 key = w[i].replace(/-/g, ''); 842 if (!r.hasOwnProperty(key)) { 843 r[key] = w[i]; 844 } 845 } 846 return r; 847 }, 848 849 /** 850 * @name Hyphenator-loadPatterns 851 * @methodOf Hyphenator 852 * @description 853 * Adds a <script>-Tag to the DOM to load an externeal .js-file containing patterns and settings for the given language. 854 * If the iven language is not in the {@link Hyphenator-supportedLang}-Object it returns. 855 * One may ask why we are not using AJAX to load the patterns. The XMLHttpRequest-Object 856 * has a same-origin-policy. This makes the isBookmarklet-functionality impossible. 857 * @param string The language to load the patterns for 858 * @private 859 * @see Hyphenator-basePath 860 */ 861 loadPatterns = function (lang) { 862 var url, xhr, head, script; 863 if (supportedLang[lang] && !Hyphenator.languages[lang]) { 864 url = basePath + 'patterns/' + lang + '.js'; 865 } else { 866 return; 867 } 868 if (isLocal && !isBookmarklet) { 869 //check if 'url' is available: 870 xhr = null; 871 if (typeof XMLHttpRequest !== 'undefined') { 872 xhr = new XMLHttpRequest(); 873 } 874 if (!xhr) { 875 try { 876 xhr = new ActiveXObject("Msxml2.XMLHTTP"); 877 } catch (e) { 878 xhr = null; 879 } 880 } 881 if (xhr) { 882 xhr.open('HEAD', url, false); 883 xhr.setRequestHeader('Cache-Control', 'no-cache'); 884 xhr.send(null); 885 if (xhr.status === 404) { 886 onError(new Error('Could not load\n' + url)); 887 delete docLanguages[lang]; 888 return; 889 } 890 } 891 } 892 if (createElem) { 893 head = document.getElementsByTagName('head').item(0); 894 script = createElem('script'); 895 script.src = url; 896 script.type = 'text/javascript'; 897 head.appendChild(script); 898 } 899 }, 900 901 /** 902 * @name Hyphenator-prepareLanguagesObj 903 * @methodOf Hyphenator 904 * @description 905 * Adds a cache to each language and converts the exceptions-list to an object. 906 * @private 907 * @param string the language ob the lang-obj 908 */ 909 prepareLanguagesObj = function (lang) { 910 var lo = Hyphenator.languages[lang], wrd; 911 if (!lo.prepared) { 912 if (enableCache) { 913 lo.cache = {}; 914 } 915 if (enableReducedPatternSet) { 916 lo.redPatSet = {}; 917 } 918 if (lo.hasOwnProperty('exceptions')) { 919 Hyphenator.addExceptions(lang, lo.exceptions); 920 delete lo.exceptions; 921 } 922 if (exceptions.hasOwnProperty('global')) { 923 if (exceptions.hasOwnProperty(lang)) { 924 exceptions[lang] += ', ' + exceptions.global; 925 } else { 926 exceptions[lang] = exceptions.global; 927 } 928 } 929 if (exceptions.hasOwnProperty(lang)) { 930 lo.exceptions = convertExceptionsToObject(exceptions[lang]); 931 delete exceptions[lang]; 932 } else { 933 lo.exceptions = {}; 934 } 935 convertPatterns(lang); 936 wrd = '[\\w' + lo.specialChars + '@' + String.fromCharCode(173) + '-]{' + min + ',}'; 937 lo.genRegExp = new RegExp('(' + url + ')|(' + mail + ')|(' + wrd + ')', 'gi'); 938 lo.prepared = true; 939 } 940 }, 941 942 /** 943 * @name Hyphenator-prepare 944 * @methodOf Hyphenator 945 * @description 946 * This funtion prepares the Hyphenator-Object: If RemoteLoading is turned off, it assumes 947 * that the patternfiles are loaded, all conversions are made and the callback is called. 948 * If RemoteLoading is on (default), it loads the pattern files and waits until they are loaded, 949 * by repeatedly checking Hyphenator.languages. If a patterfile is loaded the patterns are 950 * converted to their object style and the lang-object extended. 951 * Finally the callback is called. 952 * @param function-object callback to call, when all patterns are loaded 953 * @private 954 */ 955 prepare = function (callback) { 956 var lang, docLangEmpty = true, interval; 957 if (!enableRemoteLoading) { 958 for (lang in Hyphenator.languages) { 959 if (Hyphenator.languages.hasOwnProperty(lang)) { 960 prepareLanguagesObj(lang); 961 } 962 } 963 state = 2; 964 callback(); 965 return; 966 } 967 // get all languages that are used and preload the patterns 968 state = 1; 969 for (lang in docLanguages) { 970 if (docLanguages.hasOwnProperty(lang)) { 971 loadPatterns(lang); 972 docLangEmpty = false; 973 } 974 } 975 if (docLangEmpty) { 976 state = 2; 977 callback(); 978 return; 979 } 980 // wait until they are loaded 981 interval = window.setInterval(function () { 982 var finishedLoading = false, lang; 983 for (lang in docLanguages) { 984 if (docLanguages.hasOwnProperty(lang)) { 985 if (!Hyphenator.languages[lang]) { 986 finishedLoading = false; 987 break; 988 } else { 989 finishedLoading = true; 990 delete docLanguages[lang]; 991 //do conversion while other patterns are loading: 992 prepareLanguagesObj(lang); 993 } 994 } 995 } 996 if (finishedLoading) { 997 window.clearInterval(interval); 998 state = 2; 999 callback(); 1000 } 1001 }, 100); 1002 }, 1003 1004 /** 1005 * @name Hyphenator-switchToggleBox 1006 * @methodOf Hyphenator 1007 * @description 1008 * Creates or hides the toggleBox: a small button to turn off/on hyphenation on a page. 1009 * @param boolean true when hyphenation is on, false when it's off 1010 * @see Hyphenator.config 1011 * @private 1012 */ 1013 toggleBox = function (s) { 1014 var myBox, bdy, myIdAttribute, myTextNode, myClassAttribute; 1015 if (!!(myBox = document.getElementById('HyphenatorToggleBox'))) { 1016 if (s) { 1017 myBox.firstChild.data = 'Hy-phe-na-ti-on'; 1018 } else { 1019 myBox.firstChild.data = 'Hyphenation'; 1020 } 1021 } else { 1022 bdy = document.getElementsByTagName('body')[0]; 1023 myBox = createElem('div'); 1024 myIdAttribute = document.createAttribute('id'); 1025 myIdAttribute.nodeValue = 'HyphenatorToggleBox'; 1026 myClassAttribute = document.createAttribute('class'); 1027 myClassAttribute.nodeValue = dontHyphenateClass; 1028 myTextNode = document.createTextNode('Hy-phe-na-ti-on'); 1029 myBox.appendChild(myTextNode); 1030 myBox.setAttributeNode(myIdAttribute); 1031 myBox.setAttributeNode(myClassAttribute); 1032 myBox.onclick = Hyphenator.toggleHyphenation; 1033 myBox.style.position = 'absolute'; 1034 myBox.style.top = '0px'; 1035 myBox.style.right = '0px'; 1036 myBox.style.margin = '0'; 1037 myBox.style.backgroundColor = '#AAAAAA'; 1038 myBox.style.color = '#FFFFFF'; 1039 myBox.style.font = '6pt Arial'; 1040 myBox.style.letterSpacing = '0.2em'; 1041 myBox.style.padding = '3px'; 1042 myBox.style.cursor = 'pointer'; 1043 myBox.style.WebkitBorderBottomLeftRadius = '4px'; 1044 myBox.style.MozBorderRadiusBottomleft = '4px'; 1045 bdy.appendChild(myBox); 1046 } 1047 }, 1048 1049 /** 1050 * @name Hyphenator-hyphenateWord 1051 * @methodOf Hyphenator 1052 * @description 1053 * This function is the heart of Hyphenator.js. It returns a hyphenated word. 1054 * 1055 * If there's already a {@link Hyphenator-hypen} in the word, the word is returned as it is. 1056 * If the word is in the exceptions list or in the cache, it is retrieved from it. 1057 * If there's a '-' put a zeroWidthSpace after the '-' and hyphenate the parts. 1058 * @param string The language of the word 1059 * @param string The word 1060 * @returns string The hyphenated word 1061 * @public 1062 */ 1063 hyphenateWord = function (lang, word) { 1064 var lo = Hyphenator.languages[lang], 1065 parts, i, l, w, wl, s, hypos, p, maxwins, win, pat = false, patk, patl, c, digits, z, numb3rs, n, inserted, hyphenatedword; 1066 if (word === '') { 1067 return ''; 1068 } 1069 if (word.indexOf(hyphen) !== -1) { 1070 //word already contains shy; -> leave at it is! 1071 return word; 1072 } 1073 if (enableCache && lo.cache.hasOwnProperty(word)) { //the word is in the cache 1074 return lo.cache[word]; 1075 } 1076 if (lo.exceptions.hasOwnProperty(word)) { //the word is in the exceptions list 1077 return lo.exceptions[word].replace(/-/g, hyphen); 1078 } 1079 if (word.indexOf('-') !== -1) { 1080 //word contains '-' -> hyphenate the parts separated with '-' 1081 parts = word.split('-'); 1082 for (i = 0, l = parts.length; i < l; i++) { 1083 parts[i] = hyphenateWord(lang, parts[i]); 1084 } 1085 return parts.join('-'); 1086 } 1087 //finally the core hyphenation algorithm 1088 w = '_' + word + '_'; 1089 wl = w.length; 1090 s = w.split(''); 1091 w = w.toLowerCase(); 1092 hypos = []; 1093 numb3rs = {'0': true, '1': true, '2': true, '3': true, '4': true, '5': true, '6': true, '7': true, '8': true, '9': true}; //check for member is faster then isFinite() 1094 n = wl - lo.shortestPattern; 1095 for (p = 0; p <= n; p++) { 1096 maxwins = Math.min((wl - p), lo.longestPattern); 1097 for (win = lo.shortestPattern; win <= maxwins; win++) { 1098 if (lo.patterns.hasOwnProperty(patk = w.substr(p, win))) { 1099 pat = lo.patterns[patk]; 1100 } else { 1101 continue; 1102 } 1103 if (enableReducedPatternSet) { 1104 lo.redPatSet[patk] = pat; 1105 } 1106 digits = 1; 1107 patl = pat.length; 1108 for (i = 0; i < patl; i++) { 1109 c = pat.charAt(i); 1110 if (numb3rs[c]) { 1111 if (i === 0) { 1112 z = p - 1; 1113 if (!hypos[z] || hypos[z] < c) { 1114 hypos[z] = c; 1115 } 1116 } else { 1117 z = p + i - digits; 1118 if (!hypos[z] || hypos[z] < c) { 1119 hypos[z] = c; 1120 } 1121 } 1122 digits++; 1123 } 1124 } 1125 } 1126 } 1127 inserted = 0; 1128 for (i = lo.leftmin; i <= (word.length - lo.rightmin); i++) { 1129 if (!!(hypos[i] & 1)) { 1130 s.splice(i + inserted + 1, 0, hyphen); 1131 inserted++; 1132 } 1133 } 1134 hyphenatedword = s.slice(1, -1).join(''); 1135 if (enableCache) { 1136 lo.cache[word] = hyphenatedword; 1137 } 1138 return hyphenatedword; 1139 }, 1140 1141 /** 1142 * @name Hyphenator-hyphenateURL 1143 * @methodOf Hyphenator 1144 * @description 1145 * Puts {@link Hyphenator-urlhyphen} after each no-alphanumeric char that my be in a URL. 1146 * @param string URL to hyphenate 1147 * @returns string the hyphenated URL 1148 * @public 1149 */ 1150 hyphenateURL = function (url) { 1151 return url.replace(/([:\/\.\?#&_,;!@]+)/gi, '$&' + urlhyphen); 1152 }, 1153 1154 /** 1155 * @name Hyphenator-hyphenateElement 1156 * @methodOf Hyphenator 1157 * @description 1158 * Takes the content of the given element and - if there's text - replaces the words 1159 * by hyphenated words. If there's another element, the function is called recursively. 1160 * When all words are hyphenated, the visibility of the element is set to 'visible'. 1161 * @param object The element to hyphenate 1162 * @param string The language used in this element 1163 * @public 1164 */ 1165 hyphenateElement = function (el) { 1166 var hyphenatorSettings = Expando.getDataForElem(el), 1167 lang = hyphenatorSettings.language, hyphenate, n, i; 1168 if (Hyphenator.languages.hasOwnProperty(lang)) { 1169 hyphenate = function (word) { 1170 if (urlOrMailRE.test(word)) { 1171 return hyphenateURL(word); 1172 } else { 1173 return hyphenateWord(lang, word); 1174 } 1175 }; 1176 i = 0; 1177 while (!!(n = el.childNodes[i++])) { 1178 if (n.nodeType === 3 && n.data.length >= min) { //type 3 = #text -> hyphenate! 1179 n.data = n.data.replace(Hyphenator.languages[lang].genRegExp, hyphenate); 1180 } 1181 } 1182 } 1183 if (hyphenatorSettings.isHidden && intermediateState === 'hidden') { 1184 el.style.visibility = 'visible'; 1185 if (!hyphenatorSettings.hasOwnStyle) { 1186 el.setAttribute('style', ''); // without this, removeAttribute doesn't work in Safari (thanks to molily) 1187 el.removeAttribute('style'); 1188 } else { 1189 if (el.style.removeProperty) { 1190 el.style.removeProperty('visibility'); 1191 } else if (el.style.removeAttribute) { // IE 1192 el.style.removeAttribute('visibility'); 1193 } 1194 } 1195 } 1196 if (hyphenatorSettings.isLast) { 1197 state = 3; 1198 onHyphenationDone(); 1199 } 1200 }, 1201 1202 /** 1203 * @name Hyphenator-removeHyphenationFromElement 1204 * @methodOf Hyphenator 1205 * @description 1206 * Removes all hyphens from the element. If there are other elements, the function is 1207 * called recursively. 1208 * Removing hyphens is usefull if you like to copy text. Some browsers are buggy when the copy hyphenated texts. 1209 * @param object The element where to remove hyphenation. 1210 * @public 1211 */ 1212 removeHyphenationFromElement = function (el) { 1213 var h, i = 0, n; 1214 switch (hyphen) { 1215 case '|': 1216 h = '\\|'; 1217 break; 1218 case '+': 1219 h = '\\+'; 1220 break; 1221 case '*': 1222 h = '\\*'; 1223 break; 1224 default: 1225 h = hyphen; 1226 } 1227 while (!!(n = el.childNodes[i++])) { 1228 if (n.nodeType === 3) { 1229 n.data = n.data.replace(new RegExp(h, 'g'), ''); 1230 n.data = n.data.replace(new RegExp(zeroWidthSpace, 'g'), ''); 1231 } else if (n.nodeType === 1) { 1232 removeHyphenationFromElement(n); 1233 } 1234 } 1235 }, 1236 1237 /** 1238 * @name Hyphenator-hyphenateDocument 1239 * @methodOf Hyphenator 1240 * @description 1241 * Calls hyphenateElement() for all members of elements. This is done with a setTimout 1242 * to prevent a "long running Script"-alert when hyphenating large pages. 1243 * Therefore a tricky bind()-function was necessary. 1244 * @public 1245 */ 1246 hyphenateDocument = function () { 1247 function bind(fun, arg) { 1248 return function () { 1249 return fun(arg); 1250 }; 1251 } 1252 var i = 0, el; 1253 while (!!(el = elements[i++])) { 1254 window.setTimeout(bind(hyphenateElement, el), 0); 1255 1256 } 1257 }, 1258 1259 /** 1260 * @name Hyphenator-removeHyphenationFromDocument 1261 * @methodOf Hyphenator 1262 * @description 1263 * Does what it says ;-) 1264 * @public 1265 */ 1266 removeHyphenationFromDocument = function () { 1267 var i = 0, el; 1268 while (!!(el = elements[i++])) { 1269 removeHyphenationFromElement(el); 1270 } 1271 state = 4; 1272 }; 1273 1274 return { 1275 1276 /** 1277 * @name Hyphenator.version 1278 * @memberOf Hyphenator 1279 * @description 1280 * String containing the actual version of Hyphenator.js 1281 * [major release].[minor releas].[bugfix release] 1282 * major release: new API, new Features, big changes 1283 * minor release: new languages, improvements 1284 * @public 1285 */ 1286 version: '2.5.0', 1287 1288 /** 1289 * @name Hyphenator.languages 1290 * @memberOf Hyphenator 1291 * @description 1292 * Objects that holds key-value pairs, where key is the language and the value is the 1293 * language-object loaded from (and set by) the pattern file. 1294 * The language object holds the following members: 1295 * <table> 1296 * <tr><th>key</th><th>desc></th></tr> 1297 * <tr><td>leftmin</td><td>The minimum of chars to remain on the old line</td></tr> 1298 * <tr><td>rightmin</td><td>The minimum of chars to go on the new line</td></tr> 1299 * <tr><td>shortestPattern</td><td>The shortes pattern (numbers don't count!)</td></tr> 1300 * <tr><td>longestPattern</td><td>The longest pattern (numbers don't count!)</td></tr> 1301 * <tr><td>specialChars</td><td>Non-ASCII chars in the alphabet.</td></tr> 1302 * <tr><td>patterns</td><td>the patterns</td></tr> 1303 * </table> 1304 * And optionally (or after prepareLanguagesObj() has been called): 1305 * <table> 1306 * <tr><td>exceptions</td><td>Excpetions for the secified language</td></tr> 1307 * </table> 1308 * @public 1309 */ 1310 languages: {}, 1311 1312 1313 /** 1314 * @name Hyphenator.config 1315 * @methodOf Hyphenator 1316 * @description 1317 * Config function that takes an object as an argument. The object contains key-value-pairs 1318 * containig Hyphenator-settings. This is a shortcut for calling Hyphenator.set...-Methods. 1319 * @param object <table> 1320 * <tr><th>key</th><th>values</th><th>default</th></tr> 1321 * <tr><td>classname</td><td>string</td><td>'hyphenate'</td></tr> 1322 * <tr><td>minwordlength</td><td>integer</td><td>6</td></tr> 1323 * <tr><td>hyphenchar</td><td>string</td><td>'&shy;'</td></tr> 1324 * <tr><td>urlhyphenchar</td><td>string</td><td>'zero with space'</td></tr> 1325 * <tr><td>togglebox</td><td>function</td><td>see code</td></tr> 1326 * <tr><td>displaytogglebox</td><td>boolean</td><td>false</td></tr> 1327 * <tr><td>remoteloading</td><td>boolean</td><td>true</td></tr> 1328 * <tr><td>onhyphenationdonecallback</td><td>function</td><td>empty function</td></tr> 1329 * <tr><td>onerrorhandler</td><td>function</td><td>alert(onError)</td></tr> 1330 * <tr><td>intermediatestate</td><td>string</td><td>'hidden'</td></tr> 1331 * </table> 1332 * @public 1333 * @example <script src = "Hyphenator.js" type = "text/javascript"></script> 1334 * <script type = "text/javascript"> 1335 * Hyphenator.config({'minwordlength':4,'hyphenchar':'|'}); 1336 * Hyphenator.run(); 1337 * </script> 1338 */ 1339 config: function (obj) { 1340 var assert = function (name, type) { 1341 if (typeof obj[name] === type) { 1342 return true; 1343 } else { 1344 onError(new Error('Config onError: ' + name + ' must be of type ' + type)); 1345 return false; 1346 } 1347 }, 1348 key; 1349 for (key in obj) { 1350 if (obj.hasOwnProperty(key)) { 1351 switch (key) { 1352 case 'classname': 1353 if (assert('classname', 'string')) { 1354 hyphenateClass = obj.classname; 1355 } 1356 break; 1357 case 'donthyphenateclassname': 1358 if (assert('donthyphenateclassname', 'string')) { 1359 dontHyphenateClass = obj.donthyphenateclassname; 1360 } 1361 break; 1362 case 'minwordlength': 1363 if (assert('minwordlength', 'number')) { 1364 min = obj.minwordlength; 1365 } 1366 break; 1367 case 'hyphenchar': 1368 if (assert('hyphenchar', 'string')) { 1369 if (obj.hyphenchar === '­') { 1370 obj.hyphenchar = String.fromCharCode(173); 1371 } 1372 hyphen = obj.hyphenchar; 1373 } 1374 break; 1375 case 'urlhyphenchar': 1376 if (obj.hasOwnProperty('urlhyphenchar')) { 1377 if (assert('urlhyphenchar', 'string')) { 1378 urlhyphen = obj.urlhyphenchar; 1379 } 1380 } 1381 break; 1382 case 'togglebox': 1383 if (assert('togglebox', 'function')) { 1384 toggleBox = obj.togglebox; 1385 } 1386 break; 1387 case 'displaytogglebox': 1388 if (assert('displaytogglebox', 'boolean')) { 1389 displayToggleBox = obj.displaytogglebox; 1390 } 1391 break; 1392 case 'remoteloading': 1393 if (assert('remoteloading', 'boolean')) { 1394 enableRemoteLoading = obj.remoteloading; 1395 } 1396 break; 1397 case 'enablecache': 1398 if (assert('enablecache', 'boolean')) { 1399 enableCache = obj.enablecache; 1400 } 1401 break; 1402 case 'enablereducedpatternset': 1403 if (assert('enablereducedpatternset', 'boolean')) { 1404 enableReducedPatternSet = obj.enablereducedpatternset; 1405 } 1406 break; 1407 case 'onhyphenationdonecallback': 1408 if (assert('onhyphenationdonecallback', 'function')) { 1409 onHyphenationDone = obj.onhyphenationdonecallback; 1410 } 1411 break; 1412 case 'onerrorhandler': 1413 if (assert('onerrorhandler', 'function')) { 1414 onError = obj.onerrorhandler; 1415 } 1416 break; 1417 case 'intermediatestate': 1418 if (assert('intermediatestate', 'string')) { 1419 intermediateState = obj.intermediatestate; 1420 } 1421 break; 1422 case 'selectorfunction': 1423 if (assert('selectorfunction', 'function')) { 1424 selectorFunction = obj.selectorfunction; 1425 } 1426 break; 1427 default: 1428 onError(new Error('Hyphenator.config: property ' + key + ' not known.')); 1429 } 1430 } 1431 } 1432 }, 1433 1434 /** 1435 * @name Hyphenator.run 1436 * @methodOf Hyphenator 1437 * @description 1438 * Bootstrap function that starts all hyphenation processes when called. 1439 * @public 1440 * @example <script src = "Hyphenator.js" type = "text/javascript"></script> 1441 * <script type = "text/javascript"> 1442 * Hyphenator.run(); 1443 * </script> 1444 */ 1445 run: function () { 1446 var process = function () { 1447 try { 1448 autoSetMainLanguage(); 1449 gatherDocumentInfos(); 1450 prepare(hyphenateDocument); 1451 if (displayToggleBox) { 1452 toggleBox(true); 1453 } 1454 } catch (e) { 1455 onError(e); 1456 } 1457 }; 1458 if (!documentLoaded) { 1459 runOnContentLoaded(window, process); 1460 } 1461 if (Hyphenator.isBookmarklet() || documentLoaded) { 1462 process(); 1463 } 1464 }, 1465 1466 /** 1467 * @name Hyphenator.addExceptions 1468 * @methodOf Hyphenator 1469 * @description 1470 * Adds the exceptions from the string to the appropriate language in the 1471 * {@link Hyphenator-languages}-object 1472 * @param string The language 1473 * @param string A comma separated string of hyphenated words WITH spaces. 1474 * @public 1475 * @example <script src = "Hyphenator.js" type = "text/javascript"></script> 1476 * <script type = "text/javascript"> 1477 * Hyphenator.addExceptions('de','ziem-lich, Wach-stube'); 1478 * Hyphenator.run(); 1479 * </script> 1480 */ 1481 addExceptions: function (lang, words) { 1482 if (lang === '') { 1483 lang = 'global'; 1484 } 1485 if (exceptions.hasOwnProperty[lang]) { 1486 exceptions[lang] += ", " + words; 1487 } else { 1488 exceptions[lang] = words; 1489 } 1490 }, 1491 1492 /** 1493 * @name Hyphenator.hyphenate 1494 * @methodOf Hyphenator 1495 * @public 1496 * @description 1497 * Hyphenates the target. The language patterns must be loaded. 1498 * If the target is a string, the hyphenated string is returned, 1499 * if it's an object, the values are hyphenated directly. 1500 * @param mixed the target to be hyphenated 1501 * @param string the language of the target 1502 * @returns string 1503 * @example <script src = "Hyphenator.js" type = "text/javascript"></script> 1504 * <script src = "patterns/en.js" type = "text/javascript"></script> 1505 * <script type = "text/javascript"> 1506 * var t = Hyphenator.hyphenate('Hyphenation', 'en'); //Hy|phen|ation 1507 * </script> 1508 */ 1509 hyphenate: function (target, lang) { 1510 var hyphenate, n, i; 1511 if (Hyphenator.languages.hasOwnProperty(lang)) { 1512 if (!Hyphenator.languages[lang].prepared) { 1513 prepareLanguagesObj(lang); 1514 } 1515 hyphenate = function (word) { 1516 if (urlOrMailRE.test(word)) { 1517 return hyphenateURL(word); 1518 } else { 1519 return hyphenateWord(lang, word); 1520 } 1521 }; 1522 if (typeof target === 'string' || target.constructor === String) { 1523 return target.replace(Hyphenator.languages[lang].genRegExp, hyphenate); 1524 } else if (typeof target === 'object') { 1525 i = 0; 1526 while (!!(n = target.childNodes[i++])) { 1527 if (n.nodeType === 3 && n.data.length >= min) { //type 3 = #text -> hyphenate! 1528 n.data = n.data.replace(Hyphenator.languages[lang].genRegExp, hyphenate); 1529 } else if (n.nodeType === 1) { 1530 if (n.lang !== '') { 1531 lang = n.lang; 1532 } 1533 Hyphenator.hyphenate(n, lang); 1534 } 1535 } 1536 } 1537 } else { 1538 onError(new Error('Language "' + lang + '" is not loaded.')); 1539 } 1540 }, 1541 1542 /** 1543 * @name Hyphenator.getRedPatternSet 1544 * @methodOf Hyphenator 1545 * @description 1546 * Returns {@link Hyphenator-isBookmarklet}. 1547 * @param string the language patterns are stored for 1548 * @returns object {'patk': pat} 1549 * @public 1550 */ 1551 getRedPatternSet: function (lang) { 1552 return Hyphenator.languages[lang].redPatSet; 1553 }, 1554 1555 /** 1556 * @name Hyphenator.isBookmarklet 1557 * @methodOf Hyphenator 1558 * @description 1559 * Returns {@link Hyphenator-isBookmarklet}. 1560 * @returns boolean 1561 * @public 1562 */ 1563 isBookmarklet: function () { 1564 return isBookmarklet; 1565 }, 1566 1567 1568 /** 1569 * @name Hyphenator.toggleHyphenation 1570 * @methodOf Hyphenator 1571 * @description 1572 * Checks the current state of the ToggleBox and removes or does hyphenation. 1573 * @public 1574 */ 1575 toggleHyphenation: function () { 1576 switch (state) { 1577 case 3: 1578 removeHyphenationFromDocument(); 1579 toggleBox(false); 1580 break; 1581 case 4: 1582 hyphenateDocument(); 1583 toggleBox(true); 1584 break; 1585 } 1586 } 1587 }; 1588}()); 1589if (Hyphenator.isBookmarklet()) { 1590 Hyphenator.config({displaytogglebox: true, intermediatestate: 'visible'}); 1591 Hyphenator.run(); 1592}