mirror of
				https://github.com/kovidgoyal/calibre.git
				synced 2025-11-03 19:17:02 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			2144 lines
		
	
	
		
			65 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			2144 lines
		
	
	
		
			65 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/** @license Hyphenator X.Y.Z - client side hyphenation for webbrowsers
 | 
						||
 *  Copyright (C) 2010  Mathias Nater, Zürich (mathias at mnn dot ch)
 | 
						||
 *  Project and Source hosted on http://code.google.com/p/hyphenator/
 | 
						||
 * 
 | 
						||
 *  This JavaScript code is free software: you can redistribute
 | 
						||
 *  it and/or modify it under the terms of the GNU Lesser
 | 
						||
 *  General Public License (GNU LGPL) as published by the Free Software
 | 
						||
 *  Foundation, either version 3 of the License, or (at your option)
 | 
						||
 *  any later version.  The code is distributed WITHOUT ANY WARRANTY;
 | 
						||
 *  without even the implied warranty of MERCHANTABILITY or FITNESS
 | 
						||
 *  FOR A PARTICULAR PURPOSE.  See the GNU GPL for more details.
 | 
						||
 *
 | 
						||
 *  As additional permission under GNU GPL version 3 section 7, you
 | 
						||
 *  may distribute non-source (e.g., minimized or compacted) forms of
 | 
						||
 *  that code without the copy of the GNU GPL normally required by
 | 
						||
 *  section 4, provided you include this license notice and a URL
 | 
						||
 *  through which recipients can access the Corresponding Source.
 | 
						||
 */
 | 
						||
 
 | 
						||
/* 
 | 
						||
 *  Comments are jsdoctoolkit formatted. See http://code.google.com/p/jsdoc-toolkit/
 | 
						||
 */
 | 
						||
 
 | 
						||
/* The following comment is for JSLint: */
 | 
						||
/*global window, ActiveXObject, unescape */
 | 
						||
/*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 */
 | 
						||
 | 
						||
 | 
						||
/**
 | 
						||
 * @constructor
 | 
						||
 * @description Provides all functionality to do hyphenation, except the patterns that are loaded
 | 
						||
 * externally.
 | 
						||
 * @author Mathias Nater, <a href = "mailto:mathias@mnn.ch">mathias@mnn.ch</a>
 | 
						||
 * @version X.Y.Z
 | 
						||
 * @namespace Holds all methods and properties
 | 
						||
 * @example
 | 
						||
 * <script src = "Hyphenator.js" type = "text/javascript"></script>
 | 
						||
 * <script type = "text/javascript">
 | 
						||
 *   Hyphenator.run();
 | 
						||
 * </script>
 | 
						||
 */
 | 
						||
