User:Rumpelsepp/common.js

/* * 99% of this file is Hyphenator.js. * I'll probably separate it later (Wikipedia only gives you one js file). * Skip all the way down for custom js. */

/** @license Hyphenator 3.2.0 - 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, mathias@mnn.ch * @version 3.2.0 * @namespace Holds all methods and properties * @example * &lt;script src = "Hyphenator.js" type = "text/javascript"&gt;&lt;/script&gt; * &lt;script type = "text/javascript"&gt; *  Hyphenator.run; * &lt;/script&gt; */ 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.} * @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.} * @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.} * @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 * &lt;p class = "hyphenate"&gt;Text&lt;/p&gt; * @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 * &lt;p class = "donthyphenate"&gt;Text&lt;/p&gt; * @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 * 	 * 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: *  * lang-attribute in the html-tag * &lt;meta http-equiv = "content-language" content = "xy" /&gt; * &lt;meta name = "DC.Language" content = "xy" /&gt; * &lt;meta name = "language" content = "xy" /&gt; *  * 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 &lt;script&gt;-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: '3.2.0',

/**		 * @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: * 		 * And optionally (or after prepareLanguagesObj has been called): * 		 * @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 * @public * @example &lt;script src = "Hyphenator.js" type = "text/javascript"&gt;&lt;/script&gt; * &lt;script type = "text/javascript"&gt; *    Hyphenator.config({'minwordlength':4,'hyphenchar':'|'}); *    Hyphenator.run; * &lt;/script&gt; */		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 === '&shy;') { 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 &lt;script src = "Hyphenator.js" type = "text/javascript"&gt;&lt;/script&gt; * &lt;script type = "text/javascript"&gt; *  Hyphenator.run; * &lt;/script&gt; */		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 &lt;script src = "Hyphenator.js" type = "text/javascript"&gt;&lt;/script&gt; * &lt;script type = "text/javascript"&gt; *  Hyphenator.addExceptions('de','ziem-lich, Wach-stube'); *  Hyphenator.run; * &lt;/script&gt; */		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 &lt;script src = "Hyphenator.js" type = "text/javascript"&gt;&lt;/script&gt; * &lt;script src = "patterns/en.js" type = "text/javascript"&gt;&lt;/script&gt; * &lt;script type = "text/javascript"&gt; * var t = Hyphenator.hyphenate('Hyphenation', 'en'); //Hy|phen|ation * &lt;/script&gt; */		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) { if (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; }

/* Not Hyphenator.js below */

// From https://gist.github.com/705071 // And http://code.google.com/p/ligature-js/ function smarten(a) {	a = a.replace(/(^|[-\u2014/(\[{"\s])'/g, "$1\u2018");     // opening singles	a = a.replace(/'/g, "\u2019");                             // closing singles & apostrophes	a = a.replace(/(^|[-\u2014/(\[{\u2018\s])"/g, "$1\u201c"); // opening doubles a = a.replace(/"/g, "\u201d");                            // closing doubles

a = a.replace(/ffl/g, 'ﬄ') .replace(/ffi/g, 'ﬃ') .replace(/fl/g, 'ﬂ') .replace(/fi/g, 'ﬁ') .replace(/ff/g, 'ﬀ') .replace(/ij/g, 'ĳ') .replace(/IJ/g, 'Ĳ');

return a }

function smartenNode(node) {	if(node.nodeType == 3) node.nodeValue = smarten(node.nodeValue); }

// From http://blog.dingoeweb.com/javascript/recursive-iteration-through-the-html-dom iterate = function iterate(task, node) {	for(var x = 0; x < node.childNodes.length; x++) {		var childNode = node.childNodes[x]; task(childNode); if(childNode.childNodes.length > 0) iterate(task, childNode); } }

document.getElementById('searchInput').placeholder = "Search Wikipedia…";

document.getElementById('ca-edit').getElementsByTagName('a')[0].innerText = "Edit";

document.getElementById('p-tb').getElementsByTagName('h5')[0].innerText = "Tools"; document.getElementById('p-coll-print_export').getElementsByTagName('h5')[0].innerText = "Print";

iterate(smartenNode, document);

if(navigator.userAgent.match(/iPad/i)) {	var viewportmeta = document.createElement('meta'); viewportmeta.setAttribute('name', 'viewport'); viewportmeta.content = 'width=device-width, initial-scale=1.0, minimum-scale=1.0'; document.getElementsByTagName('head')[0].appendChild(viewportmeta); } else {	var images = document.getElementsByClassName("thumbinner"); for(var i = 0; i < images.length; i++) images[i].getElementsByTagName('a')[0].setAttribute('rel', 'lightbox');

var para = document.getElementsByTagName("p"); for(var i = 0; i < para.length; i++) para[i].className = "hyphenate";

Hyphenator.run; }