User:A.r.s.h.©/Large editor.js

// \n'; 				if (obj.focusLine.plain != '') { 					obj.changed.plain = '\n' + obj.changed.plain + '\n'; 				} 			} 			else { 				obj.changed.plain = '\n{| class="wikitable" border="1"\n|+ ' + wikEd.config.text['table caption'] + ' \n! ' + wikEd.config.text['table heading'] + ' !! ' + wikEd.config.text['table heading'] + ' \n|-\n| ' + wikEd.config.text['table cell'] + ' || ' + wikEd.config.text['table cell'] + ' \n|-\n| ' + wikEd.config.text['table cell'] + ' || ' + wikEd.config.text['table cell'] + ' \n|}\n'; 				if (obj.focusLine.plain != ) { 					obj.changed.plain = '\n' + obj.changed.plain + '\n'; 				} 			} 			break; 		// wikify: always done above 		case 'wikEdWikify': 			break;  		// textify: strip html from pasted content 		case 'wikEdTextify': 			wikEd.Textify(obj.changed); 			if (parameters == 'shift') { 				highlightNoTimeOut = true; 			} 			break;  		// redirect 		case 'wikEdRedirect': 			var linkTarget; 			if (obj.selection.plain != ) { 				linkTarget = obj.selection.plain; 			} 			else if (obj.selectionWord.plain != ) { 				linkTarget = obj.selectionWord.plain; 			} 			else { 				linkTarget = ' ' + wikEd.config.text['redirect article link'] + ' '; 			}  			// remove link text after | 			linkTarget = linkTarget.replace(/\|(.|\n)*/, );  			// remove formatting and spaces 			linkTarget = linkTarget.replace(/^(=+|'+|<[^>]*>|\s+|\[)+((.|\n)*?)(=+|'+|<[^>]*>|\s+|\])+$/g, '$2'); 			linkTarget = linkTarget.replace(/&lt;/g, '<'); 			linkTarget = linkTarget.replace(/&gt;/g, '>'); 			linkTarget = linkTarget.replace(/\s+/g, ' '); 			linkTarget = linkTarget.replace(/^\s+|\s+$/g, );  			obj.changed.plain = '#REDIRECT ' + linkTarget + ;  			// append to summary 			if (wikEd.wikiGlobals.wgUseAutomaticEditSummaries != true) { 				if (wikEd.inputElement.summary != null) { 					if ( (obj.selection.plain != ) || (obj.selectionWord.plain != ) ) { 						wikEd.inputElement.summary.value = wikEd.inputElement.summary.value.replace(/#REDIRECT( \[\^\*\]\])?(, *)?/g, ); 						wikEd.inputElement.summary.value = wikEd.AppendToSummary(wikEd.inputElement.summary.value, '#REDIRECT ' + linkTarget + ); 					} 					else { 						wikEd.inputElement.summary.value = wikEd.AppendToSummary(wikEd.inputElement.summary.value, '#REDIRECT'); 					} 				} 			} 			selectChanged = false; 			break;  		// find and replace 		case 'wikEdFindPrev': 		case 'wikEdFindNext': 		case 'wikEdJumpPrev': 		case 'wikEdJumpNext': 		case 'wikEdReplacePrev': 		case 'wikEdReplaceNext': 		case 'wikEdFindAll': 		case 'wikEdReplaceAll':  			// get the find text 			var findText;  			// unescape <, >, and & 			obj.changed.plain = obj.changed.plain.replace(/&lt;/g, '<'); 			obj.changed.plain = obj.changed.plain.replace(/&gt;/g, '>'); 			obj.changed.plain = obj.changed.plain.replace(/&amp;/g, '&');  			// copy selection/word under cursor to find field 			if ( (parameters == 'shift') && ( (buttonId == 'wikEdFindNext') || (buttonId == 'wikEdReplaceNext') ) ) { 				if (/\n/.test(obj.changed.plain) == false) { 					if (buttonId == 'wikEdFindNext') { 						wikEd.inputElement.find.value = obj.changed.plain; 					} 					else { 						wikEd.inputElement.replace.value = obj.changed.plain; 					} 					obj.changed.keepSel = true; 					obj.changed.plain = null; 					break; 				} 			}  			// get the find text from the selection 			if ( (buttonId == 'wikEdJumpPrev') || (buttonId == 'wikEdJumpNext') ) { 				findText = obj.changed.plain; 				if (obj.selection.plain == ) { 					obj.changed.keepSel = true; 					obj.changed.plain = null; 					break; 				} 			}  			// get the find text from the find field 			else { 				if (wikEd.inputElement.find.value != ) { 					findText = wikEd.inputElement.find.value; 				} 				else { 					obj.changed.plain = null; 					break; 				} 			}  			// get button status 			var regExpChecked = wikEd.GetAttribute(wikEd.regExp, 'checked'); 			var caseSensitiveChecked = wikEd.GetAttribute(wikEd.caseSensitive, 'checked');  			// get the replace text 			var replaceText = wikEd.inputElement.replace.value;  			// format the find and replace texts for a plain text search 			var useRegExp = true; 			if ( (regExpChecked == 'false') || (buttonId == 'wikEdJumpPrev') || (buttonId == 'wikEdJumpNext') ) { 				useRegExp = false; 			}  			// format the replace text for a regular expression search 			if ( (buttonId == 'wikEdReplacePrev') || (buttonId == 'wikEdReplaceNext') || (buttonId == 'wikEdReplaceAll') ) { 				if (useRegExp == true) {  					// substitute \\ \n \r \t \' \" \127 \x1f \u12ef 					replaceText = replaceText.replace(/\\\\/g, '\x00'); 					replaceText = replaceText.replace(/\\n/g, '\n'); 					replaceText = replaceText.replace(/\\r/g, '\r'); 					replaceText = replaceText.replace(/\\t/g, '\t'); 					replaceText = replaceText.replace(/\\'/g, '\''); 					replaceText = replaceText.replace(/\\"/g, '\"');  					replaceText = replaceText.replace(/\\([0-7]{3})/g, 						function(p, p1) { 							return(String.fromCharCode(parseInt(p1, 8))); 						} 					); 					replaceText = replaceText.replace(/\\x([0-9a-fA-F]{2})/g, 						function(p, p1) { 							return(String.fromCharCode(parseInt(p1, 16))); 						} 					); 					replaceText = replaceText.replace(/\\u([0-9a-fA-F]{4})/g, 						function(p, p1) { 							return(String.fromCharCode(parseInt(p1, 16))); 						} 					); 					replaceText = replaceText.replace(/\x00/g, '\\'); 				} 			}  			// check the regexp 			var replacedFlag = false; 			var regExpFind; 			if ( 				(buttonId == 'wikEdReplacePrev') || (buttonId == 'wikEdReplaceNext') || (buttonId == 'wikEdReplaceAll') || 				(buttonId == 'wikEdFindPrev') || (buttonId == 'wikEdFindNext') || (buttonId == 'wikEdFindAll') 			) { 				var regExpFindText = findText; 				if (useRegExp != true){ 					regExpFindText = regExpFindText.replace(/([\\^$*+?.\[\]{}:=!|,\-])/g, '\\$1'); 				} 				var regExpFlags = 'gm'; 				if (caseSensitive != true) { 					regExpFlags += 'i'; 				} 				try { 					regExpFind = new RegExp(regExpFindText, regExpFlags); 				} 				catch (err) { 					return; 				} 			}  			// replace all 			if (buttonId == 'wikEdReplaceAll') { 				if (regExpFind.test(obj.changed.plain)) { 					obj.changed.plain = obj.changed.plain.replace(regExpFind, replaceText); 					replacedFlag = true; 				} 				else { 					obj.changed.plain = null; 				} 			}  			// replace an existing selection 			else if ( (buttonId == 'wikEdReplacePrev') || (buttonId == 'wikEdReplaceNext') ) { 				if (regExpFind.test(obj.selection.plain)) { 					var replaced = obj.selection.plain.replace(regExpFind, replaceText); 					if (obj.changed.plain != replaced) { 						obj.changed.plain = replaced; 						replacedFlag = true; 					} 					else { 						obj.changed.plain = null; 					} 				} 				else { 					obj.changed.plain = null; 				} 			}  			else if ( 				(buttonId == 'wikEdFindPrev') || (buttonId == 'wikEdFindNext') || 				(buttonId == 'wikEdJumpPrev') || (buttonId == 'wikEdJumpNext') 			) { 				obj.changed.plain = null; 			}  			if ( 				(buttonId == 'wikEdFindPrev') || (buttonId == 'wikEdFindNext') || 				(buttonId == 'wikEdJumpPrev') || (buttonId == 'wikEdJumpNext') || 				(buttonId == 'wikEdReplacePrev') || (buttonId == 'wikEdReplaceNext') || 				(buttonId == 'wikEdFindAll') 			) { 				if (replacedFlag == false) {  					// get direction 					var backwards = false; 					if ( (buttonId == 'wikEdFindPrev') || (buttonId == 'wikEdJumpPrev') || (buttonId == 'wikEdReplacePrev') ) { 						backwards = true; 					}  					// get case sensitive 					var caseSensitive = false; 					if (caseSensitiveChecked == 'true') { 						caseSensitive = true; 					}  					// find all 					if (buttonId == 'wikEdFindAll') { 						var found; 						var foundRanges = [];  						// start at top of text 						wikEd.RemoveAllRanges(obj.sel); 						var range = wikEd.frameDocument.createRange; 						if (wikEd.frameBody.firstChild != null) { 							range.setStartBefore(wikEd.frameBody.firstChild); 						} 						range.collapse(true); 						range = obj.sel.addRange(range);  						// cycle through matches 						var scrollTop = wikEd.frameBody.scrollTop; 						do {  							// wikEd.Find(obj, findText, caseSensitive, backwards, wrap, useRegExp) 							found = wikEd.Find(obj, findText, caseSensitive, false, false, useRegExp); 							if (found == true) { 								foundRanges.push(obj.changed.range.cloneRange); 							} 						} while (found == true);  						// scroll back 						if (regExpChecked == 'false') { 							wikEd.frameBody.scrollTop = scrollTop; 						}  						// add the found ranges, Webkit does not support multiple selections 						wikEd.RemoveAllRanges(obj.sel); 						for (var i = 0; i < foundRanges.length; i ++) { 							obj.sel.addRange(foundRanges[i]); 						} 						obj.changed.plain = null; 						selectChanged = false; 					}  					// normal find 					else { 						obj.selectChanged = selectChanged; 						wikEd.Find(obj, findText, caseSensitive, backwards, true, useRegExp); 						selectChanged = obj.selectChanged; 					} 				} 			}  			// escape <, >, and & 			if (obj.changed.plain != null) { 				obj.changed.plain = obj.changed.plain.replace(/&/g, '&amp;'); 				obj.changed.plain = obj.changed.plain.replace(//g, '&gt;'); 			}  			// save search history to settings 			if ( (buttonId == 'wikEdFindPrev') || (buttonId == 'wikEdFindNext') || (buttonId == 'wikEdFindAll') ) { 				wikEd.AddToHistory('find'); 			} 			if ( (buttonId == 'wikEdReplacePrev') || (buttonId == 'wikEdReplaceNext') || (buttonId == 'wikEdReplaceAll') ) { 				wikEd.AddToHistory('find'); 				wikEd.AddToHistory('replace'); 			} 			obj.changed.keepSel = true; 			break;  		// fixbasic: fix characters, spaces, empty lines, certain headings, needed for all fixing functions 		// to do: only certain changes in multiline tags: comments, tables, subst 		case 'wikEdFixBasic': 			wikEd.FixBasic(obj.changed); 			obj.changed.keepSel = true; 			break; 		case 'wikEdFixPunct': 			wikEd.FixPunct(obj.changed); 			obj.changed.keepSel = true; 			break; 		case 'wikEdFixMath': 			wikEd.FixMath(obj.changed); 			obj.changed.keepSel = true; 			break; 		case 'wikEdFixChem': 			wikEd.FixChem(obj.changed); 			obj.changed.keepSel = true; 			break; 		case 'wikEdFixUnicode': 			wikEd.FixUnicode(obj.changed); 			obj.changed.keepSel = true; 			break; 		case 'wikEdFixRedirect': 			wikEd.FixRedirectCall(obj.changed); 			return; 		case 'wikEdFixRedirectReplace': 			wikEd.FixRedirectReplace(obj.changed); 			obj.changed.keepSel = true; 			break; 		case 'wikEdFixUnits': 			wikEd.FixUnits(obj.changed); 			obj.changed.keepSel = true; 			break; 		case 'wikEdFixDashes': 			wikEd.FixDashes(obj.changed); 			obj.changed.keepSel = true; 			break; 		case 'wikEdFixHtml': 			wikEd.FixHTML(obj.changed); 			obj.changed.keepSel = true; 			break; 		case 'wikEdFixRegExTypo': 			if ( (wikEd.config.regExTypoFix == true) && (wikEd.typoRulesFind.length > 0) ) { 				wikEd.FixTypos(obj.changed); 			} 			else { 				obj.changed.plain = null; 			} 			obj.changed.keepSel = true; 			break; 		case 'wikEdFixCaps': 			wikEd.FixCaps(obj.changed); 			obj.changed.keepSel = true; 			break; 		case 'wikEdFixAll': 			wikEd.FixAll(obj.changed); 			obj.changed.keepSel = true; 			break;  		// source on 		case 'wikEdSource': 			obj.changed.plain = obj.changed.code; 			obj.changed.plain = obj.changed.plain.replace(/(<(br|p)\b.*?>)/g, '$1\n\n'); 			obj.changed.plain = obj.changed.plain.replace(/&/g, '&amp;'); 			obj.changed.plain = obj.changed.plain.replace(//g, '&gt;'); 			highlightSyntax = false; 			break;  		// insert tags 		case 'wikEdInsertTags': 			var tagOpen = parameters[0] || ; 			var tagClose = parameters[1] || ; 			var sampleText = parameters[2] || ; 			tagOpen = tagOpen.replace(/&/g, '&amp;'); 			tagOpen = tagOpen.replace(//g, '&gt;'); 			tagClose = tagClose.replace(/&/g, '&amp;'); 			tagClose = tagClose.replace(//g, '&gt;'); 			tagsampleText = sampleText.replace(/&/g, '&amp;'); 			tagsampleText = sampleText.replace(//g, '&gt;');   			// single string to insert 			if ( (tagOpen.length > 0) && (tagClose.length == 0) && (sampleText.length == 0) ) { 				obj.changed = obj.cursor; 				obj.changed.plain = tagOpen; 			} 			else if ( (tagOpen.length == 0) && (tagClose.length == 0) && (sampleText.length > 0) ) { 				obj.changed = obj.cursor; 				obj.changed.plain = sampleText; 			}  			// opening and closing strings 			else if ( (obj.changed.plain == ) && (sampleText.length > 0) ) { 				obj.changed.plain = tagOpen + sampleText + tagClose;  				// select sample text 				selectChangedText = sampleText; 				obj.changed.keepSel = true; 			} 			else { 				obj.changed.plain = tagOpen + obj.changed.plain + tagClose; 			} 			break;  		// convert wiki tables to html //  		case 'wikEdTablify': 			obj.changed.keepSel = true; 			if (wikEd.tableMode == true) { 				wikEd.WikiTableToHtml(obj.changed); 			} 			break;  		// update text view using current control button settings //  		case 'wikEdUpdateAll': 			obj.changed.keepSel = true; 			if (parameters != null) { 				if (parameters.keepSel == false) { 					obj.changed.keepSel = false; 				} 			} 			break;  		// custom edit functions 		default: 			if (CustomHandler != null) { 				CustomHandler(obj); 			} 			else { 				alert('Unknown edit function \ + buttonId + '\); 			} 			break; 	}  	// pause frame spellchecking 	var pauseFrameSpellchecking = false; 	var frameSpellchecking = wikEd.frameBody.spellcheck; 	if (frameSpellchecking == true) { 		var wholeLength = 0; 		var changedLength = 0; 		if (obj.whole != null) { 			if (obj.whole.plain != null) { 				wholeLength = obj.whole.plain.length; 			} 		} 		if (obj.changed.plain != null) { 			changedLength = obj.changed.plain.length; 		} 		if ( (changedLength > 10000) || (wholeLength > 10000) ) { 			pauseFrameSpellchecking = true; 			wikEd.frameBody.spellcheck = false; 		} 	}  	// get the scroll position 	var frameScrollTop = wikEd.frameBody.scrollTop; 	var frameScrollLeft = wikEd.frameBody.scrollLeft;  	// update the selection ranges, do not add any text changes 	if (obj.changed.plain == null) { 		if (buttonId != 'wikEdFindAll') { 			wikEd.RemoveAllRanges(obj.sel); 			obj.sel.addRange(obj.changed.range);  			// scroll the selected text into the viewport 			if (selectChanged != false) { 				wikEd.ScrollToSelection; 			} 		} 	}  	// apply text changes 	else {  		// a text change erases the last version for redo all 		if ( (buttonId != 'wikEdUndo') && (buttonId != 'wikEdRedo') && (buttonId != 'wikEdUndoAll') ) { 			wikEd.lastVersion = null; 		}  		// highlight the syntax 		obj.html = obj.changed.plain; 		if (highlightSyntax == true) { 			if (obj.changed.from == 'whole') { 				obj.whole = true; 			} 			wikEd.HighlightSyntax(obj, highlightNoTimeOut); 		}  		// at least highlight tab characters 		else { 			obj.html = obj.html.replace(/(\t)/g, ' $1 '); 		}  		// display multiple blanks as blank-  		obj.html = obj.html.replace(/(^|\n) /g, '$1 '); 		obj.html = obj.html.replace(/ (\n|$)/g, ' $1'); 		obj.html = obj.html.replace(/ {2}/g, '  '); 		obj.html = obj.html.replace(/ {2}/g, '  ');  		// newlines to 		obj.html = obj.html.replace(/\n/g, ' ');  		// make changed range text the current selection 		wikEd.RemoveAllRanges(obj.sel); 		var range = obj.changed.range; 		obj.sel.addRange(range);  		// replace the selection with changed text 		// Opera 9.50beta bug: inserthtml removes blanks and generates consecutive text nodes 		if (obj.html != ) { 			var reselectBefore = ; 			var reselectAfter = ''; 			if (obj.changed.from != 'whole') { 				wikEd.insertCounter ++; 				reselectBefore = ' '; 				reselectAfter = ' '; 			} 			wikEd.FrameExecCommand('inserthtml', reselectBefore + obj.html + reselectAfter); 		} 		else if (obj.sel.isCollapsed == false) { 			wikEd.FrameExecCommand('delete'); 		}  		// select the whole text after replacing the whole text and scroll to same height 		if (obj.changed.from == 'whole') { 			wikEd.RemoveAllRanges(obj.sel); 			wikEd.frameBody.scrollTop = frameScrollTop; 			var range = wikEd.frameDocument.createRange; 			range.setStartBefore(wikEd.frameBody.firstChild); 			range.setEndAfter(wikEd.frameBody.lastChild); 			obj.sel.addRange(range); 			selectChanged = false; 		}  		// select the changed text and scroll it into the viewport 		else if (selectChanged != false) { 			wikEd.RemoveAllRanges(obj.sel); 			var range = wikEd.frameDocument.createRange; 			var startNodeReselect = wikEd.frameDocument.getElementById('wikEdScrollBefore' + wikEd.insertCounter); 			var endNodeReselect = wikEd.frameDocument.getElementById('wikEdScrollAfter' + wikEd.insertCounter); 			range.setStartAfter(startNodeReselect); 			// should be range.setEndAfter, but that causes caret at start of next line due to https://bugzilla.mozilla.org/show_bug.cgi?id=587461 			range.setEndBefore(endNodeReselect); 			obj.sel.addRange(range); 			wikEd.ScrollToNodes(startNodeReselect, endNodeReselect); 		} 	}  	// remove selection, keep whole text auto-selection as warning 	if ( 		( (obj.changed.keepSel != true) && (obj.changed.from != 'whole') ) || 		(obj.changed.keepSel == false) || 		(buttonId == 'wikEdRedirect') || 		( (buttonId == 'wikEdWikify') && (parameters == 'whole') ) 	) { 		if (obj.sel.rangeCount == 0) { 			obj.sel.collapse(wikEd.frameBody, 0); 		} 		else { 			obj.sel.collapseToEnd; 		}  		// focus edit area to continue editing as there is no selection that would be overwritten 		wikEd.frameWindow.focus; 	}  	// reset button to active, reset cursor 	if (buttonObj != null) { 		if (buttonObj.className != 'wikEdButtonInactive') { 			buttonObj.className = 'wikEdButton'; 		} 		buttonObj.style.cursor = 'auto'; 	}  	// grey out inactive buttons 	wikEd.InactiveButtons;  	// add event handlers to unhide refs and templates 	if ( (highlightSyntax == true) && (obj.changed.plain != null) ) {  		// add ref and template names to hide buttons 		wikEd.HighlightNamedHideButtons;  		// add event handlers to unhide refs and templates 		wikEd.HideAddHandlers;  		// add event handlers to make highlighted frame links ctrl-clickable 		wikEd.LinkifyAddHandlers; 	}  	// resume frame spellchecking 	if (pauseFrameSpellchecking == true) { 		wikEd.frameBody.spellcheck = true; 	}  	return; };   // // wikEd.LocalPreviewAjaxHandler: process the returned article preview //  wikEd.LocalPreviewAjaxHandler = function(ajax) {  	wikEd.previewIsAjax = true;  	// get response 	var html = ajax.responseText;  	// livepreview 	if (html.indexOf(' ') != -1) { 		html = html.replace(/\s*<\/livepreview>\s*/, ); 		html = html.replace(/\s*<\/preview>\s*/, ); 		html = html.replace(/&lt;/g, '<'); 		html = html.replace(/&gt;/g, '>'); 		html = html.replace(/&quot;/g, '"'); 		html = html.replace(/&apos;/g, '\); 		html = html.replace(/&amp;/g, '&'); 		html = html.replace(/(.|\n)*(.|\n)*?<\/div>/, ); 	}  	// full preview page 	else {  		// attach stylesheet declarations to document (GeSHi) 		var regExpMatch; 		var regExp = /]*?type="text\/css">((.|\n)*?)<\/style>/gi; 		while ( (regExpMatch = regExp.exec(html)) != null) { 			var css = regExpMatch[2]; 			var stylesheet = new wikEd.StyleSheet(document); 			stylesheet.AddCSSRules(css); 		}  		// get preview html 		html = wikEd.StringGetInnerHTML(html, 'div', 'id', 'wikiPreview', true); 		html = wikEd.StringGetInnerHTML(html, 'div', 'class', 'previewnote', true, false, true); 		html = html.replace(//g, ); 		html = html.replace(/\s+$/g, ); 	}  	// clean form elements 	html = html.replace(/<\/?form\b[^>]*>/g, ); 	html = html.replace(/(<\/?input\b[^>]*?)\bname="search"([^>]*>)/g, '$1$2');  	// remove cite errors for automatic section preview refs 	html = html.replace(/(]*?\bclass="wikEdPreviewRefs"[^>]*>(.|\s)*$)/, 		function (p, p1, p2) { 			p1 = p1.replace(/]*?\bclass="error"[^>]*>(.|\s)*?<\/strong>/g, ); 			return(p1); 		} 	); 	wikEd.previewBox.innerHTML = html;  	// init sortable tables (wikibits.js) 	if (typeof(sortables_init) == 'function') { 		sortables_init; 	}  	// init collapsible tables (common.js) 	if (typeof(createCollapseButtons) == 'function') { 		createCollapseButtons; 	}  	// scroll to button, textarea, or preview field 	wikEd.ScrollToPreview;  	// run scheduled custom functions 	wikEd.ExecuteHook(wikEd.config.previewHook);  	return; };   // // wikEd.FilePreviewAjaxHandler: process the returned image addresses //  wikEd.FilePreviewAjaxHandler = function(ajax) {  	// get response 	var html = ajax.responseText;  	// html-ize 	html = html.replace(/\s*<\/preview>\s*/, ); 	html = html.replace(/\s*<\/livepreview>\s*/, ); 	html = html.replace(/&lt;/g, '<'); 	html = html.replace(/&gt;/g, '>'); 	html = html.replace(/&amp;/g, '&'); 	html = html.replace(/&quot;/g, '"'); 	html = html.replace(/&apos;/g, '\); 	html = html.replace(/<\/?(br|p)\b.*?>/g, '\n');  	// parse response into file url cache 	var regExpFile = new RegExp('\\n((Image|File|' + wikEd.config.text['wikicode Image'] + '|' + wikEd.config.text['wikicode File'] + '):[^ ]+) +(\\d+) +(.*)', 'ig'); 	var regExpMatch; 	while ( (regExpMatch = regExpFile.exec(html)) != null) { 		var file = regExpMatch[1]; 		var filePreviewSize = regExpMatch[3]; 		var links = regExpMatch[4]; 		var fileObj = {}; 		var regExpMatch; 		if ( (regExpMatch = /\bsrc="(.+?)"/.exec(links)) != null) { 			fileObj.url = regExpMatch[1]; 			if ( (regExpMatch = /\bwidth="(\d+)"/.exec(links)) != null) { 				fileObj.width = parseInt(regExpMatch[1]); 			} 			if ( (regExpMatch = /\bheight="(\d+)"/.exec(links)) != null) { 				fileObj.height = parseInt(regExpMatch[1]); 			} 		} 		else { 			fileObj.url = wikEd.config.image['noFile']; 			fileObj.width = 16; 			fileObj.height = 16; 		} 		wikEd.filePreviewCache['wikEd' + file + filePreviewSize] = fileObj; 	}  	// cycle through file preview spans and add missing images as background 	for (var i = 0; i < wikEd.filePreviewNo; i ++) { 		if (wikEd.filePreviewIds[i] != ) { 			var span = wikEd.frameDocument.getElementById('wikEdFilePreview' + i); 			var fileNameSize = wikEd.filePreviewIds[i]; 			var fileObj = wikEd.filePreviewCache['wikEd' + fileNameSize]; 			if (fileObj != null) { 				span.style.backgroundImage = 'url(' + fileObj.url + ')'; 				if (fileObj.height != null) { 					span.style.height = fileObj.height + 'px'; 				} 				if (fileObj.width != null) { 					span.style.width = fileObj.width + 'px'; 				} 				span.style.display = 'block'; 			} 			wikEd.filePreviewIds[i] = ; 		} 	}  	return; };   // // wikEd.DiffResponse: calculate calculate and linkify the diff between two versions (code copied to wikEdDiff.js) //  wikEd.DiffResponse = function(oldVersion, newVersion) {  	// add trailing newline 	if (oldVersion.substr(oldVersion.length - 1, 1) != '\n') { 		oldVersion += '\n'; 	} 	if (newVersion.substr(newVersion.length - 1, 1) != '\n') { 		newVersion += '\n'; 	}  	// call external diff program 	var diffText = WDiffString(oldVersion, newVersion); 	if (wikEd.config.fullDiff != true) { 		diffText = WDiffShortenOutput(diffText); 	}  	// linkify blockwise with breaks at delete and block move tags 	var diffTextLinkified = ; 	var regExp = /]+?\bclass="wDiffHtml(Delete|Block)"[^>]*>/g; 	var regExpMatch; 	var pos = 0; 	while ( (regExpMatch = regExp.exec(diffText)) != null) { 		diffTextLinkified += wikEd.DiffLinkify(diffText.substring(pos, regExpMatch.index)) + regExpMatch[0]; 		pos = regExp.lastIndex; 	} 	diffTextLinkified += wikEd.DiffLinkify(diffText.substr(pos));  	return(diffTextLinkified); };   // // wikEd.DiffLinkify: linkify external links and wikilinks in diffed text as  anchor elements (code copied to wikEdDiff.js) //  wikEd.DiffLinkify = function(html) {  	// &lt; &gt; to \x00 \x01 	html = html.replace(/&lt;/g, '\x00'); 	html = html.replace(/&gt;/g, '\x01');  	// external links 	html = html.replace(/\b(((https?|ftp|irc|gopher):\/\/)|news:|mailto:)([^\x00-\x20\s"\[\]\x7f\|\{\}<>]|<[^>]*>)+?(?=([\!"\(\)\.\,\:\;\‘-•]*\s|[\x00-\x20\s"\[\]\x7f\|\{\}]))/gi, 		function (p) { 			var whole = p;  			var title = whole; 			title = title.replace(/\x00!--.*?--\x01/g, ); 			title = title.replace(/.*--\x01|\x00!--.*/g, ); 			title = title.replace(/<.*?>/g, ); 			title = title.replace(/^.*>|<.*$/g, ); 			title = title.replace(/^\s+|\s+$/g, ); 			title = decodeURI(title);  			var url = title.replace(/\s/g, '_'); 			url = encodeURI(url); 			url = url.replace(/"/g, '%22'); 			url = url.replace(/'/g, '%27'); 			url = url.replace(/#/g, '%23');  			var linkTitle = title.replace(/"/g, '&quot;');  			// linkify all url text fragments between highlighting s seperately 			var anchorOpen = ''; 			var anchorClose = ''; 			whole = whole.replace(/(<[^>]*>)/g, anchorClose + '$1' + anchorOpen); 			return(anchorOpen + whole + anchorClose); 		} 	);  	// linkify links and templates 	if ( (wikEd.wikiGlobals.wgServer != null) && (wikEd.wikiGlobals.wgArticlePath != null) ) {  		//                   1  text       3   1 4 {{ 5title        56                6 4 		html = html.replace(/(\[\[([^|\[\]{}\n]+)(\|[^\[\]{}<>]*)?\]\])|(\{\{([^|\[\]{}\n]*)([^\[\]{}<>]*\}\})?)/g, 		function (p, p1, p2, p3, p4, p5, p6) { 				var articleName = p2 || ; 				var templateName = p5 || ; 				var whole = p;  				// extract title 				var title = articleName; 				if (title == ) { 					title = templateName; 				} 				title = title.replace(/\x00!--.*?--\x01/g, ); 				title = title.replace(/.*--\x01|\x00!--.*/g, ); 				title = title.replace(/<.*?>/g, ); 				title = title.replace(/^.*>|<.*$/g, ); 				title = title.replace(/^\s+|\s+$/g, );  				// /subpage refers to a subpage of the current page,  to a section of the current page 				if ( (title.indexOf('/') == 0) || (title.indexOf('#') == 0) ) { 					title = wikEd.pageName + title; 				}  				// create url 				var url = title.replace(/\s/g, '_'); 				url = encodeURI(url); 				url = url.replace(/"/g, '%22'); 				url = url.replace(/'/g, '%27'); 				url = url.replace(/#/g, '%23'); 				var articleTitle = title.replace(/"/g, '&quot;'); 				if (templateName != ) { 					if (/:/.test(title) == false) { 						url = 'Template:' + url; 						articleTitle = 'Template:' + articleTitle; 					} 				} 				url = wikEd.wikiGlobals.wgServer + wikEd.wikiGlobals.wgArticlePath.replace(/\$1/, url);  				// linkify all text fragments between highlighting s seperately 				var anchorOpen = ''; 				var anchorClose = '</a>'; 				whole = whole.replace(/(<[^>]*>)/g, anchorClose + '$1' + anchorOpen); 				return(anchorOpen + whole + anchorClose); 			} 		); 	}  	// \x00 and \x01 back to &lt; and &gt; 	html = html.replace(/\x00/g, '&lt;'); 	html = html.replace(/\x01/g, '&gt;');  	return(html); };   // // wikEd.StringGetInnerHTML: get innerHTML of element from html in a string; can also get text before or after node //  wikEd.StringGetInnerHTML = function(html, tag, attrib, value, defaultToWholeHTML, getBeforeHTML, getAfterHTML) {  	var startPos; 	var startLength; 	var endPos; 	var endLength; 	var level = 0; 	var string = ; 	var regExpMatch;  	var attribValue = ; 	if (attrib != ) { 		attribValue = '[^>]*?' + attrib + '\\s*=\\s*("|\\\')?' + value + '\\1'; 	} 	var regExpStart = new RegExp('<' + tag + '\\b' + attribValue + '[^>]*?>', 'gi'); 	if ( (regExpMatch = regExpStart.exec(html)) != null) { 		startPos = regExpMatch.index; 		startLength = regExpMatch[0].length; 		var regExpParse = new RegExp('<(\\/?)' + tag + '\\b.*?>', 'g'); 		regExpParse.lastIndex = startPos; 		while ( (regExpMatch = regExpParse.exec(html)) != null) { 			if (regExpMatch[1] == ) { 				level ++; 			} 			else { 				level --; 				if (level == 0) { 					endPos = regExpMatch.index; 					endLength = regExpMatch[0].length; 					break; 				} 			} 		} 	}  	// return whole html if node does not exist 	if (endPos == null) { 		if (defaultToWholeHTML == true) { 			string = html; 		} 	}  	// return text before node 	else if (getBeforeHTML == true) { 		string = html.substr(0, startPos); 	}  	// return text after node 	else if (getAfterHTML == true) { 		string = html.substr(endPos + endLength); 	}  	// return innerHTML of node 	else { 		string = html.substring(startPos + startLength, endPos); 	}  	return(string); };   // // wikEd.ScrollToPreview: scroll to edit buttons, textarea, or preview field depending on current position //  wikEd.ScrollToPreview = function {  	// reset fixed height to auto 	wikEd.previewBox.style.height = 'auto';  	var scrollOffset = window.pageYOffset || document.body.scrollTop; 	var inputOffset = wikEd.GetOffsetTop(wikEd.inputWrapper); 	var editOffset = wikEd.GetOffsetTop(wikEd.editWrapper); 	var submitOffset = 0; 	if (wikEd.saveButton != null) { 		submitOffset = wikEd.GetOffsetTop(wikEd.saveButton); 	} 	else if (wikEd.previewButton != null) { 		submitOffset = wikEd.GetOffsetTop(wikEd.previewButton); 	} 	else if (wikEd.diffPreviewButton != null) { 		submitOffset = wikEd.GetOffsetTop(wikEd.diffPreviewButton); 	} 	var editHeight = wikEd.editWrapper.clientHeight;  	if (scrollOffset > submitOffset) { 		window.scroll(0, submitOffset); 	} 	else if (scrollOffset > (editHeight / 2 + editOffset) ) { 		window.scroll(0, submitOffset); 	} 	else if (scrollOffset > editOffset) { 		window.scroll(0, editOffset); 	} 	else { 		window.scroll(0, inputOffset); 	} 	return; };   // // wikEd.LinkifyAddHandlers: register click handlers to make highlighted frame links ctrl-clickable (linkify) //  wikEd.LinkifyAddHandlers = function {  	if (wikEd.config.linkify != true) { 		return; 	}  	// much faster than individual getElementById in SeaMonkey 1.1.18 	var spans = wikEd.frameDocument.getElementsByTagName('span'); 	for (var i = 0; i < spans.length; i ++) { 		var spanId = spans[i].id; 		if (spanId != null) { 			if (spanId.indexOf('wikEdLinkify') == 0) { 				wikEd.AddEventListener(spans[i], 'click', wikEd.LinkifyHandler, true); 			} 		} 	} 	return; };   // // wikEd.HighlightNamedHideButtons: register :before text for named hiding buttons //  wikEd.HighlightNamedHideButtons = function {  	if (wikEd.refHide != true) { 		return; 	}  	var rules = ;  	// references 	for (var i = 0; i < wikEd.referenceArray.length; i ++) { 		if (wikEd.referenceArray[i].added == true) { 			continue; 		} 		rules += '.wikEdRefButton' + i + ' { border: 1px solid; border-color: #e8e8e8 #444 #444 #e8e8e8; background: #d8d4d0; }\n';  		rules += '.wikEdRefButtonShow' + i + ' { border: 1px solid; border-color: #000 #e8e8e8 #e8e8e8 #000; background: #c8c4c0; }\n';  		rules += '.wikEdRefButton' + i + ':before, .wikEdRefButtonShow' + i + ':before { content: "' + wikEd.config.text.hideRef + ' ' + wikEd.referenceArray[i].text + '"; line-height: 0.75em; font-size: 65%; color: #000; font-family: sans-serif; }\n';  		wikEd.referenceArray[i].added = true; 	}  	// templates 	for (var i = 0; i < wikEd.templateArray.length; i ++) { 		if (wikEd.templateArray[i].added == true) { 			continue; 		} 		rules += '.wikEdTemplButton' + i + ' { border: 1px solid; border-color: #e8e8e8 #444 #444 #e8e8e8; background: #d8d4d0; }\n';  		rules += '.wikEdTemplButtonShow' + i + ' { border: 1px solid; border-color: #000 #e8e8e8 #e8e8e8 #000; background: #c8c4c0; }\n';  		rules += '.wikEdTemplButton' + i + ':before, .wikEdTemplButtonShow' + i + ':before { content: "' + wikEd.config.text.hideTempl + ' ' + wikEd.templateArray[i].text + '"; line-height: 0.75em; font-size: 65%; color: #000; font-family: sans-serif; }\n';  		wikEd.templateArray[i].added = true; 	}  	// character entities 	for (var i = 0; i < wikEd.charEntityArray.length; i ++) { 		if (wikEd.charEntityArray[i].added == true) { 			continue; 		} 		var character = wikEd.charEntityArray[i].text; 		if (character == '"') { 			character = '\\' + character; 		} 		rules += '.wikEdCharEntityButton' + i + ' { border: 1px solid; border-color: #e8e8e8 #444 #444 #e8e8e8; background: #d8d4d0; border-color: rgba(255, 255, 255, 0.75)  rgba(64, 64, 64, 0.5)  rgba(64, 64, 64, 0.5) rgba(255, 255, 255, 0.75); background: rgba(192, 192, 192, 0.3); }\n';  		rules += '.wikEdCharEntityButtonShow' + i + ' { border: 1px solid; border-color: #000 #e8e8e8 #e8e8e8 #000; background: #c8c4c0; border-color: rgba(64, 64, 64, 0.5) rgba(255, 255, 255, 0.75) rgba(255, 255, 255, 0.75) rgba(64, 64, 64, 0.5); background: rgba(192, 192, 192, 0.3); }\n';  		rules += '.wikEdCharEntityButton' + i + ':before, .wikEdCharEntityButtonShow' + i + ':before { content: "' + character + '"; }\n';  		wikEd.charEntityArray[i].added = true; 	}  	// add or replace existing css rules 	if (rules != ) { 		wikEd.HighlightNamedHideButtonsStylesheet.AddCSSRules(rules); 	} 	return; };   // // wikEd.HideAddHandlers: register mouseover handlers for tabs to unhide refs, templates, and character entities //  wikEd.HideAddHandlers = function {  	if ( (wikEd.config.hideContent != true) || (wikEd.refHide != true) ) { 		return; 	} 	var hideButton = wikEd.frameDocument.getElementsByTagName('button'); 	for (var i = 0; i < hideButton.length; i ++) { 		var tabClass = hideButton[i].className; 		if ( 			(tabClass.indexOf('wikEdRefButton') == 0) || 			(tabClass.indexOf('wikEdTemplButton') == 0) || 			(tabClass.indexOf('wikEdCharEntityButton') == 0) 		) { 			wikEd.AddEventListener(hideButton[i], 'click', wikEd.HideShowHandler, true); 			if ( 				(tabClass.indexOf('wikEdRefButtonShow') == -1) && 				(tabClass.indexOf('wikEdTemplButtonShow') == -1) && 				(tabClass.indexOf('wikEdCharEntityButtonShow') == -1) 			) { 				wikEd.AddEventListener(hideButton[i], 'mouseover', wikEd.HideShowHandler, true); 			} 		} 	} 	return; };   // // wikEd.HideShowHandler: display hidden ref or template on mouse over hide tab //  wikEd.HideShowHandler = function(event) {  	// event compatibility fixes 	event = wikEd.EventWrapper(event, this); 	if (event == null) { 		return; 	} 	event.preventDefault;  	// find hidden content node 	var hideTarget; 	var hideInto; 	var hideButtonClass; 	var hideClass; 	var hideButton; 	var hideContainer; 	var hide; 	if ( (event.type == 'mouseover') || (event.type == 'mouseout') || (event.type == 'click') ) { 		hideTarget = event.currentTarget; 		hideInto = event.safeRelatedTarget;  		//     text  		// target == button 		if (/^wikEd(Ref|Templ|CharEntity)Button(Show)?\d*$/.test(hideTarget.className) == true) { 			hideButton = hideTarget; 			hideContainer = hideButton.parentNode; 			if (hideContainer != null) { 				if (/^wikEd(Ref|Templ|CharEntity)Container$/.test(hideContainer.className) == false) { 					hideContainer = null; 				} 				else {  					// get hide text 					hide = wikEd.GetNextSiblingNode(hideContainer); 					if (hide != null) { 						if (/^wikEd(Ref|Templ|TemplNs|CharEntity)(Show)?$/.test(hide.className) == false) { 							hide = null; 						} 					} 				} 			} 		}  		// target == hide text 		else if (/^wikEd(Ref|Templ|TemplNs|CharEntity)(Show)?$/.test(hideTarget.className) == true) {  			hide = hideTarget; 			hideContainer = wikEd.GetPreviousSiblingNode(hideTarget); 			if (hideContainer != null) { 				if (/^wikEd(Ref|Templ|CharEntity)Container$/.test(hideContainer.className) == false) { 					hideContainer = null; 				} 				else {  					// get button 					hideButton = wikEd.GetFirstChildNode(hideContainer); 					if (hideButton != null) { 						if (/^wikEd(Ref|Templ|CharEntity)Button(Show)?\d*$/.test(hideButton.className) == false) { 							hideButton = null; 						} 					} 				} 			} 		}  		if ( (hideContainer == null) || (hideButton == null) || (hide == null) ) { 			return; 		}  		// get classes 		hideButtonClass = hideButton.className; 		hideClass = hide.className; 	}  	// schedule unhide on later shift or ctrl key push 	if (event.type == 'mouseover') { 		if (wikEd.config.unhideShift == true) { 			if ( (event.type == 'mouseover') && (wikEd.config.unhideShift == true) && (event.shiftKey == false) && (event.ctrlKey == false) ) { 				wikEd.scheduledUnhide = [hide, hideButton]; 				wikEd.AddEventListener(wikEd.frameDocument, 'keydown', wikEd.HideShowHandler, true); 				wikEd.AddEventListener(hideButton, 'mouseout', wikEd.HideShowHandler, true); 				return; 			} 		} 	}  	// scheduled unhide on shift or ctrl keydown 	if (event.type == 'keydown') { 		if ( (wikEd.scheduledUnhide != null) && ( (event.shiftKey == true) || (event.ctrlKey == true) ) ) { 			hide = wikEd.scheduledUnhide[0]; 			hideButton = wikEd.scheduledUnhide[1]; 			hideButtonClass = hideButton.className; 			hideClass = hide.className; 		} 	}  	// open on hover 	if ( (event.type == 'mouseover') || ( (event.type == 'keydown') && (wikEd.scheduledUnhide != null) ) ) { 		if (hideButtonClass.indexOf('wikEdRefButton') == 0) { 			hide.style.display = 'block'; 		} 		else if (hideButtonClass.indexOf('wikEdTemplButton') == 0) { 			hide.style.display = 'block'; 		} 		else if (hideButtonClass.indexOf('wikEdCharEntity') == 0) { 			hide.style.display = 'inline'; 		} 		wikEd.RemoveEventListener(hideButton, 'mouseover', wikEd.HideShowHandler, true); 		wikEd.AddEventListener(hide, 'mouseout', wikEd.HideShowHandler, true); 		wikEd.AddEventListener(hideButton, 'mouseout', wikEd.HideShowHandler, true); 	}  	// close after hover 	else if (event.type == 'mouseout') { 		if ( (hideInto != hideContainer) && (hideInto != hideButton) && (hideInto != hide) ) { 			if (/^wikEd(Ref|Templ|CharEntity)Button\d*$/.test(hideButton.className) == true) { 				var hideOut = false; 				var node = hideInto; 				while (node != null) { 					if (node == wikEd.frameBody) { 						hideOut = true; 						break; 					} 					if ( (node == hideContainer) || (node == hide) ) { 						break; 					} 					node = node.parentNode; 				} 				if (hideOut == true) { 					hide.style.display = 'none'; 					wikEd.RemoveEventListener(hide, 'mouseout', wikEd.HideShowHandler, true); 					wikEd.RemoveEventListener(hideButton, 'mouseout', wikEd.HideShowHandler, true); 					wikEd.AddEventListener(hideButton, 'mouseover', wikEd.HideShowHandler, true);  					// move cursor out of hidden text 					wikEd.UnhideCursor(hideContainer, hide); 				} 			} 		} 	}  	// hide on click 	else if (event.type == 'click') { 		if (/^wikEd(Ref|Templ|CharEntity)ButtonShow\d*$/.test(hideButtonClass) == true) { 			hide.style.display = 'none';  			hideButtonClass = hideButtonClass.replace(/Show/, ); 			hideClass = hideClass.replace(/Show/, );  			hideButton.className = hideButtonClass; 			hideButton.title = wikEd.config.text[hideButtonClass.replace(/\d+$/g, ) + 'Tooltip'];  			wikEd.AddEventListener(hideButton, 'mouseover', wikEd.HideShowHandler, true);  			// move cursor out of hidden text 			wikEd.UnhideCursor(hideContainer, hide); 		}  		// open on click 		else if (/^wikEd(Ref|Templ|CharEntity)Button\d*$/.test(hideButtonClass) == true) { 			if (hideButtonClass.indexOf('wikEdCharEntityButton') == 0) { 				hide.style.display = 'inline'; 			} 			else { 				hide.style.display = 'block'; 			} 			hideButtonClass = hideButtonClass.replace(/Button(Show)?/, 'ButtonShow'); 			hideClass += 'Show'; 			hideClass = hideClass.replace(/Show/, ) + 'Show';  			hideButton.className = hideButtonClass; 			hideButton.title = wikEd.config.text[hideButtonClass.replace(/\d+$/g, ) + 'Tooltip'];  			wikEd.RemoveEventListener(hideButton, 'mouseover', wikEd.HideShowHandler, true); 			wikEd.RemoveEventListener(hide, 'mouseout', wikEd.HideShowHandler, true); 			wikEd.RemoveEventListener(hideButton, 'mouseout', wikEd.HideShowHandler, true); 		} 	}  	// clear scheduled unhide 	if (wikEd.scheduledUnhide != null) { 		wikEd.RemoveEventListener(wikEd.frameDocument, 'keydown', wikEd.HideShowHandler, true); 		wikEd.scheduledUnhide = null; 	}  	return; };   // // wikEd.UnhideCursor: move cursor out of hidden element for wikEd.HideShowHandler //  wikEd.UnhideCursor = function(firstHiddenParent, lastHiddenParent) {  	// get selection and clone range 	var sel = wikEd.GetSelection; 	var range = sel.getRangeAt(sel.rangeCount - 1); 	if (range != null) {  		// check if selected text is hidden 		var startHidden = false; 		var node = range.startContainer; 		while (node != null) { 			if (node == wikEd.frameBody) { 				break; 			} 			if ( (node == lastHiddenParent) || (node == firstHiddenParent) ) { 				startHidden = true; 				break; 			} 			node = node.parentNode; 		} 		var endHidden = false; 		var node = range.endContainer; 		while (node != null) { 			if (node == wikEd.frameBody) { 				break; 			} 			if ( (node == lastHiddenParent) || (node == firstHiddenParent) ) { 				endHidden = true; 				break; 			} 			node = node.parentNode; 		}  		// unselect hidden text 		if ( (startHidden == false) && (endHidden == true) ) { 			range.setEndBefore(firstHiddenParent); 		} 		else if ( (startHidden == true) && (endHidden == false) ) { 			range.setStartAfter(lastHiddenParent); 		} 		else if ( (startHidden == true) && (endHidden == true) ) { 			range.setEndAfter(lastHiddenParent); 			range.collapse(false); 		} 	} 	return; };   // // wikEd.GetText: get the text fragments to manipulate //  wikEd.GetText = function(obj, whichFragment, wikify) {  	// remove dynamically inserted nodes by other scripts 	wikEd.CleanNodes(wikEd.frameDocument);  	// get selection object 	if (obj.sel == null) { 		obj.sel = wikEd.GetSelection; 	}  	// cursor for the cursor position (always done) 	if (obj.cursor == null) { 		obj.cursor = { 			'from': 'cursor', 			'keepSel': null, 			'plain':  		};  		// set cursor range 		obj.cursor.range = wikEd.frameDocument.createRange; 		wikEd.SetRangeStart(obj.cursor.range, obj.sel.focusNode, obj.sel.focusOffset); 		obj.cursor.range.collapse(true); 	}  	// whole for the whole text 	if (obj.whole == null) { 		if (/whole|selectionWord|selectionLine|selectionPara|focusWord|focusLine|focusPara/.test(whichFragment) == true) { 			obj.whole = { 				'plainArray': [], 				'plainNode': [], 				'plainStart': [], 				'from': 'whole', 				'keepSel': null 			};  			// set whole range 			obj.whole.range = wikEd.frameDocument.createRange; 			obj.whole.range.setStart(wikEd.frameBody, 0); 			obj.whole.range.setEnd(wikEd.frameBody, wikEd.frameBody.childNodes.length);  			// get whole plain text 			wikEd.GetInnerHTML(obj.whole, wikEd.frameBody); 			obj.whole.code = obj.whole.html; 			wikEd.RemoveHighlightingWikify(obj.whole, wikify); 			obj.whole.plain = obj.whole.html; 			obj.whole.plain = obj.whole.plain.replace(/[\n ]*<br\b[^>]*>[\n ]*/g, '\n'); 			obj.whole.plain = obj.whole.plain.replace(/\xa0/g, ' '); 		} 	}  	// selection for the selected text 	if (obj.selection == null) { 		if (/selection\b|selectionWord|selectionLine|selectionPara/.test(whichFragment) == true) { 			obj.selection = { 				'from': 'selection', 				'keepSel': null 			};  			// copy range to document fragment 			if (obj.sel.rangeCount == 0) { 				obj.sel.collapse(wikEd.frameBody, 0); 			} 			obj.selection.range = obj.sel.getRangeAt(obj.sel.rangeCount - 1); 			var documentFragment = obj.selection.range.cloneContents;  			// get selected text 			wikEd.GetInnerHTML(obj.selection, documentFragment); 			obj.selection.code = obj.selection.html; 			wikEd.RemoveHighlightingWikify(obj.selection, wikify); 			obj.selection.plain = obj.selection.html; 			obj.selection.plain = obj.selection.plain.replace(/[\n ]*<br\b[^>]*>[\n ]*/g, '\n'); 			obj.selection.plain = obj.selection.plain.replace(/\xa0/g, ' '); 		} 	}  	// focusWord, focusLine, and focusPara for the word, line, and paragraph under the cursor 	if (obj.focusWord == null) { 		if (/focusWord|focusLine|focusPara/.test(whichFragment) == true) { 			obj.focusWord = { 				'from': 'focusWord', 				'keepSel': false, 				'range': wikEd.frameDocument.createRange, 				'tableEdit': obj.tableEdit 			};  			// setup focusLine object for the line under the cursor 			obj.focusLine = { 				'from': 'focusLine', 				'keepSel': false, 				'range': wikEd.frameDocument.createRange, 				'tableEdit': obj.tableEdit 			};  			// setup focusPara object for the paragraph under the cursor 			obj.focusPara = { 				'from': 'focusPara', 				'keepSel': false, 				'range': wikEd.frameDocument.createRange, 				'tableEdit': obj.tableEdit 			};  			// find the word and line boundaries 			wikEd.FindBoundaries(obj.focusWord, obj.focusLine, obj.focusPara, obj.whole, obj.cursor);  			// get the wikified plain text for the word under the cursor 			var documentFragment = obj.focusWord.range.cloneContents; 			wikEd.GetInnerHTML(obj.focusWord, documentFragment); 			obj.focusWord.code = obj.focusWord.html; 			wikEd.RemoveHighlightingWikify(obj.focusWord, wikify); 			obj.focusWord.plain = obj.focusWord.html; 			obj.focusWord.plain = obj.focusWord.plain.replace(/[\n ]*<br\b[^>]*>[\n ]*/g, '\n'); 			obj.focusWord.plain = obj.focusWord.plain.replace(/\xa0/g, ' ');  			// get the wikified plain text for the line under the cursor 			var documentFragment = obj.focusLine.range.cloneContents; 			wikEd.GetInnerHTML(obj.focusLine, documentFragment); 			obj.focusLine.code = obj.focusLine.html; 			wikEd.RemoveHighlightingWikify(obj.focusLine, wikify); 			obj.focusLine.plain = obj.focusLine.html; 			obj.focusLine.plain = obj.focusLine.plain.replace(/[\n ]*<br\b[^>]*>[\n ]*/g, '\n'); 			obj.focusLine.plain = obj.focusLine.plain.replace(/\xa0/g, ' ');  			// get the wikified plain text for the paragraph under the cursor 			var documentFragment = obj.focusPara.range.cloneContents; 			wikEd.GetInnerHTML(obj.focusPara, documentFragment); 			obj.focusPara.code = obj.focusPara.html; 			wikEd.RemoveHighlightingWikify(obj.focusPara, wikify); 			obj.focusPara.plain = obj.focusPara.html; 			obj.focusPara.plain = obj.focusPara.plain.replace(/[\n ]*<br\b[^>]*>[\n ]*/g, '\n'); 			obj.focusPara.plain = obj.focusPara.plain.replace(/\xa0/g, ' '); 		} 	}  	// selectionWord and selectionLine for the complete words and lines under the selection 	if (obj.selectionWord == null) { 		if (/selectionWord|selectionLine|selectionPara/.test(whichFragment) == true) {  			// setup selectionWord object for the words under the selection 			obj.selectionWord = { 				'from': 'selectionWord', 				'keepSel': false, 				'range': wikEd.frameDocument.createRange, 				'tableEdit': obj.tableEdit 			};  			// setup selectionLine object for the lines under the selection 			obj.selectionLine = { 				'from': 'selectionLine', 				'keepSel': false, 				'range': wikEd.frameDocument.createRange, 				'tableEdit': obj.tableEdit 			};  			// setup focusPara object for the paragraph under the selection 			obj.selectionPara = { 				'from': 'selectionPara', 				'keepSel': false, 				'range': wikEd.frameDocument.createRange, 				'tableEdit': obj.tableEdit 			};  			// find the word and line boundaries 			wikEd.FindBoundaries(obj.selectionWord, obj.selectionLine, obj.selectionPara, obj.whole, obj.selection);  			// get the wikified plain text for the words under the selection 			var documentFragment = obj.selectionWord.range.cloneContents; 			wikEd.GetInnerHTML(obj.selectionWord, documentFragment); 			obj.selectionWord.code = obj.selectionWord.html; 			wikEd.RemoveHighlightingWikify(obj.selectionWord, wikify); 			obj.selectionWord.plain = obj.selectionWord.html; 			obj.selectionWord.plain = obj.selectionWord.plain.replace(/[\n ]*<br\b[^>]*>[\n ]*/g, '\n'); 			obj.selectionWord.plain = obj.selectionWord.plain.replace(/\xa0/g, ' ');  			// get the wikified plain text for the lines under the selection 			var documentFragment = obj.selectionLine.range.cloneContents; 			wikEd.GetInnerHTML(obj.selectionLine, documentFragment); 			obj.selectionLine.code = obj.selectionLine.html; 			wikEd.RemoveHighlightingWikify(obj.selectionLine, wikify); 			obj.selectionLine.plain = obj.selectionLine.html; 			obj.selectionLine.plain = obj.selectionLine.plain.replace(/[\n ]*<br\b[^>]*>[\n ]*/g, '\n'); 			obj.selectionLine.plain = obj.selectionLine.plain.replace(/\xa0/g, ' ');  			// get the wikified plain text for the paragraph under the selection 			var documentFragment = obj.selectionPara.range.cloneContents; 			wikEd.GetInnerHTML(obj.selectionPara, documentFragment); 			obj.selectionPara.code = obj.selectionPara.html; 			wikEd.RemoveHighlightingWikify(obj.selectionPara, wikify); 			obj.selectionPara.plain = obj.selectionPara.html; 			obj.selectionPara.plain = obj.selectionPara.plain.replace(/[\n ]*<br\b[^>]*>[\n ]*/g, '\n'); 			obj.selectionPara.plain = obj.selectionPara.plain.replace(/\xa0/g, ' '); 		} 	} 	return; };   // // wikEd.Find: custom find function with regexp properties, sets obj.changed.range, uses obj ranges //  wikEd.Find = function(obj, findText, caseSensitive, backwards, wrap, useRegExp) {  	var found = false;  	// get selection 	if (obj.sel == null) { 		obj.sel = wikEd.GetSelection; 	} 	if (obj.sel.rangeCount == 0) { 		obj.sel.collapse(wikEd.frameBody, 0); 	} 	var range = obj.sel.getRangeAt(obj.sel.rangeCount - 1);  	if (obj.changed == null) { 		obj.changed = {}; 	} 	obj.selectChanged = false;  	// empty the range to avoid error messages for reverse direction ranges 	obj.changed.range = wikEd.frameDocument.createRange;  	// regexp instead of plain text search for browser lacking .find (Opera), built in .find ignores newlines 	if (useRegExp != true) { 		if (typeof(wikEd.frameWindow.find) != 'function') { 			useRegExp = true; 			findText = findText.replace(/([\\^$*+?.\[\]{}:=!|,\-])/g, '\\$1'); 		} 	}  	// create the regexp 	var regExpFind; 	if (useRegExp == true) { 		var regExpFlags = 'gm'; 		if (caseSensitive != true) { 			regExpFlags += 'i'; 		} 		try { 			regExpFind = new RegExp(findText, regExpFlags); 		} 		catch (err) { 			return(false); 		} 	}  	// use the fast built-in find function for non-regexp searches; Opera does not have .find 	if (useRegExp != true) {  	// parameters: window.find(string, caseSensitive, backwards, wrapAround, wholeWord, searchInFrames, showDialog) 		found = wikEd.frameWindow.find(findText, caseSensitive, backwards, wrap, false, true, false); 		if (found == true) { 			range = obj.sel.getRangeAt(obj.sel.rangeCount - 1); 		} 		obj.changed.range = range; 	}  	// slow javascript regexp find and replace 	else {  		// perform find 		if (obj.plainArray === undefined) { 			wikEd.ParseDOM(obj, wikEd.frameBody); 		} 		var regExpMatch = [];  		// find next, search to the right 		if (backwards == false) {  			// set start position for search to right 			regExpFind.lastIndex = obj.plainFocus;  			// execute the regexp search to the right 			regExpMatch = regExpFind.exec(obj.plain);  			// remember position for repeated searches 			obj.plainFocus = regExpFind.lastIndex;  			// wrap around, start at beginning 			if ( (wrap == true) && (regExpMatch == null) ) { 				regExpFind.lastIndex = 0; 				regExpMatch = regExpFind.exec(obj.plain); 			} 		}  		// find previous, search to the left 		else {  			// cycle through the matches to the left 			var regExpMatchNext; 			do { 				regExpMatch = regExpMatchNext; 				regExpMatchNext = regExpFind.exec(obj.plain); 				if (regExpMatchNext == null) { 					break; 				} 			} while (regExpMatchNext.index < obj.plainAnchor);  			// wrap around, find last occurrence 			if ( (wrap == true) && (regExpMatch == null) ) { 				do { 					regExpMatch = regExpMatchNext; 					regExpMatchNext = regExpFind.exec(obj.plain); 				} while (regExpMatchNext != null); 			} 		}  		// select the find 		if (regExpMatch != null) { 			found = true;  			var i = 0; 			while ( (obj.plainStart[i + 1] <= regExpMatch.index) && (obj.plainStart[i + 1] != null) ) { 				i ++; 			}  			var j = i; 			while ( (obj.plainStart[j + 1] <= regExpMatch.index + regExpMatch[0].length) && (obj.plainStart[j + 1] != null) ) { 				j ++; 			}  			var startNode = obj.plainNode[i]; 			var startOffset = regExpMatch.index - obj.plainStart[i]; 			var endNode = obj.plainNode[j]; 			var endOffset = regExpMatch.index + regExpMatch[0].length - obj.plainStart[j]; 			wikEd.SetRange(obj.changed.range, startNode, startOffset, endNode, endOffset); 			obj.selectChanged = true; 		} 	} 	return(found); };   // // wikEd.ScrollToSelection: scroll iframe range into viewport //   for MSIE see http://www.webmasterworld.com/javascript/3820483.htm //   removig helper nodes gives Error: Node was not found = NS_ERROR_DOM_NOT_FOUND_ERR for certain undo actions //   adding nodes breaks the undo history in Chrome and Opera  wikEd.ScrollToSelection = function(frameScrollTop, frameScrollLeft, removeHelperNodes) {  	// get selection and clone range 	var obj = {}; 	obj.sel = wikEd.GetSelection; 	if (obj.sel.rangeCount == 0) { 		return; 	}  	// get selection plain text 	range = obj.sel.getRangeAt(obj.sel.rangeCount - 1); 	var documentFragment = range.cloneContents; 	wikEd.GetInnerHTML(obj, documentFragment); 	var plainText = obj.plain; 	plainText = plainText.replace(/&lt;/g, '<'); 	plainText = plainText.replace(/&gt;/g, '>'); 	plainText = plainText.replace(/&amp;/g, '&'); 	plainText = plainText.replace(/\xa0/g, ' ');  	// select using backwards built-in find 	if ( (typeof(wikEd.frameWindow.find) == 'function') && (plainText.length > 0) ) { 		obj.sel.collapseToEnd;  		// Chrome; parameters: wikEd.Find(obj, findText, caseSensitive, backwards, wrap, useRegExp) 		var found = wikEd.Find(obj, plainText, true, true, false, false);  		// Firefox (removes \n), 		if (found == false) { 			wikEd.Find(obj, range.toString, true, true, false, false); 		}  		// reinstate original range if it starts or ends with \n or spaces 		if (/^(\n| )|(\n| )$/.test(plainText) == true) { 			wikEd.RemoveAllRanges(obj.sel); 			obj.sel.addRange(range); 		} 	}  	// select empty range using backwards built-in find for previous character 	else if ( (typeof(wikEd.frameWindow.find) == 'function') && (plainText.length == 0) ) { 		var backwards = true;  		// get plain text from start to selection 		var rangeClone = range.cloneRange; 		rangeClone.setStartBefore(wikEd.frameBody.firstChild); 		var documentFragment = rangeClone.cloneContents; 		wikEd.GetInnerHTML(obj, documentFragment); 		var plainText = obj.plain; 		plainText = plainText.replace(/&lt;/g, '<'); 		plainText = plainText.replace(/&gt;/g, '>'); 		plainText = plainText.replace(/&amp;/g, '&'); 		plainText = plainText.replace(/^([\s\S]*?)([^\n]\n*)$/, '$2');  		// get plain text from selection to end for potentially less newlines 		if (plainText.length > 1) { 			var plainTextBack = plainText; 			var obj = {};  			var rangeClone = range.cloneRange; 			rangeClone.setEndAfter(wikEd.frameBody.lastChild); 			var documentFragment = rangeClone.cloneContents; 			wikEd.GetInnerHTML(obj, documentFragment); 			var plainText = obj.plain; 			plainText = plainText.replace(/&lt;/g, '<'); 			plainText = plainText.replace(/&gt;/g, '>'); 			plainText = plainText.replace(/&amp;/g, '&'); 			plainText = plainText.replace(/^(\n*[^\n])([\s\S]*?)$/, '$1');  			// backward or forward find 			if (plainTextBack.length > plainText.length) { 				backwards = false; 			} 			else { 				plainText = plainTextBack; 			} 		}  		// Chrome; parameters: wikEd.Find(obj, findText, caseSensitive, backwards, wrap, useRegExp) 		var found = wikEd.Find(obj, plainText, true, backwards, false, false);  		// Firefox 		if ( (found == false) && (/\n/.test(plainText) == true) ) { 			plainText = plainText.replace(/\n/g, ''); 			plainText = plainText.replace(/\xa0/g, ' '); 			wikEd.Find(obj, plainText, true, backwards, false, false); 		} 		if (backwards == true) { 			obj.sel.collapseToEnd; 		} 		else { 			obj.sel.collapseToStart; 		} 	}  	// use inserted spans as scroll marker, breaks undo history in Chrome and Opera 	else { 		var rangeStart = range.cloneRange; 		var rangeEnd = range.cloneRange;  		// spans to be temporarily inserted before and after selection range to get range position 		wikEd.insertCounter ++; 		var scrollStartNode = wikEd.frameDocument.createElement('span'); 		scrollStartNode.className = 'wikEdScrollBefore'; 		scrollStartNode.id = 'wikEdScrollBefore' + wikEd.insertCounter; 		var scrollEndNode = wikEd.frameDocument.createElement('span'); 		scrollEndNode.className = 'wikEdScrollAfter'; 		scrollEndNode.id = 'wikEdScrollAfter' + wikEd.insertCounter;  		// get the range border nodes and offsets 		var startNode = range.startContainer; 		var startOffset = range.startOffset; 		var endNode = range.endContainer; 		var endOffset = range.endOffset;  		var startLength; 		if (startNode.nodeName == '#text') { 			startLength = startNode.nodeValue.length; 		} 		var endLength; 		if (endNode.nodeName == '#text') { 			endLength = endNode.nodeValue.length; 		}  		// insert end node 		if (endNode.nodeName == '#text') { 			if (endOffset == 0) { 				endNode.parentNode.insertBefore(scrollEndNode, endNode); 			} 			else if (endOffset == endLength - 1) { 				endNode.parentNode.insertBefore(scrollEndNode, endNode.nextSibling); 			} 			else { 				rangeEnd.collapse(false); 				rangeEnd.insertNode(scrollEndNode); 			} 		} 		else { 			var refNode = endNode.childNodes.item(endOffset); 			endNode.insertBefore(scrollEndNode, refNode); 		}  		// insert start node 		if (startNode.nodeName == '#text') { 			if (startOffset == 0) { 				startNode.parentNode.insertBefore(scrollStartNode, startNode); 			} 			else if (startOffset == startLength - 1) { 				startNode.parentNode.insertBefore(scrollStartNode, startNode.nextSibling); 			} 			else {  				// collapse as a Firefox bug work around; http://stackoverflow.com/questions/665676 				rangeStart.collapse(true); 				rangeStart.insertNode(scrollStartNode); 			} 		} 		else { 			var refNode = startNode.childNodes.item(startOffset); 			startNode.insertBefore(scrollStartNode, refNode); 		}  		wikEd.ScrollToNodes(scrollStartNode, scrollEndNode);  		// set selection 		range.setStartBefore(scrollStartNode); 		range.setEndAfter(scrollEndNode); 		wikEd.RemoveAllRanges(sel); 		sel.addRange(range); 	}  	return; };   // // wikEd.ScrollToNodes: scroll iframe range into viewport //  wikEd.ScrollToNodes = function(scrollStartNode, scrollEndNode) {  	// absolute span for line height detection (Opera and Chrome do not vertically align empty span at bottom) 	var lineHeightNode = wikEd.frameDocument.createElement('span'); 	lineHeightNode.innerHTML = ' '; 	lineHeightNode.className = 'wikEdScrollLineHeight'; 	scrollEndNode.appendChild(lineHeightNode); 	lineHeight = lineHeightNode.clientHeight; 	lineHeightNode.innerHTML = ; 	scrollEndNode.removeChild(lineHeightNode);  	// scroll to node coordinates 	scrollStartNode.style.verticalAlign = 'top'; 	scrollEndNode.style.verticalAlign = 'top'; 	var startOffsetLeft = wikEd.GetOffsetLeft(scrollStartNode); 	var startOffsetTop  = wikEd.GetOffsetTop(scrollStartNode); 	var endOffsetRight  = wikEd.GetOffsetLeft(scrollEndNode); 	var endOffsetBottom = wikEd.GetOffsetTop(scrollEndNode); 	scrollStartNode.style.verticalAlign = 'baseline'; 	scrollEndNode.style.verticalAlign = 'baseline'; 	var frameScrollTop  = wikEd.frameBody.scrollTop; 	var frameScrollLeft = wikEd.frameBody.scrollLeft; 	var x = frameScrollLeft; 	var y = frameScrollTop;  	// current scroll position  	// selection above viewport 	if (endOffsetBottom < frameScrollTop) { 		y = startOffsetTop; 	}  	// selection below viewport 	else if (startOffsetTop > frameScrollTop + wikEd.frameBody.clientHeight) { 		y = endOffsetBottom - wikEd.frameBody.clientHeight + lineHeight; 	}  	// selection left of viewport 	if (endOffsetRight < frameScrollLeft) { 		if (endOffsetRight <= wikEd.frameBody.clientWidth) { 			x = 0; 		} 		else { 			x = startOffsetLeft; 		} 	}  	// selection right of viewport 	else if (startOffsetLeft > frameScrollLeft + wikEd.frameBody.clientWidth) { 		x = endOffsetRight - wikEd.frameBody.clientWidth; 	}  	// do scroll 	wikEd.frameWindow.scrollTo(x, y);  	return; };   // // wikEd.WikiTableToHtml: convert wiki tables to html //  //  wikEd.WikiTableToHtml = function(obj) {  	//// 	return; };   // // wikEd.Textify: strip html off of text //  wikEd.Textify = function(obj) {  	// convert html to plain 	obj.plain = obj.html; 	obj.plain = obj.plain.replace(/ \n|\n /g, ' '); 	obj.plain = obj.plain.replace(/\n/g, ' ');  	// delete content tags 	obj.plain = obj.plain.replace(/<(style|script|object|applet|embed)\b[^>]*>.*?<\/\1>/g, );  	// newlines 	obj.plain = obj.plain.replace(/[\n ]*<br\b[^>]*>[\n ]*/g, '\n');  	// ... to for Safari, Chrome, WebKit 	if ( (wikEd.safari == true) || (wikEd.chrome == true) || (wikEd.webkit == true) ) { 		var isRemove = []; 		obj.plain = obj.plain.replace(/(<(\/?)div\b([^>]*)>)/g, 			function (p, p1, p2, p3) { 				if (p2 == ) { 					if (p3 == ) { 						isRemove.push(true); 						return('\x00'); 					} 					isRemove.push(false); 					return(p1); 				} 				if (isRemove.pop == true) { 					return('\x01'); 				} 				return(p1); 			} 		); 		obj.plain = obj.plain.replace(/\x00\n\x01/g, '\x01'); 		obj.plain = obj.plain.replace(/\x01\n/g, '\x01'); 		obj.plain = obj.plain.replace(/\n\x00/g, '\x00'); 		obj.plain = obj.plain.replace(/\x01\x00/g, '\x01'); 		obj.plain = obj.plain.replace(/^\x00|\x01$/g, ); 		obj.plain = obj.plain.replace(/[\x00\x01]/g, '\n'); 	}  	// remove empty lines from block tags 	obj.plain = obj.plain.replace(/(<(blockquote|center|div|p|pre|gallery)\b[^>]*>)[\s\x00]+/gi, '$1'); 	obj.plain = obj.plain.replace(/[\s\x00]+(<\/(blockquote|center|div|p|pre|gallery|source|poem|categorytree|hiero|imagemap|inputbox|timeline|references)>)/gi, '$1');  	// remove highlighting pre tags 	var isRemove = []; 	obj.plain = obj.plain.replace(/(<(\/?)pre\b([^>]*)>)/g, 		function (p, p1, p2, p3) { 			if (p2 == ) { 				if (/\bclass="wikEd[\w\/]+"/.test(p3) == true) { 					isRemove.push(true); 					return(); 				} 				isRemove.push(false); 				return(p1); 			} 			if (isRemove.pop == true) { 				return(); 			} 			return(p1); 		} 	);  	// blocks 	obj.plain = obj.plain.replace(/<\/?(address|blockquote|center|div|hr|isindex|p|pre)\b.*?>/g, '\x00\x00');  	// keep headings only if starting with a newline 	obj.plain = obj.plain.replace(/[\s|\x00]*(^|\n|\x00)[\s|\x00]*<h[1-6]\b[^>]*>(.*?)<\/h[1-6]>[\s|\x00]*/g, '\x00\x00$2\x00\x00');  	// lists 	obj.plain = obj.plain.replace(/<\/?(dir|dl|menu|ol|ul)\b.*?>/g, '\x00'); 	obj.plain = obj.plain.replace(/<\/(dd|dt|li)>/g, '\x00');  	// forms 	obj.plain = obj.plain.replace(/<\/?(select|textarea)\b.*?>/g, '\x00'); 	obj.plain = obj.plain.replace(/<\/(option|legend|optgroup)>/g, '\x00');  	// tables 	if (wikEd.tableMode == true) {  		// override pasted table class //  		obj.plain = obj.plain.replace(/( '; 						} 						else { 							insertLeft = ' '; 							insertRight = '  '; 						} 						break; 				} 				break; 			case 'block': 				switch (tag) {  					// pushRight instead of insertRight if enclosed text can contain other highlighting, e.g. single character highlighting 					case 'linkNamespace': 						insertLeft = ' '; 						pushRight = ' '; 						break; 					case 'linkInter': 						insertLeft = ' '; 						pushRight = ' '; 						break; 					case 'inlineURL': 						var url = ; 						var regExpMatch; 						if ( (regExpMatch = /\w\S+/.exec(tagMatch)) != null) { 							url = regExpMatch[0]; 						} 						insertLeft = '<span class="wikEdURLName" ' + wikEd.HighlightLinkify(, , url) + '>'; 						pushRight = ' '; 						break; 					case 'externalURL': 						insertLeft = ' '; 						pushRight = ' '; 						break; 					case 'templateModifier': 						insertLeft = ' '; 						pushRight = ' '; 						break; 					case 'templateNamespace': 						insertLeft = ' '; 						pushRight = ' '; 						break; 					case 'templateParserFunct': 						insertLeft = ' '; 						pushRight = ' '; 						break; 					case 'PMID': 						var idNumber = ; 						var regExpMatch; 						if ( (regExpMatch = /\d+/.exec(tagMatch)) != null) { 							idNumber = regExpMatch[0]; 						} 						insertLeft = '<span class="wikEdPMID" ' + wikEd.HighlightLinkify(, , '//www.ncbi.nlm.nih.gov/pubmed/' + idNumber) + '>'; 						insertRight = ' '; 						break; 					case 'ISBN': 						var idNumber = ; 						var regExpMatch; 						if ( (regExpMatch = /\d[\s\d\-]+x?/.exec(tagMatch)) != null) { 							idNumber = regExpMatch[0].replace(/\D/g, ); 						} 						insertLeft = '<span class="wikEdISBN" ' + wikEd.HighlightLinkify(, 'Special:BookSources/' + idNumber) + '>'; 						pushRight = ' '; 						break; 					case 'RFC': 						var idNumber = ; 						var regExpMatch; 						if ( (regExpMatch = /\d[\s\d\-]+x?/.exec(tagMatch)) != null) { 							idNumber = regExpMatch[0].replace(/\D/g, ); 						} 						insertLeft = '<span class="wikEdISBN" ' + wikEd.HighlightLinkify(, , '//tools.ietf.org/html/rfc' + idNumber) + '>'; 						pushRight = ' '; 						break; 					case 'magic': 						insertLeft = ' '; 						insertRight = ' '; 						break; 					case 'signature': 						var title = wikEd.config.text['wikEdSignature' + tagLength]; 						insertLeft = '<span class="wikEdSignature" title="' + title + '">'; 						insertRight = ' '; 						break; 					case 'hr': 						pushLeft = ' '; 						pushRight = ' '; 						break; 					case 'linkParam': 						insertLeft = ' '; 						insertRight = ' '; 						break; 					case 'fileParam':  						// make text parameters a caption 						var params = ; 						if (pairedTagPos != null) { 							params = obj.html.substring(tagFrom + 1, parseObj.tree[node.parent].pairedTagPos - 1); 						} 						if (/^\s*(thumb|thumbnail|frame|right|left|center|none|\d+px|\d+x\d+px|link\=.*?|upright|border)\s*(\||$)/.test(params) == true) { 							insertLeft = ' '; 							insertRight = ' '; 						} 						else { 							insertLeft = ' '; 							insertRight = ' '; 						} 						break; 					case 'redirect': 						insertLeft = ' '; 						pushRight = ' '; 						break; 					case 'templateParam': 						insertLeft = ' '; 						pushRight = ' '; 						break; 					case 'parameterDefault': 						insertLeft = ' '; 						insertRight = ' '; 						break; 					case 'br'://inlineTag class 					case 'html': 					case 'htmlEmpty': 						insertLeft = '  '; 						pushRight = '  '; 						break; 					case 'htmlUnknown': 						insertLeft = '<span class="wikEdHtmlUnknown" title="' + wikEd.config.text.wikEdErrorHtmlUnknown + '">'; 						pushRight = ' '; 						break; 					case 'ref': 						var refName = ; 						var regExpMatch; 						if ( (regExpMatch = /(\bname\s*=\s*('|"))([^\x01]+?)\2/i.exec(tagMatch)) != null) { 							refName = regExpMatch[3]; 							wikEd.HighlightBuildTree('refName', 'block', tagFrom + regExpMatch.index + regExpMatch[1].length, regExpMatch[3].length, parseObj); 						} 						else if ( (regExpMatch = /(\bname\s*=\s*)(\w+)/i.exec(tagMatch)) != null) { 							refName = regExpMatch[2]; 							wikEd.HighlightBuildTree('refName', 'block', tagFrom + regExpMatch.index + regExpMatch[1].length, regExpMatch[2].length, parseObj); 						} 						if (wikEd.refHide == true) { 							if (refName != ) { 								insertLeft = ' <button class="wikEdRefButton' + wikEd.referenceArray.length + '" title="' + wikEd.config.text.wikEdRefButtonTooltip + '"> '; 								wikEd.referenceArray.push( {'text': refName + ' ↑', 'added': false} ); 							} 							else { 								insertLeft = ' <button class="wikEdRefButton" title="' + wikEd.config.text.wikEdRefButtonTooltip + '"> '; 							} 						} 						insertLeft += '  '; 						pushRight = '  '; 						break; 					case 'references': 						insertLeft = '  '; 						pushRight = '  '; 						break; 					case 'pre': 						insertLeft = ' '; 						pushRight = ' '; 						break; 					case 'math': 						insertLeft = ' '; 						pushRight = ' '; 						break; 					case 'nowiki': 						insertLeft = ' '; 						pushRight = ' '; 						break; 					case 'listTag': 						insertLeft = ' '; 						insertRight = ' '; 						break; 					case 'preformTag': 						insertLeft = ' '; 						insertRight = ' '; 						break; 					case 'refName': 						insertLeft = ' '; 						pushRight = ' '; 						break; 					case 'list': 						pushLeft = ' '; 						pushRight = ' '; 						break; 					case 'preform': 						pushLeft = ' '; 						pushRight = ' '; 						break; 					case 'caption': 					case 'row': 					case 'header': 					case 'headerParam': 					case 'headerSep': 					case 'cell': /* 						if (parseObj.tableMode == true) { 							var regExpTable = /\| *((\w+ *= *('|")[^\n'"]*\3 *)*)\|\|/gi; 							regExpTable.lastIndex = tagFrom; 							var regExpMatch; 							if ( (regExpMatch = regExpTable.exec(obj.html) ) != null) { 								if (regExpMatch.index == tagFrom) { 									var params = regExpMatch[1]; 									if (params != '') { 										params += ' '; 									} 									insertLeft = '     //      // <source lang="JavaScript">  /*  Name:    wDiff.js Version: 0.9.9 (October 10, 2010) Info:    http://en.wikipedia.org/wiki/User:Cacycle/diff Code:    http://en.wikipedia.org/wiki/User:Cacycle/diff.js  JavaScript diff algorithm by en:User:Cacycle (http://en.wikipedia.org/wiki/User_talk:Cacycle). Outputs html/css-formatted new text with highlighted deletions, inserts, and block moves. For newline highlighting the following style rules have to be added to the document: 	.wDiffParagraph:before { content: "¶"; }; The program uses cross-browser code and should work with all modern browsers. It has been tested with: * Mozilla Firefox 1.5.0.1 * Mozilla SeaMonkey 1.0 * Opera 8.53 * Internet Explorer 6.0.2900.2180 * Internet Explorer 7.0.5730.11 This program is also compatible with Greasemonkey An implementation of the word-based algorithm from:  Communications of the ACM 21(4):264 (1978) http://doi.acm.org/10.1145/359460.359467  With the following additional feature:  * Word types have been optimized for MediaWiki source texts * Additional post-pass 5 code for resolving islands caused by adding 	two common words at the end of sequences of common words * Additional detection of block borders and color coding of moved blocks and their original position * Optional "intelligent" omission of unchanged parts from the output  This code is used by the MediaWiki in-browser text editors en:User:Cacycle/editor and en:User:Cacycle/wikEd and the enhanced diff view tool wikEdDiff en:User:Cacycle/wikEd. Usage: var htmlText = WDiffString(oldText, newText); This code has been released into the public domain. Datastructures (abbreviations from publication): text: an object that holds all text related datastructures 	.newWords: consecutive words of the new text (N) 	.oldWords: consecutive words of the old text (O) 	.newToOld: array pointing to corresponding word number in old text (NA) 	.oldToNew: array pointing to corresponding word number in new text (OA) 	.message:  output message for testing purposes  symbol table: 	symbols[word]: associative array (object) of detected words for passes 1 - 3, points to symbol[i] 	symbol[i]: array of objects that hold word counters and pointers: 		.newCtr:  new word occurences counter (NC) 		.oldCtr:  old word occurences counter (OC) 		.toNew:   first word occurrence in new text, points to text.newWords[i] 		.toOld:   last word occurrence in old text, points to text.oldWords[i]  block: an object that holds block move information 	blocks indexed after new text: 	.newStart:  new text word number of start of this block 	.newLength: element number of this block including non-words 	.newWords:  true word number of this block 	.newNumber: corresponding block index in old text 	.newBlock:  moved-block-number of a block that has been moved here 	.newLeft:   moved-block-number of a block that has been moved from this border leftwards 	.newRight:  moved-block-number of a block that has been moved from this border rightwards 	.newLeftIndex:  index number of a block that has been moved from this border leftwards 	.newRightIndex: index number of a block that has been moved from this border rightwards 	blocks indexed after old text: 	.oldStart:  word number of start of this block 	.oldToNew:  corresponding new text word number of start 	.oldLength: element number of this block including non-words 	.oldWords:  true word number of this block  */   // css for change indicators if (typeof(wDiffStyleDelete) == 'undefined') { window.wDiffStyleDelete = 'font-weight: normal; text-decoration: none; color: #fff; background-color: #990033;'; } if (typeof(wDiffStyleInsert) == 'undefined') { window.wDiffStyleInsert = 'font-weight: normal; text-decoration: none; color: #fff; background-color: #009933;'; } if (typeof(wDiffStyleMoved)  == 'undefined') { window.wDiffStyleMoved  = 'font-weight: bold;  color: #000; vertical-align: text-bottom; font-size: xx-small; padding: 0; border: solid 1px;'; } if (typeof(wDiffStyleBlock)  == 'undefined') { window.wDiffStyleBlock  = [ 	'color: #000; background-color: #ffff80;', 	'color: #000; background-color: #c0ffff;', 	'color: #000; background-color: #ffd0f0;', 	'color: #000; background-color: #ffe080;', 	'color: #000; background-color: #aaddff;', 	'color: #000; background-color: #ddaaff;', 	'color: #000; background-color: #ffbbbb;', 	'color: #000; background-color: #d8ffa0;', 	'color: #000; background-color: #d0d0d0;' ]; }  // html for change indicators, {number} is replaced by the block number // {block} is replaced by the block style, class and html comments are important for shortening the output if (typeof(wDiffHtmlMovedRight)  == 'undefined') { window.wDiffHtmlMovedRight  = '<input class="wDiffHtmlMovedRight" type="button" value="&gt;" style="' + wDiffStyleMoved + ' {block}">'; } if (typeof(wDiffHtmlMovedLeft)   == 'undefined') { window.wDiffHtmlMovedLeft   = '<input class="wDiffHtmlMovedLeft" type="button" value="&lt;" style="' + wDiffStyleMoved + ' {block}">'; }  if (typeof(wDiffHtmlBlockStart)  == 'undefined') { window.wDiffHtmlBlockStart  = '<span class="wDiffHtmlBlock" style="{block}">'; } if (typeof(wDiffHtmlBlockEnd)    == 'undefined') { window.wDiffHtmlBlockEnd    = ' '; }  if (typeof(wDiffHtmlDeleteStart) == 'undefined') { window.wDiffHtmlDeleteStart = '<span class="wDiffHtmlDelete" style="' + wDiffStyleDelete + '">'; } if (typeof(wDiffHtmlDeleteEnd)   == 'undefined') { window.wDiffHtmlDeleteEnd   = ' '; }  if (typeof(wDiffHtmlInsertStart) == 'undefined') { window.wDiffHtmlInsertStart = '<span class="wDiffHtmlInsert" style="' + wDiffStyleInsert + '">'; } if (typeof(wDiffHtmlInsertEnd)   == 'undefined') { window.wDiffHtmlInsertEnd   = ' '; }  // minimal number of real words for a moved block (0 for always displaying block move indicators) if (typeof(wDiffBlockMinLength) == 'undefined') { window.wDiffBlockMinLength = 3; }  // exclude identical sequence starts and endings from change marking if (typeof(wDiffWordDiff) == 'undefined') { window.wDiffWordDiff = true; }  // enable recursive diff to resolve problematic sequences if (typeof(wDiffRecursiveDiff) == 'undefined') { window.wDiffRecursiveDiff = true; }  // enable block move display if (typeof(wDiffShowBlockMoves) == 'undefined') { window.wDiffShowBlockMoves = true; }  // remove unchanged parts from final output  // characters before diff tag to search for previous heading, paragraph, line break, cut characters if (typeof(wDiffHeadingBefore)   == 'undefined') { window.wDiffHeadingBefore   = 1500; } if (typeof(wDiffParagraphBefore) == 'undefined') { window.wDiffParagraphBefore = 1500; } if (typeof(wDiffLineBeforeMax)   == 'undefined') { window.wDiffLineBeforeMax   = 1000; } if (typeof(wDiffLineBeforeMin)   == 'undefined') { window.wDiffLineBeforeMin   =  500; } if (typeof(wDiffBlankBeforeMax)  == 'undefined') { window.wDiffBlankBeforeMax  = 1000; } if (typeof(wDiffBlankBeforeMin)  == 'undefined') { window.wDiffBlankBeforeMin  =  500; } if (typeof(wDiffCharsBefore)     == 'undefined') { window.wDiffCharsBefore     =  500; }  // characters after diff tag to search for next heading, paragraph, line break, or characters if (typeof(wDiffHeadingAfter)   == 'undefined') { window.wDiffHeadingAfter   = 1500; } if (typeof(wDiffParagraphAfter) == 'undefined') { window.wDiffParagraphAfter = 1500; } if (typeof(wDiffLineAfterMax)   == 'undefined') { window.wDiffLineAfterMax   = 1000; } if (typeof(wDiffLineAfterMin)   == 'undefined') { window.wDiffLineAfterMin   =  500; } if (typeof(wDiffBlankAfterMax)  == 'undefined') { window.wDiffBlankAfterMax  = 1000; } if (typeof(wDiffBlankAfterMin)  == 'undefined') { window.wDiffBlankAfterMin  =  500; } if (typeof(wDiffCharsAfter)     == 'undefined') { window.wDiffCharsAfter     =  500; }  // maximal fragment distance to join close fragments if (typeof(wDiffFragmentJoin)  == 'undefined') { window.wDiffFragmentJoin = 1000; } if (typeof(wDiffOmittedChars)  == 'undefined') { window.wDiffOmittedChars = '…'; } if (typeof(wDiffOmittedLines)  == 'undefined') { window.wDiffOmittedLines = '<hr style="height: 2px; margin: 1em 10%;">'; } if (typeof(wDiffNoChange)      == 'undefined') { window.wDiffNoChange     = '<hr style="height: 2px; margin: 1em 20%;">'; }  // compatibility fix for old name of main function window.StringDiff = window.WDiffString;   // WDiffString: main program // input: oldText, newText, strings containing the texts // returns: html diff  window.WDiffString = function(oldText, newText) {  // IE / Mac fix 	oldText = oldText.replace(/\r\n?/g, '\n'); 	newText = newText.replace(/\r\n?/g, '\n');  	var text = {}; 	text.newWords = []; 	text.oldWords = []; 	text.newToOld = []; 	text.oldToNew = []; 	text.message = ; 	var block = {}; 	var outText = ;  // trap trivial changes: no change 	if (oldText == newText) { 		outText = newText; 		outText = WDiffEscape(outText); 		outText = WDiffHtmlFormat(outText); 		return(outText); 	}  // trap trivial changes: old text deleted 	if ( (oldText == null) || (oldText.length == 0) ) { 		outText = newText; 		outText = WDiffEscape(outText); 		outText = WDiffHtmlFormat(outText); 		outText = wDiffHtmlInsertStart + outText + wDiffHtmlInsertEnd; 		return(outText); 	}  // trap trivial changes: new text deleted 	if ( (newText == null) || (newText.length == 0) ) { 		outText = oldText; 		outText = WDiffEscape(outText); 		outText = WDiffHtmlFormat(outText); 		outText = wDiffHtmlDeleteStart + outText + wDiffHtmlDeleteEnd; 		return(outText); 	}  // split new and old text into words 	WDiffSplitText(oldText, newText, text);  // calculate diff information 	WDiffText(text);  //detect block borders and moved blocks 	WDiffDetectBlocks(text, block);  // process diff data into formatted html text 	outText = WDiffToHtml(text, block);  // IE fix 	outText = outText.replace(/> ( *)</g, '> $1<');  	return(outText); };   // WDiffSplitText: split new and old text into words // input: oldText, newText, strings containing the texts // changes: text.newWords and text.oldWords, arrays containing the texts in arrays of words  window.WDiffSplitText = function(oldText, newText, text) {  // convert strange spaces 	oldText = oldText.replace(/[\t\u000b\u00a0\u2028\u2029]+/g, ' '); 	newText = newText.replace(/[\t\u000b\u00a0\u2028\u2029]+/g, ' ');  // split old text into words  //              /     |    |    |    |    |   |  |     |   |  |  |    |    |    | / 	var pattern = /[\w]+|\[\[|\]\]|\{\{|\}\}|\n+| +|&\w+;|'||=+|\{\||\|\}|\|\-|./g; 	var result; 	do { 		result = pattern.exec(oldText); 		if (result != null) { 			text.oldWords.push(result[0]); 		} 	} while (result != null);  // split new text into words 	do { 		result = pattern.exec(newText); 		if (result != null) { 			text.newWords.push(result[0]); 		} 	} while (result != null);  	return; };   // WDiffText: calculate diff information // input: text.newWords and text.oldWords, arrays containing the texts as arrays of words // optionally for recursive calls: newStart, newEnd, oldStart, oldEnd, recursionLevel // changes: text.newToOld and text.oldToNew, arrays pointing to corresponding words  window.WDiffText = function(text, newStart, newEnd, oldStart, oldEnd, recursionLevel) {  	var symbol = []; 	var symbols = {};  // set defaults 	if (typeof(newStart) == 'undefined') { newStart = 0; } 	if (typeof(newEnd) == 'undefined') { newEnd = text.newWords.length; } 	if (typeof(oldStart) == 'undefined') { oldStart = 0; } 	if (typeof(oldEnd) == 'undefined') { oldEnd = text.oldWords.length; } 	if (typeof(recursionLevel) == 'undefined') { recursionLevel = 0; }  // limit recursion depth 	if (recursionLevel > 10) { 		return; 	}  // // pass 1: Parse new text into symbol table // 	for (var i = newStart; i < newEnd; i ++) { 		var word = text.newWords[i];  // preserve the native method 		if (word.indexOf('hasOwnProperty') == 0) { 			word = word.replace(/^(hasOwnProperty_*)$/, '$1_'); 		}  // add new entry to symbol table 		if (symbols.hasOwnProperty(word) == false) { 			var last = symbol.length; 			symbols[word] = last; 			symbol[last] = { newCtr: 1, oldCtr: 0, toNew: i, toOld: null }; 		}  // or update existing entry 		else {  // increment word counter for new text 			var hashToArray = symbols[word]; 			symbol[hashToArray].newCtr ++; 		} 	}  // // pass 2: parse old text into symbol table // 	for (var i = oldStart; i < oldEnd; i ++) { 		var word = text.oldWords[i];  // preserve the native method 		if (word.indexOf('hasOwnProperty') == 0) { 			word = word.replace(/^(hasOwnProperty_*)$/, '$1_'); 		}  // add new entry to symbol table 		if (symbols.hasOwnProperty(word) == false) { 			var last = symbol.length; 			symbols[word] = last; 			symbol[last] = { newCtr: 0, oldCtr: 1, toNew: null, toOld: i }; 		}  // or update existing entry 		else {  // increment word counter for old text 			var hashToArray = symbols[word]; 			symbol[hashToArray].oldCtr ++;  // add word number for old text 			symbol[hashToArray].toOld = i; 		} 	}  // // pass 3: connect unique words // 	for (var i = 0; i < symbol.length; i ++) {  // find words in the symbol table that occur only once in both versions 		if ( (symbol[i].newCtr == 1) && (symbol[i].oldCtr == 1) ) { 			var toNew = symbol[i].toNew; 			var toOld = symbol[i].toOld;  // do not use spaces as unique markers 			if (/^\s+$/.test(text.newWords[toNew]) == false) {  // connect from new to old and from old to new 				text.newToOld[toNew] = toOld; 				text.oldToNew[toOld] = toNew; 			} 		} 	}  // // pass 4: connect adjacent identical words downwards // 	for (var i = newStart; i < newEnd - 1; i ++) {  // find already connected pairs 		if (text.newToOld[i] != null) { 			var j = text.newToOld[i];  // check if the following words are not yet connected 			if ( (text.newToOld[i + 1] == null) && (text.oldToNew[j + 1] == null) ) {  // connect if the following words are the same 				if (text.newWords[i + 1] == text.oldWords[j + 1]) { 					text.newToOld[i + 1] = j + 1; 					text.oldToNew[j + 1] = i + 1; 				} 			} 		} 	}  // // pass 5: connect adjacent identical words upwards // 	for (var i = newEnd - 1; i > newStart; i --) {  // find already connected pairs 		if (text.newToOld[i] != null) { 			var j = text.newToOld[i];  // check if the preceeding words are not yet connected 			if ( (text.newToOld[i - 1] == null) && (text.oldToNew[j - 1] == null) ) {  // connect if the preceeding words are the same 				if ( text.newWords[i - 1] == text.oldWords[j - 1] ) { 					text.newToOld[i - 1] = j - 1; 					text.oldToNew[j - 1] = i - 1; 				} 			} 		} 	}  // // "pass" 6: recursively diff still unresolved regions downwards // 	if (wDiffRecursiveDiff == true) { 		var i = newStart; 		var j = oldStart; 		while (i < newEnd) { 			if (text.newToOld[i - 1] != null) { 				j = text.newToOld[i - 1] + 1; 			}  // check for the start of an unresolved sequence 			if ( (text.newToOld[i] == null) && (text.oldToNew[j] == null) ) {  // determine the ends of the sequences 				var iStart = i; 				var iEnd = i; 				while ( (text.newToOld[iEnd] == null) && (iEnd < newEnd) ) { 					iEnd ++; 				} 				var iLength = iEnd - iStart;  				var jStart = j; 				var jEnd = j; 				while ( (text.oldToNew[jEnd] == null) && (jEnd < oldEnd) ) { 					jEnd ++; 				} 				var jLength = jEnd - jStart;  // recursively diff the unresolved sequence 				if ( (iLength > 0) && (jLength > 0) ) { 					if ( (iLength > 1) || (jLength > 1) ) { 						if ( (iStart != newStart) || (iEnd != newEnd) || (jStart != oldStart) || (jEnd != oldEnd) ) { 							WDiffText(text, iStart, iEnd, jStart, jEnd, recursionLevel + 1); 						} 					} 				} 				i = iEnd; 			} 			else { 				i ++; 			} 		} 	}  // // "pass" 7: recursively diff still unresolved regions upwards // 	if (wDiffRecursiveDiff == true) { 		var i = newEnd - 1; 		var j = oldEnd - 1; 		while (i >= newStart) { 			if (text.newToOld[i + 1] != null) { 				j = text.newToOld[i + 1] - 1; 			}  // check for the start of an unresolved sequence 			if ( (text.newToOld[i] == null) && (text.oldToNew[j] == null) ) {  // determine the ends of the sequences 				var iStart = i; 				var iEnd = i + 1; 				while ( (text.newToOld[iStart - 1] == null) && (iStart >= newStart) ) { 					iStart --; 				} 				if (iStart < 0) { 					iStart = 0; 				} 				var iLength = iEnd - iStart;  				var jStart = j; 				var jEnd = j + 1; 				while ( (text.oldToNew[jStart - 1] == null) && (jStart >= oldStart) ) { 					jStart --; 				} 				if (jStart < 0) { 					jStart = 0; 				} 				var jLength = jEnd - jStart;  // recursively diff the unresolved sequence 				if ( (iLength > 0) && (jLength > 0) ) { 					if ( (iLength > 1) || (jLength > 1) ) { 						if ( (iStart != newStart) || (iEnd != newEnd) || (jStart != oldStart) || (jEnd != oldEnd) ) { 							WDiffText(text, iStart, iEnd, jStart, jEnd, recursionLevel + 1); 						} 					} 				} 				i = iStart - 1; 			} 			else { 				i --; 			} 		} 	} 	return; };   // WDiffToHtml: process diff data into formatted html text // input: text.newWords and text.oldWords, arrays containing the texts in arrays of words //   text.newToOld and text.oldToNew, arrays pointing to corresponding words //   block data structure // returns: outText, a html string  window.WDiffToHtml = function(text, block) {  	var outText = text.message;  	var blockNumber = 0; 	var i = 0; 	var j = 0; 	var movedAsInsertion;  // cycle through the new text 	do { 		var movedIndex = []; 		var movedBlock = []; 		var movedLeft = []; 		var blockText = ; 		var identText = ; 		var delText = ; 		var insText = ; 		var identStart = ;  // check if a block ends here and finish previous block 		if (movedAsInsertion != null) { 			if (movedAsInsertion == false) { 				identStart += wDiffHtmlBlockEnd; 			} 			else { 				identStart += wDiffHtmlInsertEnd; 			} 			movedAsInsertion = null; 		}  // detect block boundary 		if ( (text.newToOld[i] != j) || (blockNumber == 0 ) ) { 			if ( ( (text.newToOld[i] != null) || (i >= text.newWords.length) ) && ( (text.oldToNew[j] != null) || (j >= text.oldWords.length) ) ) {  // block moved right 				var moved = block.newRight[blockNumber]; 				if (moved > 0) { 					var index = block.newRightIndex[blockNumber]; 					movedIndex.push(index); 					movedBlock.push(moved); 					movedLeft.push(false); 				}  // block moved left 				moved = block.newLeft[blockNumber]; 				if (moved > 0) { 					var index = block.newLeftIndex[blockNumber]; 					movedIndex.push(index); 					movedBlock.push(moved); 					movedLeft.push(true); 				}  // check if a block starts here 				moved = block.newBlock[blockNumber]; 				if (moved > 0) {  // mark block as inserted text 					if (block.newWords[blockNumber] < wDiffBlockMinLength) { 						identStart += wDiffHtmlInsertStart; 						movedAsInsertion = true; 					}  // mark block by color 					else { 						if (moved > wDiffStyleBlock.length) { 							moved = wDiffStyleBlock.length; 						} 						identStart += WDiffHtmlCustomize(wDiffHtmlBlockStart, moved - 1); 						movedAsInsertion = false; 					} 				}  				if (i >= text.newWords.length) { 					i ++; 				} 				else { 					j = text.newToOld[i]; 					blockNumber ++; 				} 			} 		}  // get the correct order if moved to the left as well as to the right from here 		if (movedIndex.length == 2) { 			if (movedIndex[0] > movedIndex[1]) { 				movedIndex.reverse; 				movedBlock.reverse; 				movedLeft.reverse; 			} 		}  // handle left and right block moves from this position 		for (var m = 0; m < movedIndex.length; m ++) {  // insert the block as deleted text 			if (block.newWords[ movedIndex[m] ] < wDiffBlockMinLength) { 				var movedStart = block.newStart[ movedIndex[m] ]; 				var movedLength = block.newLength[ movedIndex[m] ]; 				var str = ; 				for (var n = movedStart; n < movedStart + movedLength; n ++) { 					str += text.newWords[n]; 				} 				str = WDiffEscape(str); 				str = str.replace(/\n/g, '  '); 				blockText += wDiffHtmlDeleteStart + str + wDiffHtmlDeleteEnd; 			}  // add a placeholder / move direction indicator 			else { 				if (movedBlock[m] > wDiffStyleBlock.length) { 					movedBlock[m] = wDiffStyleBlock.length; 				} 				if (movedLeft[m]) { 					blockText += WDiffHtmlCustomize(wDiffHtmlMovedLeft, movedBlock[m] - 1); 				} 				else { 					blockText += WDiffHtmlCustomize(wDiffHtmlMovedRight, movedBlock[m] - 1); 				} 			} 		}  // collect consecutive identical text 		while ( (i < text.newWords.length) && (j < text.oldWords.length) ) { 			if ( (text.newToOld[i] == null) || (text.oldToNew[j] == null) ) { 				break; 			} 			if (text.newToOld[i] != j) { 				break; 			} 			identText += text.newWords[i]; 			i ++; 			j ++; 		}  // collect consecutive deletions 		while ( (text.oldToNew[j] == null) && (j < text.oldWords.length) ) { 			delText += text.oldWords[j]; 			j ++; 		}  // collect consecutive inserts 		while ( (text.newToOld[i] == null) && (i < text.newWords.length) ) { 			insText += text.newWords[i]; 			i ++; 		}  // remove leading and trailing similarities between delText and ins from highlighting 		var preText = ; 		var postText = ; 		if (wDiffWordDiff) { 			if ( (delText != ) && (insText != ) ) {  // remove leading similarities 				while ( delText.charAt(0) == insText.charAt(0) && (delText != ) && (insText != ) ) { 					preText = preText + delText.charAt(0); 					delText = delText.substr(1); 					insText = insText.substr(1); 				}  // remove trailing similarities 				while ( delText.charAt(delText.length - 1) == insText.charAt(insText.length - 1) && (delText != ) && (insText != ) ) { 					postText = delText.charAt(delText.length - 1) + postText; 					delText = delText.substr(0, delText.length - 1); 					insText = insText.substr(0, insText.length - 1); 				} 			} 		}  // output the identical text, deletions and inserts  // moved from here indicator 		if (blockText != ) { 			outText += blockText; 		}  // identical text 		if (identText != ) { 			outText += identStart + WDiffEscape(identText); 		} 		outText += preText;  // deleted text 		if (delText != ) { 			delText = wDiffHtmlDeleteStart + WDiffEscape(delText) + wDiffHtmlDeleteEnd; 			delText = delText.replace(/\n/g, '  '); 			outText += delText; 		}  // inserted text 		if (insText != ) { 			insText = wDiffHtmlInsertStart + WDiffEscape(insText) + wDiffHtmlInsertEnd; 			insText = insText.replace(/\n/g, '  '); 			outText += insText; 		} 		outText += postText; 	} while (i <= text.newWords.length);  	outText += '\n'; 	outText = WDiffHtmlFormat(outText);  	return(outText); };   // WDiffEscape: replaces html-sensitive characters in output text with character entities  window.WDiffEscape = function(text) {  	text = text.replace(/&/g, '&amp;'); 	text = text.replace(/</g, '&lt;'); 	text = text.replace(/>/g, '&gt;'); 	text = text.replace(/"/g, '&quot;');  	return(text); };   // HtmlCustomize: customize indicator html: replace {number} with the block number, {block} with the block style  window.WDiffHtmlCustomize = function(text, block) {  	text = text.replace(/\{number\}/, block); 	text = text.replace(/\{block\}/, wDiffStyleBlock[block]);  	return(text); };   // HtmlFormat: replaces newlines and multiple spaces in text with html code  window.WDiffHtmlFormat = function(text) {  	text = text.replace(/ {2}/g, '  '); 	text = text.replace(/\n/g, ' ');  	return(text); };   // WDiffDetectBlocks: detect block borders and moved blocks // input: text object, block object  window.WDiffDetectBlocks = function(text, block) {  	block.oldStart  = []; 	block.oldToNew  = []; 	block.oldLength = []; 	block.oldWords  = []; 	block.newStart  = []; 	block.newLength = []; 	block.newWords  = []; 	block.newNumber = []; 	block.newBlock  = []; 	block.newLeft   = []; 	block.newRight  = []; 	block.newLeftIndex  = []; 	block.newRightIndex = [];  	var blockNumber = 0; 	var wordCounter = 0; 	var realWordCounter = 0;  // get old text block order 	if (wDiffShowBlockMoves) { 		var j = 0; 		var i = 0; 		do {  // detect block boundaries on old text 			if ( (text.oldToNew[j] != i) || (blockNumber == 0 ) ) { 				if ( ( (text.oldToNew[j] != null) || (j >= text.oldWords.length) ) && ( (text.newToOld[i] != null) || (i >= text.newWords.length) ) ) { 					if (blockNumber > 0) { 						block.oldLength[blockNumber - 1] = wordCounter; 						block.oldWords[blockNumber - 1] = realWordCounter; 						wordCounter = 0; 						realWordCounter = 0; 					}  					if (j >= text.oldWords.length) { 						j ++; 					} 					else { 						i = text.oldToNew[j]; 						block.oldStart[blockNumber] = j; 						block.oldToNew[blockNumber] = text.oldToNew[j]; 						blockNumber ++; 					} 				} 			}  // jump over identical pairs 			while ( (i < text.newWords.length) && (j < text.oldWords.length) ) { 				if ( (text.newToOld[i] == null) || (text.oldToNew[j] == null) ) { 					break; 				} 				if (text.oldToNew[j] != i) { 					break; 				} 				i ++; 				j ++; 				wordCounter ++; 				if ( /\w/.test( text.newWords[i] ) ) { 					realWordCounter ++; 				} 			}  // jump over consecutive deletions 			while ( (text.oldToNew[j] == null) && (j < text.oldWords.length) ) { 				j ++; 			}  // jump over consecutive inserts 			while ( (text.newToOld[i] == null) && (i < text.newWords.length) ) { 				i ++; 			} 		} while (j <= text.oldWords.length);  // get the block order in the new text 		var lastMin; 		var currMinIndex; 		lastMin = null;  // sort the data by increasing start numbers into new text block info 		for (var i = 0; i < blockNumber; i ++) { 			currMin = null; 			for (var j = 0; j < blockNumber; j ++) { 				curr = block.oldToNew[j]; 				if ( (curr > lastMin) || (lastMin == null) ) { 					if ( (curr < currMin) || (currMin == null) ) { 						currMin = curr; 						currMinIndex = j; 					} 				} 			} 			block.newStart[i] = block.oldToNew[currMinIndex]; 			block.newLength[i] = block.oldLength[currMinIndex]; 			block.newWords[i] = block.oldWords[currMinIndex]; 			block.newNumber[i] = currMinIndex; 			lastMin = currMin; 		}  // detect not moved blocks 		for (var i = 0; i < blockNumber; i ++) { 			if (block.newBlock[i] == null) { 				if (block.newNumber[i] == i) { 					block.newBlock[i] = 0; 				} 			} 		}  // detect switches of neighbouring blocks 		for (var i = 0; i < blockNumber - 1; i ++) { 			if ( (block.newBlock[i] == null) && (block.newBlock[i + 1] == null) ) { 				if (block.newNumber[i] - block.newNumber[i + 1] == 1) { 					if ( (block.newNumber[i + 1] - block.newNumber[i + 2] != 1) || (i + 2 >= blockNumber) ) {  // the shorter one is declared the moved one 						if (block.newLength[i] < block.newLength[i + 1]) { 							block.newBlock[i] = 1; 							block.newBlock[i + 1] = 0; 						} 						else { 							block.newBlock[i] = 0; 							block.newBlock[i + 1] = 1; 						} 					} 				} 			} 		}  // mark all others as moved and number the moved blocks 		j = 1; 		for (var i = 0; i < blockNumber; i ++) { 			if ( (block.newBlock[i] == null) || (block.newBlock[i] == 1) ) { 				block.newBlock[i] = j++; 			} 		}  // check if a block has been moved from this block border 		for (var i = 0; i < blockNumber; i ++) { 			for (var j = 0; j < blockNumber; j ++) {  				if (block.newNumber[j] == i) { 					if (block.newBlock[j] > 0) {  // block moved right 						if (block.newNumber[j] < j) { 							block.newRight[i] = block.newBlock[j]; 							block.newRightIndex[i] = j; 						}  // block moved left 						else { 							block.newLeft[i + 1] = block.newBlock[j]; 							block.newLeftIndex[i + 1] = j; 						} 					} 				} 			} 		} 	} 	return; };   // WDiffShortenOutput: remove unchanged parts from final output // input: the output of WDiffString // returns: the text with removed unchanged passages indicated by (...)  window.WDiffShortenOutput = function(diffText) {  // html to newlines 	diffText = diffText.replace(/<br[^>]*>/g, '\n');  // scan for diff html tags 	var regExpDiff = /<\w+ class="(\w+)"[^>]*>(.|\n)*?/g; 	var tagStart = []; 	var tagEnd = []; 	var i = 0; 	var found; 	while ( (found = regExpDiff.exec(diffText)) != null ) {  // combine consecutive diff tags 		if ( (i > 0) && (tagEnd[i - 1] == found.index) ) { 			tagEnd[i - 1] = found.index + found[0].length; 		} 		else { 			tagStart[i] = found.index; 			tagEnd[i] = found.index + found[0].length; 			i ++; 		} 	}  // no diff tags detected 	if (tagStart.length == 0) { 		return(wDiffNoChange); 	}  // define regexps 	var regExpHeading = /\n=+.+?=+ *\n|\n\{\||\n\|\}/g; 	var regExpParagraph = /\n\n+/g; 	var regExpLine = /\n+/g; 	var regExpBlank = /(<[^>]+>)*\s+/g;  // determine fragment border positions around diff tags 	var rangeStart = []; 	var rangeEnd = []; 	var rangeStartType = []; 	var rangeEndType = []; 	for (var i = 0; i < tagStart.length; i ++) { 		var found;  // find last heading before diff tag 		var lastPos = tagStart[i] - wDiffHeadingBefore; 		if (lastPos < 0) { 			lastPos = 0; 		} 		regExpHeading.lastIndex = lastPos; 		while ( (found = regExpHeading.exec(diffText)) != null ) { 			if (found.index > tagStart[i]) { 				break; 			} 			rangeStart[i] = found.index; 			rangeStartType[i] = 'heading'; 		}  // find last paragraph before diff tag 		if (rangeStart[i] == null) { 			lastPos = tagStart[i] - wDiffParagraphBefore; 			if (lastPos < 0) { 				lastPos = 0; 			} 			regExpParagraph.lastIndex = lastPos; 			while ( (found = regExpParagraph.exec(diffText)) != null ) { 				if (found.index > tagStart[i]) { 					break; 				} 				rangeStart[i] = found.index; 				rangeStartType[i] = 'paragraph'; 			} 		}  // find line break before diff tag 		if (rangeStart[i] == null) { 			lastPos = tagStart[i] - wDiffLineBeforeMax; 			if (lastPos < 0) { 				lastPos = 0; 			} 			regExpLine.lastIndex = lastPos; 			while ( (found = regExpLine.exec(diffText)) != null ) { 				if (found.index > tagStart[i] - wDiffLineBeforeMin) { 					break; 				} 				rangeStart[i] = found.index; 				rangeStartType[i] = 'line'; 			} 		}  // find blank before diff tag 		if (rangeStart[i] == null) { 			lastPos = tagStart[i] - wDiffBlankBeforeMax; 			if (lastPos < 0) { 				lastPos = 0; 			} 			regExpBlank.lastIndex = lastPos; 			while ( (found = regExpBlank.exec(diffText)) != null ) { 				if (found.index > tagStart[i] - wDiffBlankBeforeMin) { 					break; 				} 				rangeStart[i] = found.index; 				rangeStartType[i] = 'blank'; 			} 		}  // fixed number of chars before diff tag 		if (rangeStart[i] == null) { 			rangeStart[i] = tagStart[i] - wDiffCharsBefore; 			rangeStartType[i] = 'chars'; 			if (rangeStart[i] < 0) { 				rangeStart[i] = 0; 			} 		}  // find first heading after diff tag 		regExpHeading.lastIndex = tagEnd[i]; 		if ( (found = regExpHeading.exec(diffText)) != null ) { 			if (found.index < tagEnd[i] + wDiffHeadingAfter) { 				rangeEnd[i] = found.index + found[0].length; 				rangeEndType[i] = 'heading'; 			} 		}  // find first paragraph after diff tag 		if (rangeEnd[i] == null) { 			regExpParagraph.lastIndex = tagEnd[i]; 			if ( (found = regExpParagraph.exec(diffText)) != null ) { 				if (found.index < tagEnd[i] + wDiffParagraphAfter) { 					rangeEnd[i] = found.index; 					rangeEndType[i] = 'paragraph'; 				} 			} 		}  // find first line break after diff tag 		if (rangeEnd[i] == null) { 			regExpLine.lastIndex = tagEnd[i] + wDiffLineAfterMin; 			if ( (found = regExpLine.exec(diffText)) != null ) { 				if (found.index < tagEnd[i] + wDiffLineAfterMax) { 					rangeEnd[i] = found.index; 					rangeEndType[i] = 'break'; 				} 			} 		}  // find blank after diff tag 		if (rangeEnd[i] == null) { 			regExpBlank.lastIndex = tagEnd[i] + wDiffBlankAfterMin; 			if ( (found = regExpBlank.exec(diffText)) != null ) { 				if (found.index < tagEnd[i] + wDiffBlankAfterMax) { 					rangeEnd[i] = found.index; 					rangeEndType[i] = 'blank'; 				} 			} 		}  // fixed number of chars after diff tag 		if (rangeEnd[i] == null) { 			rangeEnd[i] = tagEnd[i] + wDiffCharsAfter; 			if (rangeEnd[i] > diffText.length) { 				rangeEnd[i] = diffText.length; 				rangeEndType[i] = 'chars'; 			} 		} 	}  // remove overlaps, join close fragments 	var fragmentStart = []; 	var fragmentEnd = []; 	var fragmentStartType = []; 	var fragmentEndType = []; 	fragmentStart[0] = rangeStart[0]; 	fragmentEnd[0] = rangeEnd[0]; 	fragmentStartType[0] = rangeStartType[0]; 	fragmentEndType[0] = rangeEndType[0]; 	var j = 1; 	for (var i = 1; i < rangeStart.length; i ++) { 		if (rangeStart[i] > fragmentEnd[j - 1] + wDiffFragmentJoin) { 			fragmentStart[j] = rangeStart[i]; 			fragmentEnd[j] = rangeEnd[i]; 			fragmentStartType[j] = rangeStartType[i]; 			fragmentEndType[j] = rangeEndType[i]; 			j ++; 		} 		else { 			fragmentEnd[j - 1] = rangeEnd[i]; 			fragmentEndType[j - 1] = rangeEndType[i]; 		} 	}  // assemble the fragments 	var outText = ; 	for (var i = 0; i < fragmentStart.length; i ++) {  // get text fragment 		var fragment = diffText.substring(fragmentStart[i], fragmentEnd[i]); 		var fragment = fragment.replace(/^\n+|\n+$/g, );  // add inline marks for omitted chars and words 		if (fragmentStart[i] > 0) { 			if (fragmentStartType[i] == 'chars') { 				fragment = wDiffOmittedChars + fragment; 			} 			else if (fragmentStartType[i] == 'blank') { 				fragment = wDiffOmittedChars + ' ' + fragment; 			} 		} 		if (fragmentEnd[i] < diffText.length) { 			if (fragmentStartType[i] == 'chars') { 				fragment = fragment + wDiffOmittedChars; 			} 			else if (fragmentStartType[i] == 'blank') { 				fragment = fragment + ' ' + wDiffOmittedChars; 			} 		}  // add omitted line separator 		if (fragmentStart[i] > 0) { 			outText += wDiffOmittedLines; 		}  // encapsulate span errors 		outText += ' ' + fragment + ' '; 	}  // add trailing omitted line separator 	if (fragmentEnd[i - 1] < diffText.length) { 		outText = outText + wDiffOmittedLines; 	}  // remove leading and trailing empty lines 	outText = outText.replace(/^\n+|\n+(<\/div>)$/g, '$1$2');  // convert to html linebreaks 	outText = outText.replace(/\n/g, ' '); 	return(outText); };