var Hyphenator = (function (window) {
 | 
						||
 | 
						||
	var
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-supportedLang
 | 
						||
	 * @description
 | 
						||
	 * A key-value object that stores supported languages.
 | 
						||
	 * The key is the bcp47 code of the language and the value
 | 
						||
	 * is the (abbreviated) filename of the pattern file.
 | 
						||
	 * @type {Object.<string, string>}
 | 
						||
	 * @private
 | 
						||
	 * @example
 | 
						||
	 * Check if language lang is supported:
 | 
						||
	 * if (supportedLang.hasOwnProperty(lang))
 | 
						||
	 */
 | 
						||
	supportedLang = {
 | 
						||
		'be': 'be.js',
 | 
						||
		'cs': 'cs.js',
 | 
						||
		'da': 'da.js',
 | 
						||
		'bn': 'bn.js',
 | 
						||
		'de': 'de.js',
 | 
						||
		'el': 'el-monoton.js',
 | 
						||
		'el-monoton': 'el-monoton.js',
 | 
						||
		'el-polyton': 'el-polyton.js',
 | 
						||
		'en': 'en-us.js',
 | 
						||
		'en-gb': 'en-gb.js',
 | 
						||
		'en-us': 'en-us.js',
 | 
						||
		'es': 'es.js',
 | 
						||
		'fi': 'fi.js',
 | 
						||
		'fr': 'fr.js',
 | 
						||
		'grc': 'grc.js',
 | 
						||
		'gu': 'gu.js',
 | 
						||
		'hi': 'hi.js',
 | 
						||
		'hu': 'hu.js',
 | 
						||
		'hy': 'hy.js',
 | 
						||
		'it': 'it.js',
 | 
						||
		'kn': 'kn.js',
 | 
						||
		'la': 'la.js',
 | 
						||
		'lt': 'lt.js',
 | 
						||
		'lv': 'lv.js',
 | 
						||
		'ml': 'ml.js',
 | 
						||
		'no': 'no-nb.js',
 | 
						||
		'no-nb': 'no-nb.js',
 | 
						||
		'nl': 'nl.js',
 | 
						||
		'or': 'or.js',
 | 
						||
		'pa': 'pa.js',
 | 
						||
		'pl': 'pl.js',
 | 
						||
		'pt': 'pt.js',
 | 
						||
		'ru': 'ru.js',
 | 
						||
		'sl': 'sl.js',
 | 
						||
		'sv': 'sv.js',
 | 
						||
		'ta': 'ta.js',
 | 
						||
		'te': 'te.js',
 | 
						||
		'tr': 'tr.js',
 | 
						||
		'uk': 'uk.js'
 | 
						||
	},
 | 
						||
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-languageHint
 | 
						||
	 * @description
 | 
						||
	 * An automatically generated string to be displayed in a prompt if the language can't be guessed.
 | 
						||
	 * The string is generated using the supportedLang-object.
 | 
						||
	 * @see Hyphenator-supportedLang
 | 
						||
	 * @type {string}
 | 
						||
	 * @private
 | 
						||
	 * @see Hyphenator-autoSetMainLanguage
 | 
						||
	 */
 | 
						||
 | 
						||
	languageHint = (function () {
 | 
						||
		var k, r = '';
 | 
						||
		for (k in supportedLang) {
 | 
						||
			if (supportedLang.hasOwnProperty(k)) {
 | 
						||
				r += k + ', ';
 | 
						||
			}
 | 
						||
		}
 | 
						||
		r = r.substring(0, r.length - 2);
 | 
						||
		return r;
 | 
						||
	}()),
 | 
						||
	
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-prompterStrings
 | 
						||
	 * @description
 | 
						||
	 * A key-value object holding the strings to be displayed if the language can't be guessed
 | 
						||
	 * If you add hyphenation patterns change this string.
 | 
						||
	 * @type {Object.<string,string>}
 | 
						||
	 * @private
 | 
						||
	 * @see Hyphenator-autoSetMainLanguage
 | 
						||
	 */	
 | 
						||
	prompterStrings = {
 | 
						||
		'be': 'Мова гэтага сайта не можа быць вызначаны аўтаматычна. Калі ласка пакажыце мову:',
 | 
						||
		'cs': 'Jazyk této internetové stránky nebyl automaticky rozpoznán. Určete prosím její jazyk:',
 | 
						||
		'da': 'Denne websides sprog kunne ikke bestemmes. Angiv venligst sprog:',
 | 
						||
		'de': 'Die Sprache dieser Webseite konnte nicht automatisch bestimmt werden. Bitte Sprache angeben:',
 | 
						||
		'en': 'The language of this website could not be determined automatically. Please indicate the main language:',
 | 
						||
		'es': 'El idioma del sitio no pudo determinarse autom%E1ticamente. Por favor, indique el idioma principal:',
 | 
						||
		'fi': 'Sivun kielt%E4 ei tunnistettu automaattisesti. M%E4%E4rit%E4 sivun p%E4%E4kieli:',
 | 
						||
		'fr': 'La langue de ce site n%u2019a pas pu %EAtre d%E9termin%E9e automatiquement. Veuillez indiquer une langue, s.v.p.%A0:',
 | 
						||
		'hu': 'A weboldal nyelvét nem sikerült automatikusan megállapítani. Kérem adja meg a nyelvet:',
 | 
						||
		'hy': 'Չհաջողվեց հայտնաբերել այս կայքի լեզուն։ Խնդրում ենք նշեք հիմնական լեզուն՝',
 | 
						||
		'it': 'Lingua del sito sconosciuta. Indicare una lingua, per favore:',
 | 
						||
		'kn': 'ಜಾಲ ತಾಣದ ಭಾಷೆಯನ್ನು ನಿರ್ಧರಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ. ದಯವಿಟ್ಟು ಮುಖ್ಯ ಭಾಷೆಯನ್ನು ಸೂಚಿಸಿ:',
 | 
						||
		'lt': 'Nepavyko automatiškai nustatyti šios svetainės kalbos. Prašome įvesti kalbą:',
 | 
						||
		'lv': 'Šīs lapas valodu nevarēja noteikt automātiski. Lūdzu norādiet pamata valodu:',
 | 
						||
		'ml': 'ഈ വെ%u0D2C%u0D4D%u200Cസൈറ്റിന്റെ ഭാഷ കണ്ടുപിടിയ്ക്കാ%u0D28%u0D4D%u200D കഴിഞ്ഞില്ല. ഭാഷ ഏതാണെന്നു തിരഞ്ഞെടുക്കുക:',
 | 
						||
		'nl': 'De taal van deze website kan niet automatisch worden bepaald. Geef de hoofdtaal op:',
 | 
						||
		'no': 'Nettstedets språk kunne ikke finnes automatisk. Vennligst oppgi språk:',
 | 
						||
		'pt': 'A língua deste site não pôde ser determinada automaticamente. Por favor indique a língua principal:',
 | 
						||
		'ru': 'Язык этого сайта не может быть определен автоматически. Пожалуйста укажите язык:',
 | 
						||
		'sl': 'Jezika te spletne strani ni bilo mogoče samodejno določiti. Prosim navedite jezik:',
 | 
						||
		'sv': 'Spr%E5ket p%E5 den h%E4r webbplatsen kunde inte avg%F6ras automatiskt. V%E4nligen ange:',
 | 
						||
		'tr': 'Bu web sitesinin dili otomatik olarak tespit edilememiştir. Lütfen dökümanın dilini seçiniz%A0:',
 | 
						||
		'uk': 'Мова цього веб-сайту не може бути визначена автоматично. Будь ласка, вкажіть головну мову:'
 | 
						||
	},
 | 
						||
	
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-basePath
 | 
						||
	 * @description
 | 
						||
	 * A string storing the basepath from where Hyphenator.js was loaded.
 | 
						||
	 * This is used to load the patternfiles.
 | 
						||
	 * The basepath is determined dynamically by searching all script-tags for Hyphenator.js
 | 
						||
	 * If the path cannot be determined http://hyphenator.googlecode.com/svn/trunk/ is used as fallback.
 | 
						||
	 * @type {string}
 | 
						||
	 * @private
 | 
						||
	 * @see Hyphenator-loadPatterns
 | 
						||
	 */
 | 
						||
	basePath = (function () {
 | 
						||
		var s = document.getElementsByTagName('script'), i = 0, p, src, t;
 | 
						||
		while (!!(t = s[i++])) {
 | 
						||
			if (!t.src) {
 | 
						||
				continue;
 | 
						||
			}
 | 
						||
			src = t.src;
 | 
						||
			p = src.indexOf('Hyphenator.js');
 | 
						||
			if (p !== -1) {
 | 
						||
				return src.substring(0, p);
 | 
						||
			}
 | 
						||
		}
 | 
						||
		return 'http://hyphenator.googlecode.com/svn/trunk/';
 | 
						||
	}()),
 | 
						||
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-isLocal
 | 
						||
	 * @description
 | 
						||
	 * isLocal is true, if Hyphenator is loaded from the same domain, as the webpage, but false, if
 | 
						||
	 * it's loaded from an external source (i.e. directly from google.code)
 | 
						||
	 */
 | 
						||
	isLocal = (function () {
 | 
						||
		var re = false;
 | 
						||
		if (window.location.href.indexOf(basePath) !== -1) {
 | 
						||
			re = true;
 | 
						||
		}
 | 
						||
		return re;
 | 
						||
	}()),
 | 
						||
	
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-documentLoaded
 | 
						||
	 * @description
 | 
						||
	 * documentLoaded is true, when the DOM has been loaded. This is set by runOnContentLoaded
 | 
						||
	 */
 | 
						||
	documentLoaded = false,
 | 
						||
	documentCount = 0,
 | 
						||
	
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-persistentConfig
 | 
						||
	 * @description
 | 
						||
	 * if persistentConfig is set to true (defaults to false), config options and the state of the 
 | 
						||
	 * toggleBox are stored in DOM-storage (according to the storage-setting). So they haven't to be
 | 
						||
	 * set for each page.
 | 
						||
	 */	
 | 
						||
	persistentConfig = false,	
 | 
						||
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-contextWindow
 | 
						||
	 * @description
 | 
						||
	 * contextWindow stores the window for the document to be hyphenated.
 | 
						||
	 * If there are frames this will change.
 | 
						||
	 * So use contextWindow instead of window!
 | 
						||
	 */
 | 
						||
	contextWindow = window,
 | 
						||
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-doFrames
 | 
						||
	 * @description
 | 
						||
	 * switch to control if frames/iframes should be hyphenated, too
 | 
						||
	 * defaults to false (frames are a bag of hurt!)
 | 
						||
	 */
 | 
						||
	doFrames = false,
 | 
						||
	
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-dontHyphenate
 | 
						||
	 * @description
 | 
						||
	 * A key-value object containing all html-tags whose content should not be hyphenated
 | 
						||
	 * @type {Object.<string,boolean>}
 | 
						||
	 * @private
 | 
						||
	 * @see Hyphenator-hyphenateElement
 | 
						||
	 */
 | 
						||
	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},
 | 
						||
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-enableCache
 | 
						||
	 * @description
 | 
						||
	 * A variable to set if caching is enabled or not
 | 
						||
	 * @type boolean
 | 
						||
	 * @default true
 | 
						||
	 * @private
 | 
						||
	 * @see Hyphenator.config
 | 
						||
	 * @see hyphenateWord
 | 
						||
	 */
 | 
						||
	enableCache = true,
 | 
						||
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-storageType
 | 
						||
	 * @description
 | 
						||
	 * A variable to define what html5-DOM-Storage-Method is used ('none', 'local' or 'session')
 | 
						||
	 * @type {string}
 | 
						||
	 * @default 'none'
 | 
						||
	 * @private
 | 
						||
	 * @see Hyphenator.config
 | 
						||
	 */	
 | 
						||
	storageType = 'local',
 | 
						||
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-storage
 | 
						||
	 * @description
 | 
						||
	 * An alias to the storage-Method defined in storageType.
 | 
						||
	 * Set by Hyphenator.run()
 | 
						||
	 * @type {Object|undefined}
 | 
						||
	 * @default null
 | 
						||
	 * @private
 | 
						||
	 * @see Hyphenator.run
 | 
						||
	 */	
 | 
						||
	storage,
 | 
						||
	
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-enableReducedPatternSet
 | 
						||
	 * @description
 | 
						||
	 * A variable to set if storing the used patterns is set
 | 
						||
	 * @type boolean
 | 
						||
	 * @default false
 | 
						||
	 * @private
 | 
						||
	 * @see Hyphenator.config
 | 
						||
	 * @see hyphenateWord
 | 
						||
	 * @see Hyphenator.getRedPatternSet
 | 
						||
	 */	
 | 
						||
	enableReducedPatternSet = false,
 | 
						||
	
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-enableRemoteLoading
 | 
						||
	 * @description
 | 
						||
	 * A variable to set if pattern files should be loaded remotely or not
 | 
						||
	 * @type boolean
 | 
						||
	 * @default true
 | 
						||
	 * @private
 | 
						||
	 * @see Hyphenator.config
 | 
						||
	 * @see Hyphenator-loadPatterns
 | 
						||
	 */
 | 
						||
	enableRemoteLoading = true,
 | 
						||
	
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-displayToggleBox
 | 
						||
	 * @description
 | 
						||
	 * A variable to set if the togglebox should be displayed or not
 | 
						||
	 * @type boolean
 | 
						||
	 * @default false
 | 
						||
	 * @private
 | 
						||
	 * @see Hyphenator.config
 | 
						||
	 * @see Hyphenator-toggleBox
 | 
						||
	 */
 | 
						||
	displayToggleBox = false,
 | 
						||
	
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-hyphenateClass
 | 
						||
	 * @description
 | 
						||
	 * A string containing the css-class-name for the hyphenate class
 | 
						||
	 * @type {string}
 | 
						||
	 * @default 'hyphenate'
 | 
						||
	 * @private
 | 
						||
	 * @example
 | 
						||
	 * <p class = "hyphenate">Text</p>
 | 
						||
	 * @see Hyphenator.config
 | 
						||
	 */
 | 
						||
	hyphenateClass = 'hyphenate',
 | 
						||
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-dontHyphenateClass
 | 
						||
	 * @description
 | 
						||
	 * A string containing the css-class-name for elements that should not be hyphenated
 | 
						||
	 * @type {string}
 | 
						||
	 * @default 'donthyphenate'
 | 
						||
	 * @private
 | 
						||
	 * @example
 | 
						||
	 * <p class = "donthyphenate">Text</p>
 | 
						||
	 * @see Hyphenator.config
 | 
						||
	 */
 | 
						||
	dontHyphenateClass = 'donthyphenate',
 | 
						||
	
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-min
 | 
						||
	 * @description
 | 
						||
	 * A number wich indicates the minimal length of words to hyphenate.
 | 
						||
	 * @type {number}
 | 
						||
	 * @default 6
 | 
						||
	 * @private
 | 
						||
	 * @see Hyphenator.config
 | 
						||
	 */	
 | 
						||
	min = 6,
 | 
						||
	
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-orphanControl
 | 
						||
	 * @description
 | 
						||
	 * Control how the last words of a line are handled:
 | 
						||
	 * level 1 (default): last word is hyphenated
 | 
						||
	 * level 2: last word is not hyphenated
 | 
						||
	 * level 3: last word is not hyphenated and last space is non breaking
 | 
						||
	 * @type {number}
 | 
						||
	 * @default 1
 | 
						||
	 * @private
 | 
						||
	 */
 | 
						||
	orphanControl = 1,
 | 
						||
	
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-isBookmarklet
 | 
						||
	 * @description
 | 
						||
	 * Indicates if Hyphanetor runs as bookmarklet or not.
 | 
						||
	 * @type boolean
 | 
						||
	 * @default false
 | 
						||
	 * @private
 | 
						||
	 */	
 | 
						||
	isBookmarklet = (function () {
 | 
						||
		var loc = null, re = false, jsArray = document.getElementsByTagName('script'), i, l;
 | 
						||
		for (i = 0, l = jsArray.length; i < l; i++) {
 | 
						||
			if (!!jsArray[i].getAttribute('src')) {
 | 
						||
				loc = jsArray[i].getAttribute('src');
 | 
						||
			}
 | 
						||
			if (!loc) {
 | 
						||
				continue;
 | 
						||
			} else if (loc.indexOf('Hyphenator.js?bm=true') !== -1) {
 | 
						||
				re = true;
 | 
						||
			}
 | 
						||
		}
 | 
						||
		return re;
 | 
						||
	}()),
 | 
						||
	
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-mainLanguage
 | 
						||
	 * @description
 | 
						||
	 * The general language of the document. In contrast to {@link Hyphenator-defaultLanguage},
 | 
						||
	 * mainLanguage is defined by the client (i.e. by the html or by a prompt).
 | 
						||
	 * @type {string|null}
 | 
						||
	 * @private
 | 
						||
	 * @see Hyphenator-autoSetMainLanguage
 | 
						||
	 */	
 | 
						||
	mainLanguage = null,
 | 
						||
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-defaultLanguage
 | 
						||
	 * @description
 | 
						||
	 * The language defined by the developper. This language setting is defined by a config option.
 | 
						||
	 * It is overwritten by any html-lang-attribute and only taken in count, when no such attribute can
 | 
						||
	 * be found (i.e. just before the prompt).
 | 
						||
	 * @type {string|null}
 | 
						||
	 * @private
 | 
						||
	 * @see Hyphenator-autoSetMainLanguage
 | 
						||
	 */	
 | 
						||
	defaultLanguage = '',
 | 
						||
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-elements
 | 
						||
	 * @description
 | 
						||
	 * An array holding all elements that have to be hyphenated. This var is filled by
 | 
						||
	 * {@link Hyphenator-gatherDocumentInfos}
 | 
						||
	 * @type {Array}
 | 
						||
	 * @private
 | 
						||
	 */	
 | 
						||
	elements = [],
 | 
						||
	
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-exceptions
 | 
						||
	 * @description
 | 
						||
	 * An object containing exceptions as comma separated strings for each language.
 | 
						||
	 * When the language-objects are loaded, their exceptions are processed, copied here and then deleted.
 | 
						||
	 * @see Hyphenator-prepareLanguagesObj
 | 
						||
	 * @type {Object}
 | 
						||
	 * @private
 | 
						||
	 */	
 | 
						||
	exceptions = {},
 | 
						||
	
 | 
						||
	countObjProps = function (obj) {
 | 
						||
		var k, l = 0;
 | 
						||
		for (k in obj) {
 | 
						||
			if (obj.hasOwnProperty(k)) {
 | 
						||
				l++;
 | 
						||
			}
 | 
						||
		}
 | 
						||
		return l;
 | 
						||
	},
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-docLanguages
 | 
						||
	 * @description
 | 
						||
	 * An object holding all languages used in the document. This is filled by
 | 
						||
	 * {@link Hyphenator-gatherDocumentInfos}
 | 
						||
	 * @type {Object}
 | 
						||
	 * @private
 | 
						||
	 */	
 | 
						||
	docLanguages = {},
 | 
						||
 | 
						||
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-state
 | 
						||
	 * @description
 | 
						||
	 * A number that inidcates the current state of the script
 | 
						||
	 * 0: not initialized
 | 
						||
	 * 1: loading patterns
 | 
						||
	 * 2: ready
 | 
						||
	 * 3: hyphenation done
 | 
						||
	 * 4: hyphenation removed
 | 
						||
	 * @type {number}
 | 
						||
	 * @private
 | 
						||
	 */	
 | 
						||
	state = 0,
 | 
						||
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-url
 | 
						||
	 * @description
 | 
						||
	 * A string containing a RegularExpression to match URL's
 | 
						||
	 * @type {string}
 | 
						||
	 * @private
 | 
						||
	 */	
 | 
						||
	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#!:\\.?\\+=&%@!\\-]*)*',
 | 
						||
	//      protocoll     usr     pwd                    ip               or                          host                 tld        port               path
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-mail
 | 
						||
	 * @description
 | 
						||
	 * A string containing a RegularExpression to match mail-adresses
 | 
						||
	 * @type {string}
 | 
						||
	 * @private
 | 
						||
	 */	
 | 
						||
	mail = '[\\w-\\.]+@[\\w\\.]+',
 | 
						||
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-urlRE
 | 
						||
	 * @description
 | 
						||
	 * A RegularExpressions-Object for url- and mail adress matching
 | 
						||
	 * @type {RegExp}
 | 
						||
	 * @private
 | 
						||
	 */		
 | 
						||
	urlOrMailRE = new RegExp('(' + url + ')|(' + mail + ')', 'i'),
 | 
						||
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-zeroWidthSpace
 | 
						||
	 * @description
 | 
						||
	 * A string that holds a char.
 | 
						||
	 * Depending on the browser, this is the zero with space or an empty string.
 | 
						||
	 * zeroWidthSpace is used to break URLs
 | 
						||
	 * @type {string}
 | 
						||
	 * @private
 | 
						||
	 */		
 | 
						||
	zeroWidthSpace = (function () {
 | 
						||
		var zws, ua = navigator.userAgent.toLowerCase();
 | 
						||
		zws = String.fromCharCode(8203); //Unicode zero width space
 | 
						||
		if (ua.indexOf('msie 6') !== -1) {
 | 
						||
			zws = ''; //IE6 doesn't support zws
 | 
						||
		}
 | 
						||
		if (ua.indexOf('opera') !== -1 && ua.indexOf('version/10.00') !== -1) {
 | 
						||
			zws = ''; //opera 10 on XP doesn't support zws
 | 
						||
		}
 | 
						||
		return zws;
 | 
						||
	}()),
 | 
						||
	
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-createElem
 | 
						||
	 * @description
 | 
						||
	 * A function alias to document.createElementNS or document.createElement
 | 
						||
	 * @type {function(string, Object)}
 | 
						||
	 * @private
 | 
						||
	 */		
 | 
						||
	createElem = function (tagname, context) {
 | 
						||
		context = context || contextWindow;
 | 
						||
		if (document.createElementNS) {
 | 
						||
			return context.document.createElementNS('http://www.w3.org/1999/xhtml', tagname);
 | 
						||
		} else if (document.createElement) {
 | 
						||
			return context.document.createElement(tagname);
 | 
						||
		}
 | 
						||
	},
 | 
						||
	
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-onHyphenationDone
 | 
						||
	 * @description
 | 
						||
	 * A method to be called, when the last element has been hyphenated or the hyphenation has been
 | 
						||
	 * removed from the last element.
 | 
						||
	 * @see Hyphenator.config
 | 
						||
	 * @type {function()}
 | 
						||
	 * @private
 | 
						||
	 */		
 | 
						||
	onHyphenationDone = function () {},
 | 
						||
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-onError
 | 
						||
	 * @description
 | 
						||
	 * A function that can be called upon an error.
 | 
						||
	 * @see Hyphenator.config
 | 
						||
	 * @type {function(Object)}
 | 
						||
	 * @private
 | 
						||
	 */		
 | 
						||
	onError = function (e) {
 | 
						||
		window.alert("Hyphenator.js says:\n\nAn Error ocurred:\n" + e.message);
 | 
						||
	},
 | 
						||
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-selectorFunction
 | 
						||
	 * @description
 | 
						||
	 * A function that has to return a HTMLNodeList of Elements to be hyphenated.
 | 
						||
	 * By default it uses the classname ('hyphenate') to select the elements.
 | 
						||
	 * @see Hyphenator.config
 | 
						||
	 * @type {function()}
 | 
						||
	 * @private
 | 
						||
	 */		
 | 
						||
	selectorFunction = function () {
 | 
						||
		var tmp, el = [], i, l;
 | 
						||
		if (document.getElementsByClassName) {
 | 
						||
			el = contextWindow.document.getElementsByClassName(hyphenateClass);
 | 
						||
		} else {
 | 
						||
			tmp = contextWindow.document.getElementsByTagName('*');
 | 
						||
			l = tmp.length;
 | 
						||
			for (i = 0; i < l; i++)
 | 
						||
			{
 | 
						||
				if (tmp[i].className.indexOf(hyphenateClass) !== -1 && tmp[i].className.indexOf(dontHyphenateClass) === -1) {
 | 
						||
					el.push(tmp[i]);
 | 
						||
				}
 | 
						||
			}
 | 
						||
		}
 | 
						||
		return el;
 | 
						||
	},
 | 
						||
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-intermediateState
 | 
						||
	 * @description
 | 
						||
	 * The value of style.visibility of the text while it is hyphenated.
 | 
						||
	 * @see Hyphenator.config
 | 
						||
	 * @type {string}
 | 
						||
	 * @private
 | 
						||
	 */		
 | 
						||
	intermediateState = 'hidden',
 | 
						||
	
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-hyphen
 | 
						||
	 * @description
 | 
						||
	 * A string containing the character for in-word-hyphenation
 | 
						||
	 * @type {string}
 | 
						||
	 * @default the soft hyphen
 | 
						||
	 * @private
 | 
						||
	 * @see Hyphenator.config
 | 
						||
	 */
 | 
						||
	hyphen = String.fromCharCode(173),
 | 
						||
	
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-urlhyphen
 | 
						||
	 * @description
 | 
						||
	 * A string containing the character for url/mail-hyphenation
 | 
						||
	 * @type {string}
 | 
						||
	 * @default the zero width space
 | 
						||
	 * @private
 | 
						||
	 * @see Hyphenator.config
 | 
						||
	 * @see Hyphenator-zeroWidthSpace
 | 
						||
	 */
 | 
						||
	urlhyphen = zeroWidthSpace,
 | 
						||
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-safeCopy
 | 
						||
	 * @description
 | 
						||
	 * Defines wether work-around for copy issues is active or not
 | 
						||
	 * Not supported by Opera (no onCopy handler)
 | 
						||
	 * @type boolean
 | 
						||
	 * @default true
 | 
						||
	 * @private
 | 
						||
	 * @see Hyphenator.config
 | 
						||
	 * @see Hyphenator-registerOnCopy
 | 
						||
	 */
 | 
						||
	safeCopy = true,
 | 
						||
	
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-Expando
 | 
						||
	 * @description
 | 
						||
	 * This custom object stores data for elements: storing data directly in elements
 | 
						||
	 * (DomElement.customData = foobar;) isn't a good idea. It would lead to conflicts
 | 
						||
	 * in form elements, when the form has a child with name="foobar". Therefore, this
 | 
						||
	 * solution follows the approach of jQuery: the data is stored in an object and
 | 
						||
	 * referenced by a unique attribute of the element. The attribute has a name that 
 | 
						||
	 * is built by the prefix "HyphenatorExpando_" and a random number, so if the very
 | 
						||
	 * very rare case occurs, that there's already an attribute with the same name, a
 | 
						||
	 * simple reload is enough to make it function.
 | 
						||
	 * @private
 | 
						||
	 */		
 | 
						||
	Expando = (function () {
 | 
						||
		var container = {},
 | 
						||
			name = "HyphenatorExpando_" + Math.random(),
 | 
						||
			uuid = 0;
 | 
						||
		return {
 | 
						||
			getDataForElem : function (elem) {
 | 
						||
				return container[elem[name].id];
 | 
						||
			},
 | 
						||
			setDataForElem : function (elem, data) {
 | 
						||
				var id;
 | 
						||
				if (elem[name] && elem[name].id !== '') {
 | 
						||
					id = elem[name].id;
 | 
						||
				} else {
 | 
						||
					id = uuid++;
 | 
						||
					elem[name] = {'id': id}; //object needed, otherways it is reflected in HTML in IE
 | 
						||
				}
 | 
						||
				container[id] = data;
 | 
						||
			},
 | 
						||
			appendDataForElem : function (elem, data) {
 | 
						||
				var k;
 | 
						||
				for (k in data) {
 | 
						||
					if (data.hasOwnProperty(k)) {
 | 
						||
						container[elem[name].id][k] = data[k];
 | 
						||
					}
 | 
						||
				}
 | 
						||
			},
 | 
						||
			delDataOfElem : function (elem) {
 | 
						||
				delete container[elem[name]];
 | 
						||
			}
 | 
						||
		};
 | 
						||
	}()),
 | 
						||
		
 | 
						||
	/*
 | 
						||
	 * runOnContentLoaded is based od jQuery.bindReady()
 | 
						||
	 * see
 | 
						||
	 * jQuery JavaScript Library v1.3.2
 | 
						||
	 * http://jquery.com/
 | 
						||
	 *
 | 
						||
	 * Copyright (c) 2009 John Resig
 | 
						||
	 * Dual licensed under the MIT and GPL licenses.
 | 
						||
	 * http://docs.jquery.com/License
 | 
						||
	 *
 | 
						||
	 * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009)
 | 
						||
	 * Revision: 6246
 | 
						||
	 */
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-runOnContentLoaded
 | 
						||
	 * @description
 | 
						||
	 * A crossbrowser solution for the DOMContentLoaded-Event based on jQuery
 | 
						||
	 * <a href = "http://jquery.com/</a>
 | 
						||
	 * I added some functionality: e.g. support for frames and iframes…
 | 
						||
	 * @param {Object} w the window-object
 | 
						||
	 * @param {function()} f the function to call onDOMContentLoaded
 | 
						||
	 * @private
 | 
						||
	 */
 | 
						||
	runOnContentLoaded = function (w, f) {
 | 
						||
		var DOMContentLoaded = function () {}, toplevel, hyphRunForThis = {};
 | 
						||
		if (documentLoaded && !hyphRunForThis[w.location.href]) {
 | 
						||
			f();
 | 
						||
			hyphRunForThis[w.location.href] = true;
 | 
						||
			return;
 | 
						||
		}
 | 
						||
		function init(context) {
 | 
						||
			contextWindow = context || window;
 | 
						||
			if (!hyphRunForThis[contextWindow.location.href] && (!documentLoaded || contextWindow != window.parent)) {
 | 
						||
				documentLoaded = true;
 | 
						||
				f();
 | 
						||
				hyphRunForThis[contextWindow.location.href] = true;
 | 
						||
			}
 | 
						||
		}
 | 
						||
		
 | 
						||
		function doScrollCheck() {
 | 
						||
			try {
 | 
						||
				// If IE is used, use the trick by Diego Perini
 | 
						||
				// http://javascript.nwbox.com/IEContentLoaded/
 | 
						||
				document.documentElement.doScroll("left");
 | 
						||
			} catch (error) {
 | 
						||
				setTimeout(doScrollCheck, 1);
 | 
						||
				return;
 | 
						||
			}
 | 
						||
		
 | 
						||
			// and execute any waiting functions
 | 
						||
			init(window);
 | 
						||
		}
 | 
						||
 | 
						||
		function doOnLoad() {
 | 
						||
			var i, haveAccess, fl = window.frames.length;
 | 
						||
			if (doFrames && fl > 0) {
 | 
						||
				for (i = 0; i < fl; i++) {
 | 
						||
					haveAccess = undefined;
 | 
						||
					//try catch isn't enough for webkit
 | 
						||
					try {
 | 
						||
						//opera throws only on document.toString-access
 | 
						||
						haveAccess = window.frames[i].document.toString();
 | 
						||
					} catch (e) {
 | 
						||
						haveAccess = undefined;
 | 
						||
					}
 | 
						||
					if (!!haveAccess) {
 | 
						||
						init(window.frames[i]);
 | 
						||
					}
 | 
						||
				}
 | 
						||
				contextWindow = window;
 | 
						||
				f();
 | 
						||
				hyphRunForThis[window.location.href] = true;
 | 
						||
			} else {
 | 
						||
				init(window);
 | 
						||
			}
 | 
						||
		}
 | 
						||
		
 | 
						||
		// Cleanup functions for the document ready method
 | 
						||
		if (document.addEventListener) {
 | 
						||
			DOMContentLoaded = function () {
 | 
						||
				document.removeEventListener("DOMContentLoaded", DOMContentLoaded, false);
 | 
						||
				if (doFrames && window.frames.length > 0) {
 | 
						||
					//we are in a frameset, so do nothing but wait for onload to fire
 | 
						||
					return;
 | 
						||
				} else {
 | 
						||
					init(window);
 | 
						||
				}
 | 
						||
			};
 | 
						||
		
 | 
						||
		} else if (document.attachEvent) {
 | 
						||
			DOMContentLoaded = function () {
 | 
						||
				// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
 | 
						||
				if (document.readyState === "complete") {
 | 
						||
					document.detachEvent("onreadystatechange", DOMContentLoaded);
 | 
						||
					if (doFrames && window.frames.length > 0) {
 | 
						||
						//we are in a frameset, so do nothing but wait for onload to fire
 | 
						||
						return;
 | 
						||
					} else {
 | 
						||
						init(window);
 | 
						||
					}
 | 
						||
				}
 | 
						||
			};
 | 
						||
		}
 | 
						||
 | 
						||
		// Mozilla, Opera and webkit nightlies currently support this event
 | 
						||
		if (document.addEventListener) {
 | 
						||
			// Use the handy event callback
 | 
						||
			document.addEventListener("DOMContentLoaded", DOMContentLoaded, false);
 | 
						||
			
 | 
						||
			// A fallback to window.onload, that will always work
 | 
						||
			window.addEventListener("load", doOnLoad, false);
 | 
						||
 | 
						||
		// If IE event model is used
 | 
						||
		} else if (document.attachEvent) {
 | 
						||
			// ensure firing before onload,
 | 
						||
			// maybe late but safe also for iframes
 | 
						||
			document.attachEvent("onreadystatechange", DOMContentLoaded);
 | 
						||
			
 | 
						||
			// A fallback to window.onload, that will always work
 | 
						||
			window.attachEvent("onload", doOnLoad);
 | 
						||
 | 
						||
			// If IE and not a frame
 | 
						||
			// continually check to see if the document is ready
 | 
						||
			toplevel = false;
 | 
						||
			try {
 | 
						||
				toplevel = window.frameElement === null;
 | 
						||
			} catch (e) {}
 | 
						||
 | 
						||
			if (document.documentElement.doScroll && toplevel) {
 | 
						||
				doScrollCheck();
 | 
						||
			}
 | 
						||
		}
 | 
						||
 | 
						||
	},
 | 
						||
 | 
						||
 | 
						||
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-getLang
 | 
						||
	 * @description
 | 
						||
	 * Gets the language of an element. If no language is set, it may use the {@link Hyphenator-mainLanguage}.
 | 
						||
	 * @param {Object} el The first parameter is an DOM-Element-Object
 | 
						||
	 * @param {boolean} fallback The second parameter is a boolean to tell if the function should return the {@link Hyphenator-mainLanguage}
 | 
						||
	 * if there's no language found for the element.
 | 
						||
	 * @private
 | 
						||
	 */
 | 
						||
	getLang = function (el, fallback) {
 | 
						||
		if (!!el.getAttribute('lang')) {
 | 
						||
			return el.getAttribute('lang').toLowerCase();
 | 
						||
		}
 | 
						||
		// The following doesn't work in IE due to a bug when getAttribute('xml:lang') in a table
 | 
						||
		/*if (!!el.getAttribute('xml:lang')) {
 | 
						||
			return el.getAttribute('xml:lang').substring(0, 2);
 | 
						||
		}*/
 | 
						||
		//instead, we have to do this (thanks to borgzor):
 | 
						||
		try {
 | 
						||
			if (!!el.getAttribute('xml:lang')) {
 | 
						||
				return el.getAttribute('xml:lang').toLowerCase();
 | 
						||
			}
 | 
						||
		} catch (ex) {}
 | 
						||
		if (el.tagName !== 'HTML') {
 | 
						||
			return getLang(el.parentNode, true);
 | 
						||
		}
 | 
						||
		if (fallback) {
 | 
						||
			return mainLanguage;
 | 
						||
		}
 | 
						||
		return null;
 | 
						||
	},
 | 
						||
	
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-autoSetMainLanguage
 | 
						||
	 * @description
 | 
						||
	 * Retrieves the language of the document from the DOM.
 | 
						||
	 * The function looks in the following places:
 | 
						||
	 * <ul>
 | 
						||
	 * <li>lang-attribute in the html-tag</li>
 | 
						||
	 * <li><meta http-equiv = "content-language" content = "xy" /></li>
 | 
						||
	 * <li><meta name = "DC.Language" content = "xy" /></li>
 | 
						||
	 * <li><meta name = "language" content = "xy" /></li>
 | 
						||
	 * </li>
 | 
						||
	 * If nothing can be found a prompt using {@link Hyphenator-languageHint} and {@link Hyphenator-prompterStrings} is displayed.
 | 
						||
	 * If the retrieved language is in the object {@link Hyphenator-supportedLang} it is copied to {@link Hyphenator-mainLanguage}
 | 
						||
	 * @private
 | 
						||
	 */		
 | 
						||
	autoSetMainLanguage = function (w) {
 | 
						||
		w = w || contextWindow;
 | 
						||
		var el = w.document.getElementsByTagName('html')[0],
 | 
						||
			m = w.document.getElementsByTagName('meta'),
 | 
						||
			i, text, e, ul;
 | 
						||
		mainLanguage = getLang(el, false);
 | 
						||
		if (!mainLanguage) {
 | 
						||
			for (i = 0; i < m.length; i++) {
 | 
						||
				//<meta http-equiv = "content-language" content="xy">	
 | 
						||
				if (!!m[i].getAttribute('http-equiv') && (m[i].getAttribute('http-equiv').toLowerCase() === 'content-language')) {
 | 
						||
					mainLanguage = m[i].getAttribute('content').toLowerCase();
 | 
						||
				}
 | 
						||
				//<meta name = "DC.Language" content="xy">
 | 
						||
				if (!!m[i].getAttribute('name') && (m[i].getAttribute('name').toLowerCase() === 'dc.language')) {
 | 
						||
					mainLanguage = m[i].getAttribute('content').toLowerCase();
 | 
						||
				}			
 | 
						||
				//<meta name = "language" content = "xy">
 | 
						||
				if (!!m[i].getAttribute('name') && (m[i].getAttribute('name').toLowerCase() === 'language')) {
 | 
						||
					mainLanguage = m[i].getAttribute('content').toLowerCase();
 | 
						||
				}
 | 
						||
			}
 | 
						||
		}
 | 
						||
		//get lang for frame from enclosing document
 | 
						||
		if (!mainLanguage && doFrames && contextWindow != window.parent) {
 | 
						||
			autoSetMainLanguage(window.parent);
 | 
						||
		}
 | 
						||
		//fallback to defaultLang if set
 | 
						||
		if (!mainLanguage && defaultLanguage !== '') {
 | 
						||
			mainLanguage = defaultLanguage;
 | 
						||
		}
 | 
						||
		//ask user for lang
 | 
						||
		if (!mainLanguage) {
 | 
						||
			text = '';
 | 
						||
			ul = navigator.language ? navigator.language : navigator.userLanguage;
 | 
						||
			ul = ul.substring(0, 2);
 | 
						||
			if (prompterStrings.hasOwnProperty(ul)) {
 | 
						||
				text = prompterStrings[ul];
 | 
						||
			} else {
 | 
						||
				text = prompterStrings.en;
 | 
						||
			}
 | 
						||
			text += ' (ISO 639-1)\n\n' + languageHint;
 | 
						||
			mainLanguage = window.prompt(unescape(text), ul).toLowerCase();
 | 
						||
		}
 | 
						||
		if (!supportedLang.hasOwnProperty(mainLanguage)) {
 | 
						||
			if (supportedLang.hasOwnProperty(mainLanguage.split('-')[0])) { //try subtag
 | 
						||
				mainLanguage = mainLanguage.split('-')[0];
 | 
						||
			} else {
 | 
						||
				e = new Error('The language "' + mainLanguage + '" is not yet supported.');
 | 
						||
				throw e;
 | 
						||
			}
 | 
						||
		}
 | 
						||
	},
 | 
						||
    
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-gatherDocumentInfos
 | 
						||
	 * @description
 | 
						||
	 * This method runs through the DOM and executes the process()-function on:
 | 
						||
	 * - every node returned by the {@link Hyphenator-selectorFunction}.
 | 
						||
	 * The process()-function copies the element to the elements-variable, sets its visibility
 | 
						||
	 * to intermediateState, retrieves its language and recursivly descends the DOM-tree until
 | 
						||
	 * the child-Nodes aren't of type 1
 | 
						||
	 * @private
 | 
						||
	 */		
 | 
						||
	gatherDocumentInfos = function () {
 | 
						||
		var elToProcess, tmp, i = 0,
 | 
						||
		process = function (el, hide, lang) {
 | 
						||
			var n, i = 0, hyphenatorSettings = {};
 | 
						||
			if (hide && intermediateState === 'hidden') {
 | 
						||
				if (!!el.getAttribute('style')) {
 | 
						||
					hyphenatorSettings.hasOwnStyle = true;
 | 
						||
				} else {
 | 
						||
					hyphenatorSettings.hasOwnStyle = false;					
 | 
						||
				}
 | 
						||
				hyphenatorSettings.isHidden = true;
 | 
						||
				el.style.visibility = 'hidden';
 | 
						||
			}
 | 
						||
			if (el.lang && typeof(el.lang) === 'string') {
 | 
						||
				hyphenatorSettings.language = el.lang.toLowerCase(); //copy attribute-lang to internal lang
 | 
						||
			} else if (lang) {
 | 
						||
				hyphenatorSettings.language = lang.toLowerCase();
 | 
						||
			} else {
 | 
						||
				hyphenatorSettings.language = getLang(el, true);
 | 
						||
			}
 | 
						||
			lang = hyphenatorSettings.language;
 | 
						||
			if (supportedLang[lang]) {
 | 
						||
				docLanguages[lang] = true;
 | 
						||
			} else {
 | 
						||
				if (supportedLang.hasOwnProperty(lang.split('-')[0])) { //try subtag
 | 
						||
					lang = lang.split('-')[0];
 | 
						||
					hyphenatorSettings.language = lang;
 | 
						||
				} else if (!isBookmarklet) {
 | 
						||
					onError(new Error('Language ' + lang + ' is not yet supported.'));
 | 
						||
				}
 | 
						||
			}
 | 
						||
			Expando.setDataForElem(el, hyphenatorSettings);			
 | 
						||
			
 | 
						||
			elements.push(el);
 | 
						||
			while (!!(n = el.childNodes[i++])) {
 | 
						||
				if (n.nodeType === 1 && !dontHyphenate[n.nodeName.toLowerCase()] &&
 | 
						||
					n.className.indexOf(dontHyphenateClass) === -1 && !(n in elToProcess)) {
 | 
						||
					process(n, false, lang);
 | 
						||
				}
 | 
						||
			}
 | 
						||
		};
 | 
						||
		if (isBookmarklet) {
 | 
						||
			elToProcess = contextWindow.document.getElementsByTagName('body')[0];
 | 
						||
			process(elToProcess, false, mainLanguage);
 | 
						||
		} else {
 | 
						||
			elToProcess = selectorFunction();
 | 
						||
			while (!!(tmp = elToProcess[i++]))
 | 
						||
			{
 | 
						||
				process(tmp, true, '');
 | 
						||
			}			
 | 
						||
		}
 | 
						||
		if (!Hyphenator.languages.hasOwnProperty(mainLanguage)) {
 | 
						||
			docLanguages[mainLanguage] = true;
 | 
						||
		} else if (!Hyphenator.languages[mainLanguage].prepared) {
 | 
						||
			docLanguages[mainLanguage] = true;
 | 
						||
		}
 | 
						||
		if (elements.length > 0) {
 | 
						||
			Expando.appendDataForElem(elements[elements.length - 1], {isLast : true});
 | 
						||
		}
 | 
						||
	},
 | 
						||
		 
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-convertPatterns
 | 
						||
	 * @description
 | 
						||
	 * Converts the patterns from string '_a6' to object '_a':'_a6'.
 | 
						||
	 * The result is stored in the {@link Hyphenator-patterns}-object.
 | 
						||
	 * @private
 | 
						||
	 * @param {string} lang the language whose patterns shall be converted
 | 
						||
	 */		
 | 
						||
	convertPatterns = function (lang) {
 | 
						||
		var plen, anfang, ende, pats, pat, key, tmp = {};
 | 
						||
		pats = Hyphenator.languages[lang].patterns;
 | 
						||
		for (plen in pats) {
 | 
						||
			if (pats.hasOwnProperty(plen)) {
 | 
						||
				plen = parseInt(plen, 10);
 | 
						||
				anfang = 0;
 | 
						||
				ende = plen;
 | 
						||
				while (!!(pat = pats[plen].substring(anfang, ende))) {
 | 
						||
					key = pat.replace(/\d/g, '');
 | 
						||
					tmp[key] = pat;
 | 
						||
					anfang = ende;
 | 
						||
					ende += plen;
 | 
						||
				}
 | 
						||
			}
 | 
						||
		}
 | 
						||
		Hyphenator.languages[lang].patterns = tmp;
 | 
						||
		Hyphenator.languages[lang].patternsConverted = true;
 | 
						||
	},
 | 
						||
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-convertExceptionsToObject
 | 
						||
	 * @description
 | 
						||
	 * Converts a list of comma seprated exceptions to an object:
 | 
						||
	 * 'Fortran,Hy-phen-a-tion' -> {'Fortran':'Fortran','Hyphenation':'Hy-phen-a-tion'}
 | 
						||
	 * @private
 | 
						||
	 * @param {string} exc a comma separated string of exceptions (without spaces)
 | 
						||
	 */		
 | 
						||
	convertExceptionsToObject = function (exc) {
 | 
						||
		var w = exc.split(', '),
 | 
						||
			r = {},
 | 
						||
			i, l, key;
 | 
						||
		for (i = 0, l = w.length; i < l; i++) {
 | 
						||
			key = w[i].replace(/-/g, '');
 | 
						||
			if (!r.hasOwnProperty(key)) {
 | 
						||
				r[key] = w[i];
 | 
						||
			}
 | 
						||
		}
 | 
						||
		return r;
 | 
						||
	},
 | 
						||
	
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-loadPatterns
 | 
						||
	 * @description
 | 
						||
	 * Adds a <script>-Tag to the DOM to load an externeal .js-file containing patterns and settings for the given language.
 | 
						||
	 * If the given language is not in the {@link Hyphenator-supportedLang}-Object it returns.
 | 
						||
	 * One may ask why we are not using AJAX to load the patterns. The XMLHttpRequest-Object 
 | 
						||
	 * has a same-origin-policy. This makes the isBookmarklet-functionality impossible.
 | 
						||
	 * @param {string} lang The language to load the patterns for
 | 
						||
	 * @private
 | 
						||
	 * @see Hyphenator-basePath
 | 
						||
	 */
 | 
						||
	loadPatterns = function (lang) {
 | 
						||
		var url, xhr, head, script;
 | 
						||
		if (supportedLang[lang] && !Hyphenator.languages[lang]) {
 | 
						||
	        url = basePath + 'patterns/' + supportedLang[lang];
 | 
						||
		} else {
 | 
						||
			return;
 | 
						||
		}
 | 
						||
		if (isLocal && !isBookmarklet) {
 | 
						||
			//check if 'url' is available:
 | 
						||
			xhr = null;
 | 
						||
			if (typeof XMLHttpRequest !== 'undefined') {
 | 
						||
				xhr = new XMLHttpRequest();
 | 
						||
			}
 | 
						||
			if (!xhr) {
 | 
						||
				try {
 | 
						||
					xhr  = new ActiveXObject("Msxml2.XMLHTTP");
 | 
						||
				} catch (e) {
 | 
						||
					xhr  = null;
 | 
						||
				}
 | 
						||
			}
 | 
						||
			if (xhr) {
 | 
						||
				xhr.open('HEAD', url, false);
 | 
						||
				xhr.setRequestHeader('Cache-Control', 'no-cache');
 | 
						||
				xhr.send(null);
 | 
						||
				if (xhr.status === 404) {
 | 
						||
					onError(new Error('Could not load\n' + url));
 | 
						||
					delete docLanguages[lang];
 | 
						||
					return;
 | 
						||
				}
 | 
						||
			}
 | 
						||
		}
 | 
						||
		if (createElem) {
 | 
						||
			head = window.document.getElementsByTagName('head').item(0);
 | 
						||
			script = createElem('script', window);
 | 
						||
			script.src = url;
 | 
						||
			script.type = 'text/javascript';
 | 
						||
			head.appendChild(script);
 | 
						||
		}
 | 
						||
	},
 | 
						||
	
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-prepareLanguagesObj
 | 
						||
	 * @description
 | 
						||
	 * Adds a cache to each language and converts the exceptions-list to an object.
 | 
						||
	 * If storage is active the object is stored there.
 | 
						||
	 * @private
 | 
						||
	 * @param {string} lang the language ob the lang-obj
 | 
						||
	 */		
 | 
						||
	prepareLanguagesObj = function (lang) {
 | 
						||
		var lo = Hyphenator.languages[lang], wrd;
 | 
						||
		if (!lo.prepared) {	
 | 
						||
			if (enableCache) {
 | 
						||
				lo.cache = {};
 | 
						||
				//Export
 | 
						||
				lo['cache'] = lo.cache;
 | 
						||
			}
 | 
						||
			if (enableReducedPatternSet) {
 | 
						||
				lo.redPatSet = {};
 | 
						||
			}
 | 
						||
			//add exceptions from the pattern file to the local 'exceptions'-obj
 | 
						||
			if (lo.hasOwnProperty('exceptions')) {
 | 
						||
				Hyphenator.addExceptions(lang, lo.exceptions);
 | 
						||
				delete lo.exceptions;
 | 
						||
			}
 | 
						||
			//copy global exceptions to the language specific exceptions
 | 
						||
			if (exceptions.hasOwnProperty('global')) {
 | 
						||
				if (exceptions.hasOwnProperty(lang)) {
 | 
						||
					exceptions[lang] += ', ' + exceptions.global;
 | 
						||
				} else {
 | 
						||
					exceptions[lang] = exceptions.global;
 | 
						||
				}
 | 
						||
			}
 | 
						||
			//move exceptions from the the local 'exceptions'-obj to the 'language'-object
 | 
						||
			if (exceptions.hasOwnProperty(lang)) {
 | 
						||
				lo.exceptions = convertExceptionsToObject(exceptions[lang]);
 | 
						||
				delete exceptions[lang];
 | 
						||
			} else {
 | 
						||
				lo.exceptions = {};
 | 
						||
			}
 | 
						||
			convertPatterns(lang);
 | 
						||
			wrd = '[\\w' + lo.specialChars + '@' + String.fromCharCode(173) + '-]{' + min + ',}';
 | 
						||
			lo.genRegExp = new RegExp('(' + url + ')|(' + mail + ')|(' + wrd + ')', 'gi');
 | 
						||
			lo.prepared = true;
 | 
						||
		}
 | 
						||
		if (!!storage) {
 | 
						||
			try {
 | 
						||
				storage.setItem('Hyphenator_' + lang, window.JSON.stringify(lo));
 | 
						||
			} catch (e) {
 | 
						||
				//onError(e);
 | 
						||
			}
 | 
						||
		}
 | 
						||
		
 | 
						||
	},
 | 
						||
	
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-prepare
 | 
						||
	 * @description
 | 
						||
	 * This funtion prepares the Hyphenator-Object: If RemoteLoading is turned off, it assumes
 | 
						||
	 * that the patternfiles are loaded, all conversions are made and the callback is called.
 | 
						||
	 * If storage is active the object is retrieved there.
 | 
						||
	 * If RemoteLoading is on (default), it loads the pattern files and waits until they are loaded,
 | 
						||
	 * by repeatedly checking Hyphenator.languages. If a patterfile is loaded the patterns are
 | 
						||
	 * converted to their object style and the lang-object extended.
 | 
						||
	 * Finally the callback is called.
 | 
						||
	 * @param {function()} callback to call, when all patterns are loaded
 | 
						||
	 * @private
 | 
						||
	 */
 | 
						||
	prepare = function (callback) {
 | 
						||
		var lang, interval, tmp1, tmp2;
 | 
						||
		if (!enableRemoteLoading) {
 | 
						||
			for (lang in Hyphenator.languages) {
 | 
						||
				if (Hyphenator.languages.hasOwnProperty(lang)) {
 | 
						||
					prepareLanguagesObj(lang);
 | 
						||
				}
 | 
						||
			}
 | 
						||
			state = 2;
 | 
						||
			callback();
 | 
						||
			return;
 | 
						||
		}
 | 
						||
		// get all languages that are used and preload the patterns
 | 
						||
		state = 1;
 | 
						||
		for (lang in docLanguages) {
 | 
						||
			if (docLanguages.hasOwnProperty(lang)) {
 | 
						||
				if (!!storage && storage.getItem('Hyphenator_' + lang)) {
 | 
						||
					Hyphenator.languages[lang] = window.JSON.parse(storage.getItem('Hyphenator_' + lang));
 | 
						||
					if (exceptions.hasOwnProperty('global')) {
 | 
						||
						tmp1 = convertExceptionsToObject(exceptions.global);
 | 
						||
						for (tmp2 in tmp1) {
 | 
						||
							if (tmp1.hasOwnProperty(tmp2)) {
 | 
						||
								Hyphenator.languages[lang].exceptions[tmp2] = tmp1[tmp2];
 | 
						||
							}
 | 
						||
						}
 | 
						||
					}
 | 
						||
					//Replace exceptions since they may have been changed:
 | 
						||
					if (exceptions.hasOwnProperty(lang)) {
 | 
						||
						tmp1 = convertExceptionsToObject(exceptions[lang]);
 | 
						||
						for (tmp2 in tmp1) {
 | 
						||
							if (tmp1.hasOwnProperty(tmp2)) {
 | 
						||
								Hyphenator.languages[lang].exceptions[tmp2] = tmp1[tmp2];
 | 
						||
							}
 | 
						||
						}
 | 
						||
						delete exceptions[lang];
 | 
						||
					}
 | 
						||
					//Replace genRegExp since it may have been changed:
 | 
						||
					tmp1 = '[\\w' + Hyphenator.languages[lang].specialChars + '@' + String.fromCharCode(173) + '-]{' + min + ',}';
 | 
						||
					Hyphenator.languages[lang].genRegExp = new RegExp('(' + url + ')|(' + mail + ')|(' + tmp1 + ')', 'gi');
 | 
						||
					
 | 
						||
					delete docLanguages[lang];
 | 
						||
					continue;
 | 
						||
				} else {
 | 
						||
					loadPatterns(lang);
 | 
						||
				}
 | 
						||
			}
 | 
						||
		}
 | 
						||
		// if all patterns are loaded from storage: callback
 | 
						||
		if (countObjProps(docLanguages) === 0) {
 | 
						||
			state = 2;
 | 
						||
			callback();
 | 
						||
			return;
 | 
						||
		}
 | 
						||
		// else async wait until patterns are loaded, then callback
 | 
						||
		interval = window.setInterval(function () {
 | 
						||
			var finishedLoading = true, lang;
 | 
						||
			for (lang in docLanguages) {
 | 
						||
				if (docLanguages.hasOwnProperty(lang)) {
 | 
						||
					finishedLoading = false;
 | 
						||
					if (!!Hyphenator.languages[lang]) {
 | 
						||
						delete docLanguages[lang];
 | 
						||
						//do conversion while other patterns are loading:
 | 
						||
						prepareLanguagesObj(lang);
 | 
						||
					}
 | 
						||
				}
 | 
						||
			}
 | 
						||
			if (finishedLoading) {
 | 
						||
				//console.log('callig callback for ' + contextWindow.location.href);
 | 
						||
				window.clearInterval(interval);
 | 
						||
				state = 2;
 | 
						||
				callback();
 | 
						||
			}
 | 
						||
		}, 100);
 | 
						||
	},
 | 
						||
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-switchToggleBox
 | 
						||
	 * @description
 | 
						||
	 * Creates or hides the toggleBox: a small button to turn off/on hyphenation on a page.
 | 
						||
	 * @param {boolean} s true when hyphenation is on, false when it's off
 | 
						||
	 * @see Hyphenator.config
 | 
						||
	 * @private
 | 
						||
	 */		
 | 
						||
	toggleBox = function () {
 | 
						||
		var myBox, bdy, myIdAttribute, myTextNode, myClassAttribute,
 | 
						||
		text = (Hyphenator.doHyphenation ? 'Hy-phen-a-tion' : 'Hyphenation');
 | 
						||
		if (!!(myBox = contextWindow.document.getElementById('HyphenatorToggleBox'))) {
 | 
						||
			myBox.firstChild.data = text;
 | 
						||
		} else {
 | 
						||
			bdy = contextWindow.document.getElementsByTagName('body')[0];
 | 
						||
			myBox = createElem('div', contextWindow);
 | 
						||
			myIdAttribute = contextWindow.document.createAttribute('id');
 | 
						||
			myIdAttribute.nodeValue = 'HyphenatorToggleBox';
 | 
						||
			myClassAttribute = contextWindow.document.createAttribute('class');
 | 
						||
			myClassAttribute.nodeValue = dontHyphenateClass;
 | 
						||
			myTextNode = contextWindow.document.createTextNode(text);
 | 
						||
			myBox.appendChild(myTextNode);
 | 
						||
			myBox.setAttributeNode(myIdAttribute);
 | 
						||
			myBox.setAttributeNode(myClassAttribute);
 | 
						||
			myBox.onclick =  Hyphenator.toggleHyphenation;
 | 
						||
			myBox.style.position = 'absolute';
 | 
						||
			myBox.style.top = '0px';
 | 
						||
			myBox.style.right = '0px';
 | 
						||
			myBox.style.margin = '0';
 | 
						||
			myBox.style.backgroundColor = '#AAAAAA';
 | 
						||
			myBox.style.color = '#FFFFFF';
 | 
						||
			myBox.style.font = '6pt Arial';
 | 
						||
			myBox.style.letterSpacing = '0.2em';
 | 
						||
			myBox.style.padding = '3px';
 | 
						||
			myBox.style.cursor = 'pointer';
 | 
						||
			myBox.style.WebkitBorderBottomLeftRadius = '4px';
 | 
						||
			myBox.style.MozBorderRadiusBottomleft = '4px';
 | 
						||
			bdy.appendChild(myBox);
 | 
						||
		}
 | 
						||
	},
 | 
						||
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-hyphenateWord
 | 
						||
	 * @description
 | 
						||
	 * This function is the heart of Hyphenator.js. It returns a hyphenated word.
 | 
						||
	 *
 | 
						||
	 * If there's already a {@link Hyphenator-hypen} in the word, the word is returned as it is.
 | 
						||
	 * If the word is in the exceptions list or in the cache, it is retrieved from it.
 | 
						||
	 * If there's a '-' put a zeroWidthSpace after the '-' and hyphenate the parts.
 | 
						||
	 * @param {string} lang The language of the word
 | 
						||
	 * @param {string} word The word
 | 
						||
	 * @returns string The hyphenated word
 | 
						||
	 * @public
 | 
						||
	 */	
 | 
						||
	hyphenateWord = function (lang, word) {
 | 
						||
		var lo = Hyphenator.languages[lang],
 | 
						||
			parts, i, l, w, wl, s, hypos, p, maxwins, win, pat = false, patk, c, t, n, numb3rs, inserted, hyphenatedword, val;
 | 
						||
		if (word === '') {
 | 
						||
			return '';
 | 
						||
		}
 | 
						||
		if (word.indexOf(hyphen) !== -1) {
 | 
						||
			//word already contains shy; -> leave at it is!
 | 
						||
			return word;
 | 
						||
		}
 | 
						||
		if (enableCache && lo.cache.hasOwnProperty(word)) { //the word is in the cache
 | 
						||
			return lo.cache[word];
 | 
						||
		}
 | 
						||
		if (lo.exceptions.hasOwnProperty(word)) { //the word is in the exceptions list
 | 
						||
			return lo.exceptions[word].replace(/-/g, hyphen);
 | 
						||
		}
 | 
						||
		if (word.indexOf('-') !== -1) {
 | 
						||
			//word contains '-' -> hyphenate the parts separated with '-'
 | 
						||
			parts = word.split('-');
 | 
						||
			for (i = 0, l = parts.length; i < l; i++) {
 | 
						||
				parts[i] = hyphenateWord(lang, parts[i]);
 | 
						||
			}
 | 
						||
			return parts.join('-');
 | 
						||
		}
 | 
						||
		//finally the core hyphenation algorithm
 | 
						||
		w = '_' + word + '_';
 | 
						||
		wl = w.length;
 | 
						||
		s = w.split('');
 | 
						||
		if (word.indexOf("'") !== -1) {
 | 
						||
			w = w.toLowerCase().replace("'", "’"); //replace APOSTROPHE with RIGHT SINGLE QUOTATION MARK (since the latter is used in the patterns)
 | 
						||
		} else {
 | 
						||
			w = w.toLowerCase();
 | 
						||
		}
 | 
						||
		hypos = [];
 | 
						||
		numb3rs = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}; //check for member is faster then isFinite()
 | 
						||
		n = wl - lo.shortestPattern;
 | 
						||
		for (p = 0; p <= n; p++) {
 | 
						||
			maxwins = Math.min((wl - p), lo.longestPattern);
 | 
						||
			for (win = lo.shortestPattern; win <= maxwins; win++) {
 | 
						||
				if (lo.patterns.hasOwnProperty(patk = w.substring(p, p + win))) {
 | 
						||
					pat = lo.patterns[patk];
 | 
						||
					if (enableReducedPatternSet && (typeof pat === 'string')) {
 | 
						||
						lo.redPatSet[patk] = pat;
 | 
						||
					}
 | 
						||
					if (typeof pat === 'string') {
 | 
						||
						//convert from string 'a5b' to array [1,5] (pos,value)
 | 
						||
						t = 0;
 | 
						||
						val = [];
 | 
						||
						for (i = 0; i < pat.length; i++) {
 | 
						||
							if (!!(c = numb3rs[pat.charAt(i)])) {
 | 
						||
								val.push(i - t, c);
 | 
						||
								t++;								
 | 
						||
							}
 | 
						||
						}
 | 
						||
						pat = lo.patterns[patk] = val;
 | 
						||
					}
 | 
						||
				} else {
 | 
						||
					continue;
 | 
						||
				}
 | 
						||
				for (i = 0; i < pat.length; i++) {
 | 
						||
					c = p - 1 + pat[i];
 | 
						||
					if (!hypos[c] || hypos[c] < pat[i + 1]) {
 | 
						||
						hypos[c] = pat[i + 1];
 | 
						||
					}
 | 
						||
					i++;
 | 
						||
				}
 | 
						||
			}
 | 
						||
		}
 | 
						||
		inserted = 0;
 | 
						||
		for (i = lo.leftmin; i <= (word.length - lo.rightmin); i++) {
 | 
						||
			if (!!(hypos[i] & 1)) {
 | 
						||
				s.splice(i + inserted + 1, 0, hyphen);
 | 
						||
				inserted++;
 | 
						||
			}
 | 
						||
		}
 | 
						||
		hyphenatedword = s.slice(1, -1).join('');
 | 
						||
		if (enableCache) {
 | 
						||
			lo.cache[word] = hyphenatedword;
 | 
						||
		}
 | 
						||
		return hyphenatedword;
 | 
						||
	},
 | 
						||
		
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-hyphenateURL
 | 
						||
	 * @description
 | 
						||
	 * Puts {@link Hyphenator-urlhyphen} after each no-alphanumeric char that my be in a URL.
 | 
						||
	 * @param {string} url to hyphenate
 | 
						||
	 * @returns string the hyphenated URL
 | 
						||
	 * @public
 | 
						||
	 */
 | 
						||
	hyphenateURL = function (url) {
 | 
						||
		return url.replace(/([:\/\.\?#&_,;!@]+)/gi, '$&' + urlhyphen);
 | 
						||
	},
 | 
						||
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-removeHyphenationFromElement
 | 
						||
	 * @description
 | 
						||
	 * Removes all hyphens from the element. If there are other elements, the function is
 | 
						||
	 * called recursively.
 | 
						||
	 * Removing hyphens is usefull if you like to copy text. Some browsers are buggy when the copy hyphenated texts.
 | 
						||
	 * @param {Object} el The element where to remove hyphenation.
 | 
						||
	 * @public
 | 
						||
	 */
 | 
						||
	removeHyphenationFromElement = function (el) {
 | 
						||
		var h, i = 0, n;
 | 
						||
		switch (hyphen) {
 | 
						||
		case '|':
 | 
						||
			h = '\\|';
 | 
						||
			break;
 | 
						||
		case '+':
 | 
						||
			h = '\\+';
 | 
						||
			break;
 | 
						||
		case '*':
 | 
						||
			h = '\\*';
 | 
						||
			break;
 | 
						||
		default:
 | 
						||
			h = hyphen;
 | 
						||
		}
 | 
						||
		while (!!(n = el.childNodes[i++])) {
 | 
						||
			if (n.nodeType === 3) {
 | 
						||
				n.data = n.data.replace(new RegExp(h, 'g'), '');
 | 
						||
				n.data = n.data.replace(new RegExp(zeroWidthSpace, 'g'), '');
 | 
						||
			} else if (n.nodeType === 1) {
 | 
						||
				removeHyphenationFromElement(n);
 | 
						||
			}
 | 
						||
		}
 | 
						||
	},
 | 
						||
	
 | 
						||
	
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-registerOnCopy
 | 
						||
	 * @description
 | 
						||
	 * Huge work-around for browser-inconsistency when it comes to
 | 
						||
	 * copying of hyphenated text.
 | 
						||
	 * The idea behind this code has been provided by http://github.com/aristus/sweet-justice
 | 
						||
	 * sweet-justice is under BSD-License
 | 
						||
	 * @private
 | 
						||
	 */
 | 
						||
	registerOnCopy = function (el) {
 | 
						||
		var body = el.ownerDocument.getElementsByTagName('body')[0],
 | 
						||
		shadow,
 | 
						||
		selection,
 | 
						||
		range,
 | 
						||
		rangeShadow,
 | 
						||
		restore,
 | 
						||
		oncopyHandler = function (e) {
 | 
						||
			e = e || window.event;
 | 
						||
			var target = e.target || e.srcElement,
 | 
						||
			currDoc = target.ownerDocument,
 | 
						||
			body = currDoc.getElementsByTagName('body')[0],
 | 
						||
			targetWindow = 'defaultView' in currDoc ? currDoc.defaultView : currDoc.parentWindow;
 | 
						||
			if (target.tagName && dontHyphenate[target.tagName.toLowerCase()]) {
 | 
						||
				//Safari needs this
 | 
						||
				return;
 | 
						||
			}
 | 
						||
			//create a hidden shadow element
 | 
						||
			shadow = currDoc.createElement('div');
 | 
						||
			shadow.style.overflow = 'hidden';
 | 
						||
			shadow.style.position = 'absolute';
 | 
						||
			shadow.style.top = '-5000px';
 | 
						||
			shadow.style.height = '1px';
 | 
						||
			body.appendChild(shadow);
 | 
						||
			if (!!window.getSelection) {
 | 
						||
				//FF3, Webkit
 | 
						||
				selection = targetWindow.getSelection();
 | 
						||
				range = selection.getRangeAt(0);
 | 
						||
				shadow.appendChild(range.cloneContents());
 | 
						||
				removeHyphenationFromElement(shadow);
 | 
						||
				selection.selectAllChildren(shadow);
 | 
						||
				restore = function () {
 | 
						||
					shadow.parentNode.removeChild(shadow);
 | 
						||
					selection.addRange(range);
 | 
						||
				};
 | 
						||
			} else {
 | 
						||
				// IE
 | 
						||
				selection = targetWindow.document.selection;
 | 
						||
				range = selection.createRange();
 | 
						||
				shadow.innerHTML = range.htmlText;
 | 
						||
				removeHyphenationFromElement(shadow);
 | 
						||
				rangeShadow = body.createTextRange();
 | 
						||
				rangeShadow.moveToElementText(shadow);
 | 
						||
				rangeShadow.select();
 | 
						||
				restore = function () {
 | 
						||
					shadow.parentNode.removeChild(shadow);
 | 
						||
					if (range.text !== "") {
 | 
						||
						range.select();
 | 
						||
					}
 | 
						||
				};
 | 
						||
			}
 | 
						||
			window.setTimeout(restore, 0);
 | 
						||
		};
 | 
						||
		if (!body) {
 | 
						||
			return;
 | 
						||
		}
 | 
						||
		el = el || body;
 | 
						||
		if (window.addEventListener) {
 | 
						||
			el.addEventListener("copy", oncopyHandler, false);
 | 
						||
		} else {
 | 
						||
			el.attachEvent("oncopy", oncopyHandler);
 | 
						||
		}
 | 
						||
	},
 | 
						||
	
 | 
						||
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-hyphenateElement
 | 
						||
	 * @description
 | 
						||
	 * Takes the content of the given element and - if there's text - replaces the words
 | 
						||
	 * by hyphenated words. If there's another element, the function is called recursively.
 | 
						||
	 * When all words are hyphenated, the visibility of the element is set to 'visible'.
 | 
						||
	 * @param {Object} el The element to hyphenate
 | 
						||
	 * @private
 | 
						||
	 */
 | 
						||
	hyphenateElement = function (el) {
 | 
						||
		var hyphenatorSettings = Expando.getDataForElem(el),
 | 
						||
			lang = hyphenatorSettings.language, hyphenate, n, i,
 | 
						||
			controlOrphans = function (part) {
 | 
						||
				var h, r;
 | 
						||
				switch (hyphen) {
 | 
						||
				case '|':
 | 
						||
					h = '\\|';
 | 
						||
					break;
 | 
						||
				case '+':
 | 
						||
					h = '\\+';
 | 
						||
					break;
 | 
						||
				case '*':
 | 
						||
					h = '\\*';
 | 
						||
					break;
 | 
						||
				default:
 | 
						||
					h = hyphen;
 | 
						||
				}
 | 
						||
				if (orphanControl >= 2) {
 | 
						||
					//remove hyphen points from last word
 | 
						||
					r = part.split(' ');
 | 
						||
					r[1] = r[1].replace(new RegExp(h, 'g'), '');
 | 
						||
					r[1] = r[1].replace(new RegExp(zeroWidthSpace, 'g'), '');
 | 
						||
					r = r.join(' ');
 | 
						||
				}
 | 
						||
				if (orphanControl === 3) {
 | 
						||
					//replace spaces by non breaking spaces
 | 
						||
					r = r.replace(/[ ]+/g, String.fromCharCode(160));
 | 
						||
				}
 | 
						||
				return r;
 | 
						||
			};
 | 
						||
		if (Hyphenator.languages.hasOwnProperty(lang)) {
 | 
						||
			hyphenate = function (word) {
 | 
						||
				if (!Hyphenator.doHyphenation) {
 | 
						||
					return word;
 | 
						||
				} else if (urlOrMailRE.test(word)) {
 | 
						||
					return hyphenateURL(word);
 | 
						||
				} else {
 | 
						||
					return hyphenateWord(lang, word);
 | 
						||
				}
 | 
						||
			};
 | 
						||
			if (safeCopy && (el.tagName.toLowerCase() !== 'body')) {
 | 
						||
				registerOnCopy(el);
 | 
						||
			}
 | 
						||
			i = 0;
 | 
						||
			while (!!(n = el.childNodes[i++])) {
 | 
						||
				if (n.nodeType === 3 && n.data.length >= min) { //type 3 = #text -> hyphenate!
 | 
						||
					n.data = n.data.replace(Hyphenator.languages[lang].genRegExp, hyphenate);
 | 
						||
					if (orphanControl !== 1) {
 | 
						||
						n.data = n.data.replace(/[\S]+ [\S]+$/, controlOrphans);
 | 
						||
					}
 | 
						||
				}
 | 
						||
			}
 | 
						||
		}
 | 
						||
		if (hyphenatorSettings.isHidden && intermediateState === 'hidden') {
 | 
						||
			el.style.visibility = 'visible';
 | 
						||
			if (!hyphenatorSettings.hasOwnStyle) {
 | 
						||
				el.setAttribute('style', ''); // without this, removeAttribute doesn't work in Safari (thanks to molily)
 | 
						||
				el.removeAttribute('style');
 | 
						||
			} else {
 | 
						||
				if (el.style.removeProperty) {
 | 
						||
					el.style.removeProperty('visibility');
 | 
						||
				} else if (el.style.removeAttribute) { // IE
 | 
						||
					el.style.removeAttribute('visibility');
 | 
						||
				}  
 | 
						||
			}
 | 
						||
		}
 | 
						||
		if (hyphenatorSettings.isLast) {
 | 
						||
			state = 3;
 | 
						||
			documentCount--;
 | 
						||
			if (documentCount > (-1000) && documentCount <= 0) {
 | 
						||
				documentCount = (-2000);
 | 
						||
				onHyphenationDone();
 | 
						||
			}
 | 
						||
		}
 | 
						||
	},
 | 
						||
	
 | 
						||
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-hyphenateDocument
 | 
						||
	 * @description
 | 
						||
	 * Calls hyphenateElement() for all members of elements. This is done with a setTimout
 | 
						||
	 * to prevent a "long running Script"-alert when hyphenating large pages.
 | 
						||
	 * Therefore a tricky bind()-function was necessary.
 | 
						||
	 * @private
 | 
						||
	 */
 | 
						||
	hyphenateDocument = function () {
 | 
						||
		function bind(fun, arg) {
 | 
						||
			return function () {
 | 
						||
				return fun(arg);
 | 
						||
			};
 | 
						||
		}
 | 
						||
		var i = 0, el;
 | 
						||
		while (!!(el = elements[i++])) {
 | 
						||
			if (el.ownerDocument.location.href === contextWindow.location.href) {
 | 
						||
				window.setTimeout(bind(hyphenateElement, el), 0);
 | 
						||
			}
 | 
						||
		}
 | 
						||
	},
 | 
						||
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-removeHyphenationFromDocument
 | 
						||
	 * @description
 | 
						||
	 * Does what it says ;-)
 | 
						||
	 * @private
 | 
						||
	 */
 | 
						||
	removeHyphenationFromDocument = function () {
 | 
						||
		var i = 0, el;
 | 
						||
		while (!!(el = elements[i++])) {
 | 
						||
			removeHyphenationFromElement(el);
 | 
						||
		}
 | 
						||
		state = 4;
 | 
						||
	},
 | 
						||
		
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-createStorage
 | 
						||
	 * @description
 | 
						||
	 * inits the private var storage depending of the setting in storageType
 | 
						||
	 * and the supported features of the system.
 | 
						||
	 * @private
 | 
						||
	 */
 | 
						||
	createStorage = function () {
 | 
						||
		try {
 | 
						||
			if (storageType !== 'none' &&
 | 
						||
				typeof(window.localStorage) !== 'undefined' &&
 | 
						||
				typeof(window.sessionStorage) !== 'undefined' &&
 | 
						||
				typeof(window.JSON.stringify) !== 'undefined' &&
 | 
						||
				typeof(window.JSON.parse) !== 'undefined') {
 | 
						||
				switch (storageType) {
 | 
						||
				case 'session':
 | 
						||
					storage = window.sessionStorage;
 | 
						||
					break;
 | 
						||
				case 'local':
 | 
						||
					storage = window.localStorage;
 | 
						||
					break;
 | 
						||
				default:
 | 
						||
					storage = undefined;
 | 
						||
					break;
 | 
						||
				}
 | 
						||
			}
 | 
						||
		} catch (f) {
 | 
						||
			//FF throws an error if DOM.storage.enabled is set to false
 | 
						||
		}
 | 
						||
	},
 | 
						||
	
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-storeConfiguration
 | 
						||
	 * @description
 | 
						||
	 * Stores the current config-options in DOM-Storage
 | 
						||
	 * @private
 | 
						||
	 */
 | 
						||
	storeConfiguration = function () {
 | 
						||
		if (!storage) {
 | 
						||
			return;
 | 
						||
		}
 | 
						||
		var settings = {
 | 
						||
			'STORED': true,
 | 
						||
			'classname': hyphenateClass,
 | 
						||
			'donthyphenateclassname': dontHyphenateClass,
 | 
						||
			'minwordlength': min,
 | 
						||
			'hyphenchar': hyphen,
 | 
						||
			'urlhyphenchar': urlhyphen,
 | 
						||
			'togglebox': toggleBox,
 | 
						||
			'displaytogglebox': displayToggleBox,
 | 
						||
			'remoteloading': enableRemoteLoading,
 | 
						||
			'enablecache': enableCache,
 | 
						||
			'onhyphenationdonecallback': onHyphenationDone,
 | 
						||
			'onerrorhandler': onError,
 | 
						||
			'intermediatestate': intermediateState,
 | 
						||
			'selectorfunction': selectorFunction,
 | 
						||
			'safecopy': safeCopy,
 | 
						||
			'doframes': doFrames,
 | 
						||
			'storagetype': storageType,
 | 
						||
			'orphancontrol': orphanControl,
 | 
						||
			'dohyphenation': Hyphenator.doHyphenation,
 | 
						||
			'persistentconfig': persistentConfig,
 | 
						||
			'defaultlanguage': defaultLanguage
 | 
						||
		};
 | 
						||
		storage.setItem('Hyphenator_config', window.JSON.stringify(settings));
 | 
						||
	},
 | 
						||
	
 | 
						||
	/**
 | 
						||
	 * @name Hyphenator-restoreConfiguration
 | 
						||
	 * @description
 | 
						||
	 * Retrieves config-options from DOM-Storage and does configuration accordingly
 | 
						||
	 * @private
 | 
						||
	 */
 | 
						||
	restoreConfiguration = function () {
 | 
						||
		var settings;
 | 
						||
		if (storage.getItem('Hyphenator_config')) {
 | 
						||
			settings = window.JSON.parse(storage.getItem('Hyphenator_config'));
 | 
						||
			Hyphenator.config(settings);
 | 
						||
		}
 | 
						||
	};
 | 
						||
 | 
						||
	return {
 | 
						||
		
 | 
						||
		/**
 | 
						||
		 * @name Hyphenator.version
 | 
						||
		 * @memberOf Hyphenator
 | 
						||
		 * @description
 | 
						||
		 * String containing the actual version of Hyphenator.js
 | 
						||
		 * [major release].[minor releas].[bugfix release]
 | 
						||
		 * major release: new API, new Features, big changes
 | 
						||
		 * minor release: new languages, improvements
 | 
						||
		 * @public
 | 
						||
         */		
 | 
						||
		version: 'X.Y.Z',
 | 
						||
 | 
						||
		/**
 | 
						||
		 * @name Hyphenator.doHyphenation
 | 
						||
		 * @description
 | 
						||
		 * If doHyphenation is set to false (defaults to true), hyphenateDocument() isn't called.
 | 
						||
		 * All other actions are performed.
 | 
						||
		 */		
 | 
						||
		doHyphenation: true,
 | 
						||
		
 | 
						||
		/**
 | 
						||
		 * @name Hyphenator.languages
 | 
						||
		 * @memberOf Hyphenator
 | 
						||
		 * @description
 | 
						||
		 * Objects that holds key-value pairs, where key is the language and the value is the
 | 
						||
		 * language-object loaded from (and set by) the pattern file.
 | 
						||
		 * The language object holds the following members:
 | 
						||
		 * <table>
 | 
						||
		 * <tr><th>key</th><th>desc></th></tr>
 | 
						||
		 * <tr><td>leftmin</td><td>The minimum of chars to remain on the old line</td></tr>
 | 
						||
		 * <tr><td>rightmin</td><td>The minimum of chars to go on the new line</td></tr>
 | 
						||
		 * <tr><td>shortestPattern</td><td>The shortes pattern (numbers don't count!)</td></tr>
 | 
						||
		 * <tr><td>longestPattern</td><td>The longest pattern (numbers don't count!)</td></tr>
 | 
						||
		 * <tr><td>specialChars</td><td>Non-ASCII chars in the alphabet.</td></tr>
 | 
						||
		 * <tr><td>patterns</td><td>the patterns</td></tr>
 | 
						||
		 * </table>
 | 
						||
		 * And optionally (or after prepareLanguagesObj() has been called):
 | 
						||
		 * <table>
 | 
						||
		 * <tr><td>exceptions</td><td>Excpetions for the secified language</td></tr>
 | 
						||
		 * </table>
 | 
						||
		 * @public
 | 
						||
         */		
 | 
						||
		languages: {},
 | 
						||
		
 | 
						||
 | 
						||
		/**
 | 
						||
		 * @name Hyphenator.config
 | 
						||
			 * @description
 | 
						||
		 * Config function that takes an object as an argument. The object contains key-value-pairs
 | 
						||
		 * containig Hyphenator-settings. This is a shortcut for calling Hyphenator.set...-Methods.
 | 
						||
		 * @param {Object} obj <table>
 | 
						||
		 * <tr><th>key</th><th>values</th><th>default</th></tr>
 | 
						||
		 * <tr><td>classname</td><td>string</td><td>'hyphenate'</td></tr>
 | 
						||
		 * <tr><td>donthyphenateclassname</td><td>string</td><td>''</td></tr>
 | 
						||
		 * <tr><td>minwordlength</td><td>integer</td><td>6</td></tr>
 | 
						||
		 * <tr><td>hyphenchar</td><td>string</td><td>'&shy;'</td></tr>
 | 
						||
		 * <tr><td>urlhyphenchar</td><td>string</td><td>'zero with space'</td></tr>
 | 
						||
		 * <tr><td>togglebox</td><td>function</td><td>see code</td></tr>
 | 
						||
		 * <tr><td>displaytogglebox</td><td>boolean</td><td>false</td></tr>
 | 
						||
		 * <tr><td>remoteloading</td><td>boolean</td><td>true</td></tr>
 | 
						||
		 * <tr><td>enablecache</td><td>boolean</td><td>true</td></tr>
 | 
						||
		 * <tr><td>enablereducedpatternset</td><td>boolean</td><td>false</td></tr>
 | 
						||
		 * <tr><td>onhyphenationdonecallback</td><td>function</td><td>empty function</td></tr>
 | 
						||
		 * <tr><td>onerrorhandler</td><td>function</td><td>alert(onError)</td></tr>
 | 
						||
		 * <tr><td>intermediatestate</td><td>string</td><td>'hidden'</td></tr>
 | 
						||
		 * <tr><td>selectorfunction</td><td>function</td><td>[…]</td></tr>
 | 
						||
		 * <tr><td>safecopy</td><td>boolean</td><td>true</td></tr>
 | 
						||
		 * <tr><td>doframes</td><td>boolean</td><td>false</td></tr>
 | 
						||
		 * <tr><td>storagetype</td><td>string</td><td>'none'</td></tr>
 | 
						||
		 * </table>
 | 
						||
		 * @public
 | 
						||
		 * @example <script src = "Hyphenator.js" type = "text/javascript"></script>
 | 
						||
         * <script type = "text/javascript">
 | 
						||
         *     Hyphenator.config({'minwordlength':4,'hyphenchar':'|'});
 | 
						||
         *     Hyphenator.run();
 | 
						||
         * </script>
 | 
						||
         */
 | 
						||
		config: function (obj) {
 | 
						||
			var assert = function (name, type) {
 | 
						||
					if (typeof obj[name] === type) {
 | 
						||
						return true;
 | 
						||
					} else {
 | 
						||
						onError(new Error('Config onError: ' + name + ' must be of type ' + type));
 | 
						||
						return false;
 | 
						||
					}
 | 
						||
				},
 | 
						||
				key;
 | 
						||
 | 
						||
			if (obj.hasOwnProperty('storagetype')) {
 | 
						||
				if (assert('storagetype', 'string')) {
 | 
						||
					storageType = obj.storagetype;
 | 
						||
				}
 | 
						||
				if (!storage) {
 | 
						||
					createStorage();
 | 
						||
				}			
 | 
						||
			}
 | 
						||
			if (!obj.hasOwnProperty('STORED') && storage && obj.hasOwnProperty('persistentconfig') && obj.persistentconfig === true) {
 | 
						||
				restoreConfiguration();
 | 
						||
			}
 | 
						||
			
 | 
						||
			for (key in obj) {
 | 
						||
				if (obj.hasOwnProperty(key)) {
 | 
						||
					switch (key) {
 | 
						||
					case 'STORED':
 | 
						||
						break;
 | 
						||
					case 'classname':
 | 
						||
						if (assert('classname', 'string')) {
 | 
						||
							hyphenateClass = obj[key];
 | 
						||
						}
 | 
						||
						break;
 | 
						||
					case 'donthyphenateclassname':
 | 
						||
						if (assert('donthyphenateclassname', 'string')) {
 | 
						||
							dontHyphenateClass = obj[key];
 | 
						||
						}						
 | 
						||
						break;
 | 
						||
					case 'minwordlength':
 | 
						||
						if (assert('minwordlength', 'number')) {
 | 
						||
							min = obj[key];
 | 
						||
						}
 | 
						||
						break;
 | 
						||
					case 'hyphenchar':
 | 
						||
						if (assert('hyphenchar', 'string')) {
 | 
						||
							if (obj.hyphenchar === '­') {
 | 
						||
								obj.hyphenchar = String.fromCharCode(173);
 | 
						||
							}
 | 
						||
							hyphen = obj[key];
 | 
						||
						}
 | 
						||
						break;
 | 
						||
					case 'urlhyphenchar':
 | 
						||
						if (obj.hasOwnProperty('urlhyphenchar')) {
 | 
						||
							if (assert('urlhyphenchar', 'string')) {
 | 
						||
								urlhyphen = obj[key];
 | 
						||
							}
 | 
						||
						}
 | 
						||
						break;
 | 
						||
					case 'togglebox':
 | 
						||
						if (assert('togglebox', 'function')) {
 | 
						||
							toggleBox = obj[key];
 | 
						||
						}
 | 
						||
						break;
 | 
						||
					case 'displaytogglebox':
 | 
						||
						if (assert('displaytogglebox', 'boolean')) {
 | 
						||
							displayToggleBox = obj[key];
 | 
						||
						}
 | 
						||
						break;
 | 
						||
					case 'remoteloading':
 | 
						||
						if (assert('remoteloading', 'boolean')) {
 | 
						||
							enableRemoteLoading = obj[key];
 | 
						||
						}
 | 
						||
						break;
 | 
						||
					case 'enablecache':
 | 
						||
						if (assert('enablecache', 'boolean')) {
 | 
						||
							enableCache = obj[key];
 | 
						||
						}
 | 
						||
						break;
 | 
						||
					case 'enablereducedpatternset':
 | 
						||
						if (assert('enablereducedpatternset', 'boolean')) {
 | 
						||
							enableReducedPatternSet = obj[key];
 | 
						||
						}
 | 
						||
						break;
 | 
						||
					case 'onhyphenationdonecallback':
 | 
						||
						if (assert('onhyphenationdonecallback', 'function')) {
 | 
						||
							onHyphenationDone = obj[key];
 | 
						||
						}
 | 
						||
						break;
 | 
						||
					case 'onerrorhandler':
 | 
						||
						if (assert('onerrorhandler', 'function')) {
 | 
						||
							onError = obj[key];
 | 
						||
						}
 | 
						||
						break;
 | 
						||
					case 'intermediatestate':
 | 
						||
						if (assert('intermediatestate', 'string')) {
 | 
						||
							intermediateState = obj[key];
 | 
						||
						}
 | 
						||
						break;
 | 
						||
					case 'selectorfunction':
 | 
						||
						if (assert('selectorfunction', 'function')) {
 | 
						||
							selectorFunction = obj[key];
 | 
						||
						}
 | 
						||
						break;
 | 
						||
					case 'safecopy':
 | 
						||
						if (assert('safecopy', 'boolean')) {
 | 
						||
							safeCopy = obj[key];
 | 
						||
						}
 | 
						||
						break;
 | 
						||
					case 'doframes':
 | 
						||
						if (assert('doframes', 'boolean')) {
 | 
						||
							doFrames = obj[key];
 | 
						||
						}
 | 
						||
						break;
 | 
						||
					case 'storagetype':
 | 
						||
						if (assert('storagetype', 'string')) {
 | 
						||
							storageType = obj[key];
 | 
						||
						}						
 | 
						||
						break;
 | 
						||
					case 'orphancontrol':
 | 
						||
						if (assert('orphancontrol', 'number')) {
 | 
						||
							orphanControl = obj[key];
 | 
						||
						}
 | 
						||
						break;
 | 
						||
					case 'dohyphenation':
 | 
						||
						if (assert('dohyphenation', 'boolean')) {
 | 
						||
							Hyphenator.doHyphenation = obj[key];
 | 
						||
						}
 | 
						||
						break;
 | 
						||
					case 'persistentconfig':
 | 
						||
						if (assert('persistentconfig', 'boolean')) {
 | 
						||
							persistentConfig = obj[key];
 | 
						||
						}
 | 
						||
						break;
 | 
						||
					case 'defaultlanguage':
 | 
						||
						if (assert('defaultlanguage', 'string')) {
 | 
						||
							defaultLanguage = obj[key];
 | 
						||
						}
 | 
						||
						break;
 | 
						||
					default:
 | 
						||
						onError(new Error('Hyphenator.config: property ' + key + ' not known.'));
 | 
						||
					}
 | 
						||
				}
 | 
						||
			}
 | 
						||
			if (storage && persistentConfig) {
 | 
						||
				storeConfiguration();
 | 
						||
			}
 | 
						||
		},
 | 
						||
 | 
						||
		/**
 | 
						||
		 * @name Hyphenator.run
 | 
						||
			 * @description
 | 
						||
		 * Bootstrap function that starts all hyphenation processes when called.
 | 
						||
		 * @public
 | 
						||
		 * @example <script src = "Hyphenator.js" type = "text/javascript"></script>
 | 
						||
         * <script type = "text/javascript">
 | 
						||
         *   Hyphenator.run();
 | 
						||
         * </script>
 | 
						||
         */
 | 
						||
		run: function () {
 | 
						||
			documentCount = 0;
 | 
						||
			var process = function () {
 | 
						||
				try {
 | 
						||
					if (contextWindow.document.getElementsByTagName('frameset').length > 0) {
 | 
						||
						return; //we are in a frameset
 | 
						||
					}
 | 
						||
					documentCount++;
 | 
						||
					autoSetMainLanguage(undefined);
 | 
						||
					gatherDocumentInfos();
 | 
						||
					//console.log('preparing for ' + contextWindow.location.href);
 | 
						||
					prepare(hyphenateDocument);
 | 
						||
					if (displayToggleBox) {
 | 
						||
						toggleBox();
 | 
						||
					}
 | 
						||
				} catch (e) {
 | 
						||
					onError(e);
 | 
						||
				}
 | 
						||
			}, i, haveAccess, fl = window.frames.length;
 | 
						||
			
 | 
						||
			if (!storage) {
 | 
						||
				createStorage();
 | 
						||
			}
 | 
						||
			if (!documentLoaded && !isBookmarklet) {
 | 
						||
				runOnContentLoaded(window, process);
 | 
						||
			}
 | 
						||
			if (isBookmarklet || documentLoaded) {
 | 
						||
				if (doFrames && fl > 0) {
 | 
						||
					for (i = 0; i < fl; i++) {
 | 
						||
						haveAccess = undefined;
 | 
						||
						//try catch isn't enough for webkit
 | 
						||
						try {
 | 
						||
							//opera throws only on document.toString-access
 | 
						||
							haveAccess = window.frames[i].document.toString();
 | 
						||
						} catch (e) {
 | 
						||
							haveAccess = undefined;
 | 
						||
						}
 | 
						||
						if (!!haveAccess) {
 | 
						||
							contextWindow = window.frames[i];
 | 
						||
							process();
 | 
						||
						}						
 | 
						||
					}
 | 
						||
				}
 | 
						||
				contextWindow = window;
 | 
						||
				process();
 | 
						||
			}
 | 
						||
		},
 | 
						||
		
 | 
						||
		/**
 | 
						||
		 * @name Hyphenator.addExceptions
 | 
						||
			 * @description
 | 
						||
		 * Adds the exceptions from the string to the appropriate language in the 
 | 
						||
		 * {@link Hyphenator-languages}-object
 | 
						||
		 * @param {string} lang The language
 | 
						||
		 * @param {string} words A comma separated string of hyphenated words WITH spaces.
 | 
						||
		 * @public
 | 
						||
		 * @example <script src = "Hyphenator.js" type = "text/javascript"></script>
 | 
						||
         * <script type = "text/javascript">
 | 
						||
         *   Hyphenator.addExceptions('de','ziem-lich, Wach-stube');
 | 
						||
         *   Hyphenator.run();
 | 
						||
         * </script>
 | 
						||
         */
 | 
						||
		addExceptions: function (lang, words) {
 | 
						||
			if (lang === '') {
 | 
						||
				lang = 'global';
 | 
						||
			}
 | 
						||
			if (exceptions.hasOwnProperty(lang)) {
 | 
						||
				exceptions[lang] += ", " + words;
 | 
						||
			} else {
 | 
						||
				exceptions[lang] = words;
 | 
						||
			}
 | 
						||
		},
 | 
						||
		
 | 
						||
		/**
 | 
						||
		 * @name Hyphenator.hyphenate
 | 
						||
			 * @public
 | 
						||
		 * @description
 | 
						||
		 * Hyphenates the target. The language patterns must be loaded.
 | 
						||
		 * If the target is a string, the hyphenated string is returned,
 | 
						||
		 * if it's an object, the values are hyphenated directly.
 | 
						||
		 * @param {string|Object} target the target to be hyphenated
 | 
						||
		 * @param {string} lang the language of the target
 | 
						||
		 * @returns string
 | 
						||
		 * @example <script src = "Hyphenator.js" type = "text/javascript"></script>
 | 
						||
		 * <script src = "patterns/en.js" type = "text/javascript"></script>
 | 
						||
         * <script type = "text/javascript">
 | 
						||
		 * var t = Hyphenator.hyphenate('Hyphenation', 'en'); //Hy|phen|ation
 | 
						||
		 * </script>
 | 
						||
		 */
 | 
						||
		hyphenate: function (target, lang) {
 | 
						||
			var hyphenate, n, i;
 | 
						||
			if (Hyphenator.languages.hasOwnProperty(lang)) {
 | 
						||
				if (!Hyphenator.languages[lang].prepared) {
 | 
						||
					prepareLanguagesObj(lang);
 | 
						||
				}
 | 
						||
				hyphenate = function (word) {
 | 
						||
					if (urlOrMailRE.test(word)) {
 | 
						||
						return hyphenateURL(word);
 | 
						||
					} else {
 | 
						||
						return hyphenateWord(lang, word);
 | 
						||
					}
 | 
						||
				};
 | 
						||
				if (typeof target === 'string' || target.constructor === String) {
 | 
						||
					return target.replace(Hyphenator.languages[lang].genRegExp, hyphenate);
 | 
						||
				} else if (typeof target === 'object') {
 | 
						||
					i = 0;
 | 
						||
					while (!!(n = target.childNodes[i++])) {
 | 
						||
						if (n.nodeType === 3 && n.data.length >= min) { //type 3 = #text -> hyphenate!
 | 
						||
							n.data = n.data.replace(Hyphenator.languages[lang].genRegExp, hyphenate);
 | 
						||
						} else if (n.nodeType === 1) {
 | 
						||
                            // Modified by Kovid to use element lang only if it has been loaded
 | 
						||
							if (n.lang !== '' && Hyphenator.languages.hasOwnProperty(n.lang)) {
 | 
						||
								Hyphenator.hyphenate(n, n.lang);
 | 
						||
							} else {
 | 
						||
								Hyphenator.hyphenate(n, lang);
 | 
						||
							}
 | 
						||
						}
 | 
						||
					}
 | 
						||
				}
 | 
						||
			} else {
 | 
						||
				onError(new Error('Language "' + lang + '" is not loaded.'));
 | 
						||
			}
 | 
						||
		},
 | 
						||
		
 | 
						||
		/**
 | 
						||
		 * @name Hyphenator.getRedPatternSet
 | 
						||
			 * @description
 | 
						||
		 * Returns {@link Hyphenator-isBookmarklet}.
 | 
						||
		 * @param {string} lang the language patterns are stored for
 | 
						||
		 * @returns object {'patk': pat}
 | 
						||
		 * @public
 | 
						||
         */
 | 
						||
		getRedPatternSet: function (lang) {
 | 
						||
			return Hyphenator.languages[lang].redPatSet;
 | 
						||
		},
 | 
						||
		
 | 
						||
		/**
 | 
						||
		 * @name Hyphenator.isBookmarklet
 | 
						||
			 * @description
 | 
						||
		 * Returns {@link Hyphenator-isBookmarklet}.
 | 
						||
		 * @returns boolean
 | 
						||
		 * @public
 | 
						||
         */
 | 
						||
		isBookmarklet: function () {
 | 
						||
			return isBookmarklet;
 | 
						||
		},
 | 
						||
 | 
						||
		getConfigFromURI: function () {
 | 
						||
			var loc = null, re = {}, jsArray = document.getElementsByTagName('script'), i, j, l, s, gp, option;
 | 
						||
			for (i = 0, l = jsArray.length; i < l; i++) {
 | 
						||
				if (!!jsArray[i].getAttribute('src')) {
 | 
						||
					loc = jsArray[i].getAttribute('src');
 | 
						||
				}
 | 
						||
				if (!loc) {
 | 
						||
					continue;
 | 
						||
				} else {
 | 
						||
					s = loc.indexOf('Hyphenator.js?');
 | 
						||
					if (s === -1) {
 | 
						||
						continue;
 | 
						||
					}
 | 
						||
					gp = loc.substring(s + 14).split('&');
 | 
						||
					for (j = 0; j < gp.length; j++) {
 | 
						||
						option = gp[j].split('=');
 | 
						||
						if (option[0] === 'bm') {
 | 
						||
							continue;
 | 
						||
						}
 | 
						||
						if (option[1] === 'true') {
 | 
						||
							re[option[0]] = true;
 | 
						||
							continue;
 | 
						||
						}
 | 
						||
						if (option[1] === 'false') {
 | 
						||
							re[option[0]] = false;
 | 
						||
							continue;
 | 
						||
						}
 | 
						||
						if (isFinite(option[1])) {
 | 
						||
							re[option[0]] = parseInt(option[1], 10);
 | 
						||
							continue;
 | 
						||
						}
 | 
						||
						if (option[0] === 'onhyphenationdonecallback') {
 | 
						||
							re[option[0]] = new Function('', option[1]);
 | 
						||
							continue;
 | 
						||
						}
 | 
						||
						re[option[0]] = option[1];
 | 
						||
					}
 | 
						||
					break;
 | 
						||
				}
 | 
						||
			}
 | 
						||
			return re;
 | 
						||
		},
 | 
						||
 | 
						||
		/**
 | 
						||
		 * @name Hyphenator.toggleHyphenation
 | 
						||
			 * @description
 | 
						||
		 * Checks the current state of the ToggleBox and removes or does hyphenation.
 | 
						||
		 * @public
 | 
						||
         */
 | 
						||
		toggleHyphenation: function () {
 | 
						||
			if (Hyphenator.doHyphenation) {
 | 
						||
				removeHyphenationFromDocument();
 | 
						||
				Hyphenator.doHyphenation = false;
 | 
						||
				storeConfiguration();
 | 
						||
				toggleBox();
 | 
						||
			} else {
 | 
						||
				hyphenateDocument();
 | 
						||
				Hyphenator.doHyphenation = true;
 | 
						||
				storeConfiguration();
 | 
						||
				toggleBox();
 | 
						||
			}
 | 
						||
		}
 | 
						||
	};
 | 
						||
}(window));
 | 
						||
 | 
						||
//Export properties/methods (for google closure compiler)
 | 
						||
Hyphenator['languages'] = Hyphenator.languages;
 | 
						||
Hyphenator['config'] = Hyphenator.config;
 | 
						||
Hyphenator['run'] = Hyphenator.run;
 | 
						||
Hyphenator['addExceptions'] = Hyphenator.addExceptions;
 | 
						||
Hyphenator['hyphenate'] = Hyphenator.hyphenate;
 | 
						||
Hyphenator['getRedPatternSet'] = Hyphenator.getRedPatternSet;
 | 
						||
Hyphenator['isBookmarklet'] = Hyphenator.isBookmarklet;
 | 
						||
Hyphenator['getConfigFromURI'] = Hyphenator.getConfigFromURI;
 | 
						||
Hyphenator['toggleHyphenation'] = Hyphenator.toggleHyphenation;
 | 
						||
window['Hyphenator'] = Hyphenator;
 | 
						||
 | 
						||
if (Hyphenator.isBookmarklet()) {
 | 
						||
	Hyphenator.config({displaytogglebox: true, intermediatestate: 'visible', doframes: true});
 | 
						||
	Hyphenator.config(Hyphenator.getConfigFromURI());
 | 
						||
	Hyphenator.run();
 | 
						||
}
 |