Jump to content

User:Zocky/wikEdDev.js

From Wikipedia, the free encyclopedia
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
/* <pre><nowiki> */


/*

[[User:Zocky|Zocky]]'s hacks of [[User:Cacycle/wikEd]].
Hacks released under GPL.


*/

var programHomepage = 'http://en.wikipedia.org/wiki/User:Cacycle/wikEd';
var programVersion  = 'alpha';
var programDate     = 'September 12, 2006';

//
// configuration variables
//


// CSS rules edit frame
var frameCSS = frameCSS || [];

frameCSS['body']              = frameCSS['body']             || 'background: #fff; margin: 0px; padding: 0.2em; overflow: -moz-scrollbars-vertical; overflow-x: auto;font-size:13px;padding:8px';

frameCSS['.wikEdLine']       = 
frameCSS['.wikEdLine']       || 'color: #333;';
frameCSS['.wikEdBlock']      = 
frameCSS['.wikEdBlock']      || '';
frameCSS['.wikEdInline']      = 
frameCSS['.wikEdInline']     || 'background: #ddd; color: #484; font-family: monospace; font-weight:bold';
frameCSS['.wikEdUnknown']     = 
frameCSS['.wikEdUnknown']    || 'background: red; color: white; font-weight: bold;';
frameCSS['.wikEdSub']         = 
frameCSS['.wikEdSub']        || 'position: relative; top: 0.3em; font-size:90%';
frameCSS['.wikEdSup']         = 
frameCSS['.wikEdSup']        || 'position: relative; top: -0.3em;font-size:90%';
frameCSS['.wikEdBold']        = 
frameCSS['.wikEdBold']       || 'color:#000; font-weight: bold;';
frameCSS['.wikEdComment']     = 
frameCSS['.wikEdComment']    || 'background-color: #ffff80;';
frameCSS['.wikEdDel']         = 
frameCSS['.wikEdDel']        || 'text-decoration: line-through;';
frameCSS['.wikEdIns']         = 
frameCSS['.wikEdIns']        || 'text-decoration: underline;';
frameCSS['.wikEdItalic']      = 
frameCSS['.wikEdItalic']     || 'font-style: italic;';
frameCSS['.wikEdRGB']         = 
frameCSS['.wikEdRGB']        || '';

// horizontal rule
frameCSS['.wikEdHR']          = 
frameCSS['.wikEdHR']         || 'background-color: #d0d0d0;';
frameCSS['.wikEdHRInline']    = 
frameCSS['.wikEdHRInline']   || 'color: #999; font-family: monospace;';

// wiki code
frameCSS['.wikEdWiki']        = 
frameCSS['.wikEdWiki']       || 'color: #999; font-family: monospace;';
frameCSS['.wikEdWikiRedir']   = 
frameCSS['.wikEdWikiRedir']  || 'color: #999; font-family: monospace;';

// headings
frameCSS['.wikEdHeading']     = 
frameCSS['.wikEdHeading']    || 'font-weight:bold;font-size:120%;padding:8px 0;';
frameCSS['.wikEdHeadingWp']   = 
frameCSS['.wikEdHeadingWp']  || 'font-weight:bold;font-size:120%;padding:8px 0;';

// tables
frameCSS['.wikEdTableBlock']  = 
frameCSS['.wikEdTableBlock'] || 'background-color: #f0f0f0;';
frameCSS['.wikEdTableLine']   = 
frameCSS['.wikEdTableLine']  || 'background-color: #f0f0f0;';
frameCSS['.wikEdTableTag']    = 
frameCSS['.wikEdTableTag']   || 'background-color: #f0f0f0; color: #0000e0; font-weight: bold;';

// list
frameCSS['.wikEdListBlock']   = 
frameCSS['.wikEdListBlock']  || 'padding:4px 0;';
frameCSS['.wikEdListLine']    = 
frameCSS['.wikEdListLine']   || '';
frameCSS['.wikEdListTag']     = 
frameCSS['.wikEdListTag']    || 'color: teal; font-family: monospace;font-weight:bold;';

// space-pre
frameCSS['.wikEdSpaceBlock']  = 
frameCSS['.wikEdSpaceBlock'] || 'background-color: #f0f0f0;';
frameCSS['.wikEdSpaceLine']   = 
frameCSS['.wikEdSpaceLine']  || 'background-color: #f0f0f0;';
frameCSS['.wikEdSpaceTag']    = 
frameCSS['.wikEdSpaceTag']   || 'color: #0000e0; font-weight: bold;';

// wiki links, images, categories, templates
frameCSS['.wikEdLinkTag']     = 
frameCSS['.wikEdLinkTag']    || 'color: #999; font-family: monospace;';

frameCSS['.wikEdLink']        = 
frameCSS['.wikEdLink']       || '';
frameCSS['.wikEdImage']       = 
frameCSS['.wikEdImage']      || 'background:#ff8;';
frameCSS['.wikEdCat']         = 
frameCSS['.wikEdCat']        || 'background:#ff8';
frameCSS['.wikEdTempl']       = 
frameCSS['.wikEdTempl']      || 'background:#ff8;';

// interlanguage
frameCSS['.wikEdInter']       = 
frameCSS['.wikEdInter']      || 'color: #999; font-family: monospace;';
frameCSS['.wikEdLinkInter']   = 
frameCSS['.wikEdLinkInter']  || '';
frameCSS['.wikEdImageInter']  = 
frameCSS['.wikEdImageInter'] || 'background:#ff8';
frameCSS['.wikEdCatInter']    = 
frameCSS['.wikEdCatInter']   || 'background:#ff8';
frameCSS['.wikEdTemplInter']  = 
frameCSS['.wikEdTemplInter'] || '';

// name
frameCSS['.wikEdLinkName']    = 
frameCSS['.wikEdLinkName']   || 'color: #999; font-family: monospace;';
frameCSS['.wikEdImageName']   = 
frameCSS['.wikEdImageName']  || 'color: #999; font-family: monospace;';
frameCSS['.wikEdCatName']     = 
frameCSS['.wikEdCatName']    || 'color: #999; font-family: monospace;';
frameCSS['.wikEdTemplName']   = 
frameCSS['.wikEdTemplName']  || 'color: #999; font-family: monospace;';
frameCSS['.wikEdURLLink']     = 
frameCSS['.wikEdURLLink']    || 'color: #f00000; font-weight: bold;';

// text and parameters
frameCSS['.wikEdLinkText']    = 
frameCSS['.wikEdLinkText']   || 'color:#00d;text-decoration:underline';
frameCSS['.wikEdLinkLiteral']    = 
frameCSS['.wikEdLinkLiteral']|| 'color:#00d;text-decoration:underline';
frameCSS['.wikEdImageText']   = 
frameCSS['.wikEdImageText']  || 'color: #999; font-family: monospace;';
frameCSS['.wikEdCatText']     = 
frameCSS['.wikEdCatText']    || 'color: #999; font-family: monospace;';
frameCSS['.wikEdTemplText']   = 
frameCSS['.wikEdTemplText']  || 'color: #999; font-family: monospace;';
frameCSS['.wikEdURLText']     = 
frameCSS['.wikEdURLText']    || 'font-weight: bold;';

// insert wikicode here
frameCSS['.wikEdInsertHere']  = 
frameCSS['.wikEdInsertHere'] || 'background-color: orange; font-style: italic;';

// invisibles
frameCSS['.wikEdTab']         = 
frameCSS['.wikEdTab']        || 'outline: silver dotted thin; display: inline;';
frameCSS['.wikEdBlank']       = 
frameCSS['.wikEdBlank']      || 'background-color: #ff0000; outline: black dotted thin; display: inline;';

// CSS rules main window
var mainCSS = mainCSS || [];
mainCSS['.wikEdCombo']           = 
mainCSS['.wikEdCombo']          || 'font-size: smaller; padding-left: 0.1em; padding-right: 0.1em; margin-left: 0.1em; margin-right: 0.1em; height: 1.6em; vertical-align: bottom;';
mainCSS['.wikEdPreviewBox']      = 
mainCSS['.wikEdPreviewBox']     || 'background-color: #f9f9f9;';

mainCSS['.wikEdButtonsFormat']   = 
mainCSS['.wikEdButtonsFormat']  || 'background: #d4d0cc; border: 1px black solid; padding: 0.1em; margin: 0.2em 0.6em 0 0    ; float: left;';
mainCSS['.wikEdButtonsFind']     = 
mainCSS['.wikEdButtonsFind']    || 'background: #d4d0cc; border: 1px black solid; padding: 0.1em; margin: 0.2em 0.6em 0 0    ; float: left;';
mainCSS['.wikEdButtonsFix']      = 
mainCSS['.wikEdButtonsFix']     || 'background: #d4d0cc; border: 1px black solid; padding: 0.1em; margin: 0.2em 0.6em 0 0    ; float: left';
mainCSS['.wikEdButtonsWindow']   = 
mainCSS['.wikEdButtonsWindow']  || 'background: #d4d0cc; border: 1px black solid; padding: 0.1em; margin: 0.2em 0     0 0    ; float: right;';
mainCSS['.wikEdButtonsPreview']  = 
mainCSS['.wikEdButtonsPreview'] || 'background: #d4d0cc; border: 1px black solid; padding: 0.1em; margin: 0.2em 0     0 0.6em; float: right;';

mainCSS['.wikEdButton']          = 
mainCSS['.wikEdButton']         || 'vertical-align: text-top; font-size: small; text-decoration: underline; margin: 1px 2px; padding: 0; background: #d4d0cc; border: 1px #d4d0cc solid; cursor: pointer;';
mainCSS['.wikEdButton:hover']    = 
mainCSS['.wikEdButton:hover']   || 'background: #e4e0dd; border: 1px outset; cursor: pointer;';
mainCSS['.wikEdButton:active']   = 
mainCSS['.wikEdButton:active']  || 'background: #e4e0dc; border: 1px inset;  cursor: pointer;';
mainCSS['.wikEdButtonFloat']     = 
mainCSS['.wikEdButtonFloat']    || 'background: #d4d0cc; border: 1px outset; cursor: pointer; display: none; position: absolute; z-index: 5;';
mainCSS['.wikEdButtonChecked']   = 
mainCSS['.wikEdButtonChecked']  || 'vertical-align: text-top; font-size: small; text-decoration: underline; margin: 1px 2px; padding: 0; background: #f8f8f8; border: 1px inset;  cursor: pointer;';
mainCSS['.wikEdButtonUnchecked'] = 
mainCSS['.wikEdButtonUnchecked']|| 'vertical-align: text-top; font-size: small; text-decoration: underline; margin: 1px 2px; padding: 0; background: #e4e0dd; border: 1px outset; cursor: pointer;';

// levels of undo (each level holds the whole text)
var undoBufferMax = undoBufferMax || 20;

// history length for summary, find and replace fields
var findHistoryLength = findHistoryLength || 10;

// presets for input field dropdown options, {using} appends a link to this script
var presetOptions = presetOptions || [];
presetOptions['summary'] = presetOptions['summary'] || [
	'article created',
	'intro rewrite',
	'copyedit',
	'linkfix',
	'fixing typos',
	'reverting test',
	'reverting vandalism',
	'formatting source text',
	'({using})'
];

// text for summary link to this script
var summaryUsing = summaryUsing || 'using [[User:Cacycle/wikEd|wikEd]]';

// expiration time span for history cookies in seconds
var cookieExpireSec = cookieExpireSec || (365 * 24 * 60 * 60);

// enable cursor horizontal position memory
var cursorMemory = cursorMemory || true;

// show at least this number of lines ahead of cursor movement
var scrollMargin = scrollMargin || 1;

// show at least this number of lines ahead of cursor movement for
var findMargin = findMargin || 2;

// find ahead checkbox selected by default
var findAheadSelected = findAheadSelected || true;

// highlight syntax
var highlightSyntax = highlightSyntax || true;

// enable wikEd
var useWikEd = useWikEd || true;

// image source (button images)
var imagesPath = imagesPath || '/media/wikipedia/commons/';
var image = image || [];
image['align_buttons']      = image['align_buttons']      || imagesPath + '0/01/WikEd_align_buttons.png';
image['align_top']          = image['align_top']          || imagesPath + '1/13/WikEd_align_top.png';
image['bold']               = image['bold']               || imagesPath + '5/59/WikEd_bold.png';
image['bullet_list']        = image['bullet_list']        || imagesPath + '6/62/WikEd_bullet_list.png';
image['case']               = image['case']               || imagesPath + 'a/aa/WikEd_case.png';
image['case_sensitive']     = image['case_sensitive']     || imagesPath + '0/0d/WikEd_case_sensitive.png';
image['classic']            = image['classic']            || imagesPath + '9/9e/WikEd_classic.png';
image['clear_find']         = image['clear_find']         || imagesPath + 'f/f0/WikEd_clear_find.png';
image['clear_history']      = image['clear_history']      || imagesPath + 'c/c8/WikEd_clear_history.png';
image['close']              = image['close']              || imagesPath + '9/97/WikEd_close.png';
image['decrease_heading']   = image['decrease_heading']   || imagesPath + '7/72/WikEd_decrease_heading.png';
image['definition_list']    = image['definition_list']    || imagesPath + 'f/f5/WikEd_definition_list.png';
image['diff']               = image['diff']               || imagesPath + 'd/db/WikEd_diff.png';
image['error']              = image['error']              || imagesPath + '3/3e/WikEd_error.png';
image['find_ahead']         = image['find_ahead']         || imagesPath + '3/34/WikEd_find_ahead.png';
image['find_all']           = image['find_all']           || imagesPath + '7/75/WikEd_find_all.png';
image['find_next']          = image['find_next']          || imagesPath + 'a/ad/WikEd_find_next.png';
image['find_prev']          = image['find_prev']          || imagesPath + 'f/f5/WikEd_find_prev.png';
image['fix_all']            = image['fix_all']            || imagesPath + '8/86/WikEd_fix_all.png';
image['fix_basic']          = image['fix_basic']          || imagesPath + '3/30/WikEd_fix_basic.png';
image['fix_caps']           = image['fix_caps']           || imagesPath + '0/00/WikEd_fix_caps.png';
image['fix_chem']           = image['fix_chem']           || imagesPath + 'e/e7/WikEd_fix_chem.png';
image['fix_dash']           = image['fix_dash']           || imagesPath + 'e/e5/WikEd_fix_dash.png';
image['fix_html']           = image['fix_html']           || imagesPath + '0/05/WikEd_fix_html.png';
image['fix_math']           = image['fix_math']           || imagesPath + '3/3f/WikEd_fix_math.png';
image['fix_pipes']          = image['fix_pipes']          || imagesPath + '9/92/WikEd_fix_pipes.png';
image['fix_punct']          = image['fix_punct']          || imagesPath + 'd/db/WikEd_fix_punct.png';
image['fix_units']          = image['fix_units']          || imagesPath + '6/69/WikEd_fix_units.png';
image['fullscreen']         = image['fullscreen']         || imagesPath + 'd/d3/WikEd_fullscreen.png';
image['get_selection']      = image['get_selection']      || imagesPath + '9/96/WikEd_get_selection.png';
// image['get_selection_both'] = image['get_selection_both'] || imagesPath + '9/95/WikEd_get_selection_both.png';
image['image']              = image['image']              || imagesPath + '3/37/WikEd_image.png';
image['increase_heading']   = image['increase_heading']   || imagesPath + '5/50/WikEd_increase_heading.png';
image['indent_list']        = image['indent_list']        || imagesPath + '7/7a/WikEd_indent_list.png';
image['italic']             = image['italic']             || imagesPath + 'd/d4/WikEd_italic.png';
image['jump_next']          = image['jump_next']          || imagesPath + '5/54/WikEd_jump_next.png';
image['jump_prev']          = image['jump_prev']          || imagesPath + 'c/c7/WikEd_jump_prev.png';
image['jump_top_bottom']    = image['jump_top_bottom']    || imagesPath + '5/5d/WikEd_jump_top_bottom.png';
image['logo']               = image['logo']               || imagesPath + '6/67/WikEd_logo.png';
image['number_list']        = image['number_list']        || imagesPath + '3/3b/WikEd_number_list.png';
image['preview']            = image['preview']            || imagesPath + '3/31/WikEd_preview.png';
image['redirect']           = image['redirect']           || imagesPath + 'f/fa/WikEd_redirect.png';
image['redo']               = image['redo']               || imagesPath + 'd/d7/WikEd_redo.png';
image['redo_all']           = image['redo_all']           || imagesPath + '2/2d/WikEd_redo_all.png';
image['regexp']             = image['regexp']             || imagesPath + '6/6a/WikEd_regexp.png';
image['replace_all']        = image['replace_all']        || imagesPath + '2/2a/WikEd_replace_all.png';
image['replace_next']       = image['replace_next']       || imagesPath + 'b/b0/WikEd_replace_next.png';
image['replace_prev']       = image['replace_prev']       || imagesPath + 'a/a1/WikEd_replace_prev.png';
image['source']             = image['source']             || imagesPath + '0/02/WikEd_source.png';
image['subscript']          = image['subscript']          || imagesPath + '9/9e/WikEd_subscript.png';
image['superscript']        = image['superscript']        || imagesPath + 'b/bf/WikEd_superscript.png';
image['syntax']             = image['syntax']             || imagesPath + '6/67/WikEd_syntax.png';
image['table']              = image['table']              || imagesPath + 'b/bd/WikEd_table.png';
image['textify']            = image['textify']            || imagesPath + 'c/cd/WikEd_textify.png';
image['underline']          = image['underline']          || imagesPath + '2/21/WikEd_underline.png';
image['undo']               = image['undo']               || imagesPath + 'e/e6/WikEd_undo.png';
image['undo_all']           = image['undo_all']           || imagesPath + '0/08/WikEd_undo_all.png';
image['weblink']            = image['weblink']            || imagesPath + '1/16/WikEd_weblink.png';
image['wikify']             = image['wikify']             || imagesPath + '9/9f/WikEd_wikify.png';
image['wikilink']           = image['wikilink']           || imagesPath + '2/21/WikEd_wikilink.png';
                            
// global variables


// history
var fieldHist = [];
var cookieName = [];
var inputElement = [];
var selectElement = [];

var checkMarker = [];
checkMarker[true] = '\u2022';
checkMarker[false] = '\u22c5';

// undo
var undoBuffer = new Array(undoBufferMax);
var undoBufferSelStart = new Array(undoBufferMax);
var undoBufferSelEnd = new Array(undoBufferMax);
var undoBufferFirst = 0;
var undoBufferLast = 0;
var undoBufferCurr = 0;

var editformOrig = '';
var editformLast = null;

// fullscreen
var normalTextareaWidth;
var normalTextareaHeight;
var normalTextareaMargin;
var normalTextareaRows;
var normalPageXOffset;
var normalPageYOffset;
var normalTreePos = {};
var fullScreenMode = false;
var fullButtonValue = 'Full screen';
var fullButtonTitle = 'Full screen editing mode';
var normalButtonValue = 'Normal view';
var normalButtonTitle = 'Back no normal page view';
var normalFloatButtonValue = 'Back';

// textarea text info object
var textRows = new Object();
textRows.lineStart = [];
textRows.lineLength = [];
textRows.rowStart = [];
textRows.rowLength = [];

var textareaObj = {};
var frameBody = {};
var frameDocument = {};
var frameWindow = {};

var lastPosObj = null;

// counters
var i;
var j;


// add setup routine to addOnloadHook
if (window.addOnloadHook != null) {
	addOnloadHook(WikEdSetup);
}


//
// WikEdSetup: setup routine, called
//

function WikEdSetup() {

	var html = '';

// check if setup was already run
	if (document.getElementById('wikEdLogo') != null) {
		return;
	}

// insert logo into personal toolbar
	var logo = {};
	logo.img = document.createElement('img');
	logo.lnk = document.createElement('a');
	logo.lnk.href = programHomepage;
	logo.lnk.alt = 'WikEd Logo';
	logo.lnk.appendChild(logo.img);
	var listObj = document.createElement('li');
	listObj.id = 'wikEdLogo';
	listObj.appendChild(logo.lnk);
	var personalTools = document.getElementById('p-personal').getElementsByTagName('ul')[0];
	personalTools.appendChild(listObj);

// set error logo
	SetLogo(logo, false);

// at the moment this works only for mozilla browsers (Mozilla, Mozilla Firefox, Mozilla SeaMonkey)
	if (navigator.appName == null) {
		return;
	}
	var nameMatch = navigator.appName.match(/Netscape/i);
	if (nameMatch == null) {
		return;
	}
	var name = nameMatch[0];
	if ( (name == null) || (name == '') ) {
		return;
	}
	var version = navigator.appVersion.match(/\d+(\.\d+)/)[0];
	if ( (version == null) || (version < 5.0) ) {
		return;
	}

// check if this is an edit page
	textareaObj = document.getElementById('wpTextbox1');
	if (textareaObj == null) {

// reset error indicator
		SetLogo(logo);
		return;
	}

// get initial textarea height
	var textareaHeight = textareaObj.offsetHeight;

// setup the undo buffers and get the original text for local changes view
	editformOrig = textareaObj.value;

// set textarea size to maximal row number, always show vertical scrollbar
	textareaObj.style.overflow = '-moz-scrollbars-vertical';
	textareaObj.style.overflowX = 'auto';

// add stylesheet definitions
	var mainStyle = new StyleSheet();
	for (var rule in mainCSS) {
		mainStyle.addRule(rule, mainCSS[rule]);
	}

// create inputWrapper for textarea and buttons (fullscreen elements)
	var inputWrapper = document.createElement('div');
	inputWrapper.id = 'inputWrapper';
	textareaObj.parentNode.insertBefore(inputWrapper, textareaObj);

// move textareaObj to textareaWrapper
	var textareaWrapper = document.createElement('div');
	textareaWrapper.id = 'textareaWrapper';
	inputWrapper.appendChild(textareaWrapper);
	textareaWrapper.appendChild(textareaObj);

// add all other buttons and inputs to buttonsWrapper
	var buttonsWrapper = document.createElement('div');
	buttonsWrapper.id = 'buttonsWrapper';
	inputWrapper.appendChild(buttonsWrapper);

// add custom formatting buttons
	var wikEditButtons = document.createElement('div');
	wikEditButtons.id = 'wikEditButtons';
	html = '';

// format buttons
	html += '<div class="wikEdButtonsFormat" id="wikEdButtonsFormat">';

	html += '<img class="wikEdButton" src="' + image['undo']             + '" width="16" height="16" alt="Undo"             title="Undo"                                 onClick="javascript:Edit(\'undo\');">';
	html += '<img class="wikEdButton" src="' + image['redo']             + '" width="16" height="16" alt="Redo"             title="Redo"                                 onClick="javascript:Edit(\'redo\');">';

	html += '<img class="wikEdButton" src="' + image['bold']             + '" width="16" height="16" alt="Bold"             title="Bold text"                            onClick="javascript:Edit(\'bold\');">';
	html += '<img class="wikEdButton" src="' + image['italic']           + '" width="16" height="16" alt="Italic"           title="Italic text"                          onClick="javascript:Edit(\'italic\');">';
	html += '<img class="wikEdButton" src="' + image['underline']        + '" width="16" height="16" alt="Underline"        title="Underline text"                       onClick="javascript:Edit(\'underline\');">';
	html += '<img class="wikEdButton" src="' + image['superscript']      + '" width="16" height="16" alt="Superscript"      title="Superscript text"                     onClick="javascript:Edit(\'sup\');">';
	html += '<img class="wikEdButton" src="' + image['subscript']        + '" width="16" height="16" alt="Subscript"        title="Subscript text"                       onClick="javascript:Edit(\'sub\');">';
	html += '<img class="wikEdButton" src="' + image['case']             + '" width="16" height="16" alt="Casing"           title="Toggle between lowercase, uppercase first letters, and uppercase" onClick="javascript:Edit(\'case\');">';

	html += '<img class="wikEdButton" src="' + image['undo_all']         + '" width="16" height="16" alt="Undo all"         title="Undo all changes"                     onClick="javascript:Edit(\'undoall\');">';
	html += '<img class="wikEdButton" src="' + image['redo_all']         + '" width="16" height="16" alt="Redo all"         title="Redo all changes"                     onClick="javascript:Edit(\'redoall\');">';

	html += '<img class="wikEdButton" src="' + image['redirect']         + '" width="16" height="16" alt="Redirect"         title="Redirect"                             onClick="javascript:Edit(\'redirect\');">';
	html += '<img class="wikEdButton" src="' + image['syntax']           + '" width="16" height="16" alt="Syntax"           title="Update syntax highlighting"           onClick="javascript:Edit(\'update_syntax\');">';

	html += '<br>';

	html += '<img class="wikEdButton" src="' + image['wikilink']         + '" width="16" height="16" alt="Link"             title="Wiki link"                            onClick="javascript:Edit(\'wikilink\');">';
	html += '<img class="wikEdButton" src="' + image['weblink']          + '" width="16" height="16" alt="Weblink"          title="External Weblink"                     onClick="javascript:Edit(\'weblink\');">';

	html += '<img class="wikEdButton" src="' + image['decrease_heading'] + '" width="16" height="16" alt="Heading-"         title="Decrease heading levels"              onClick="javascript:Edit(\'headingless\');">';
	html += '<img class="wikEdButton" src="' + image['increase_heading'] + '" width="16" height="16" alt="Heading+"         title="Increase heading levels"              onClick="javascript:Edit(\'headingmore\');">';

	html += '<img class="wikEdButton" src="' + image['bullet_list']      + '" width="16" height="16" alt="Bullet list"      title="Bulleted list"                        onClick="javascript:Edit(\'bulletlist\');">';
	html += '<img class="wikEdButton" src="' + image['number_list']      + '" width="16" height="16" alt="Number list"      title="Numbered list"                        onClick="javascript:Edit(\'numberlist\');">';
	html += '<img class="wikEdButton" src="' + image['indent_list']      + '" width="16" height="16" alt="Indent list"      title="Indented list"                        onClick="javascript:Edit(\'indentlist\');">';
	html += '<img class="wikEdButton" src="' + image['definition_list']  + '" width="16" height="16" alt="Def list"         title="Definition list"                      onClick="javascript:Edit(\'deflist\');">';

	html += '<img class="wikEdButton" src="' + image['image']            + '" width="16" height="16" alt="Image"            title="Image"                                onClick="javascript:Edit(\'image\');">';
	html += '<img class="wikEdButton" src="' + image['table']            + '" width="16" height="16" alt="Table"            title="Table"                                onClick="javascript:Edit(\'table\');">';

	html += '<img class="wikEdButton" src="' + image['wikify']           + '" width="16" height="16" alt="Wikify"           title="Wikify pasted content"                onClick="javascript:Edit(\'wikify\');">';
	html += '<img class="wikEdButton" src="' + image['textify']          + '" width="16" height="16" alt="Textify"          title="Convert pasted content to plain text" onClick="javascript:Edit(\'textify\');">';

	html += '</div>';

// window functions: syntax highlighting, classic textarea, align, fullscreen
	html += '<div class="wikEdButtonsWindow" id="wikEdButtonsWindow">';

	html += '<img class="wikEdButtonUnchecked" src="' + image['source']        + '" width="16" height="16" alt="Source"             title="Show the source code for testing purposes"    id="source"                onClick="javascript:Button(\'source\', true);" onLoad="javascript:Button(\'source\', null, false);" >';
	html += '<img class="wikEdButtonUnchecked" src="' + image['syntax']        + '" width="16" height="16" alt="Syntax"             title="Highlight syntax"                             id="syntax"                onClick="javascript:Button(\'syntax\', true);" onLoad="javascript:Button(\'syntax\', null, highlightSyntax);" >';
	html += '<img class="wikEdButton"          src="' + image['align_buttons'] + '" width="16" height="16" alt="Scroll to buttons"  title="Scroll to edit buttons"                       id="scrolltobuttons"       onClick="javascript:Button(\'scrolltobuttons\');">';
	html += '<img class="wikEdButton"          src="' + image['align_top']     + '" width="16" height="16" alt="Scroll to textarea" title="Scroll to textarea"                           id="scrolltotop"           onClick="javascript:Button(\'scrolltotop\');">';
                                                                                                                                                                                       
	html += '<br>';                                                                                                                                                                      
                                                                                                                                                                                       
	html += '<img class="wikEdButtonUnchecked" src="' + image['classic']       + '" width="16" height="16" alt="wikEd"              title="Use wikEd"                                    id="wikEd"                 onClick="javascript:Button(\'wikEd\', true);"           onLoad="javascript:Button(\'wikEd\', null, useWikEd);" >';
	html += '<img class="wikEdButtonFloat"     src="' + image['fullscreen']    + '" width="16" height="16" alt="Fullscreen"         title="Switch to fullscreen mode"                    id="fullScreenButtonFloat" onClick="javascript:Button(\'fullScreenButtonFloat\');" onLoad="javascript:Button(\'fullScreenButtonFloat\', null, false);" >';
	html += '<img class="wikEdButton"          src="' + image['fullscreen']    + '" width="16" height="16" alt="Fullscreen"         title="Switch to fullscreen mode"                    id="fullScreenButton"      onClick="javascript:Button(\'fullScreenButton\');"      onLoad="javascript:Button(\'fullScreenButton\', null, false);" >';
	html += '<img class="wikEdButton"          src="' + image['clear_history'] + '" width="16" height="16" alt="Clear history"      title="Clear the find, replace, and summary history" id="clearhistory"          onClick="javascript:Button(\'clearhistory\');">';
	html += '</div>';

// find / replace buttons

	html += '<div class="wikEdButtonsFind" id="wikEdButtonsFind">';

	html += '<img class="wikEdButton" src="' + image['get_selection']      + '" width="16" height="16" alt="Get find"         title="Copy selection to find field (double click: copy selection to find and to replace field)" onClick="javascript:Edit(\'getfind\');" ondblclick="javascript:Edit(\'getfindreplace\');">';
	html += '<img class="wikEdButton" src="' + image['find_all']           + '" width="16" height="16" alt="Find all"         title="Find all matches in whole text or selection"    onClick="javascript:Edit(\'findall\');">';
	html += '<img class="wikEdButton" src="' + image['find_prev']          + '" width="16" height="16" alt="Find prev"        title="Find previous match"                            onClick="javascript:Edit(\'findprev\');">';

	html += '<span style="position: relative; padding: 0; margin: 0 0.2em;" id="findComboInput">';
	html += '<input class="wikEdCombo" type="text" value="" style="height: 1.4em; font-family: monospace; height: 1.2em; padding: 0; margin: 0; position: absolute; left: 0; top: 0; z-index: 2;" onfocus="javascript:this.setSelectionRange(0, this.textLength);" id="findText" title="">';
	html += '<select class="wikEdCombo" id="findSelect" style="height: 1.5em; font-family: monospace; border: none; padding: 0; margin: 0; position: relative; vertical-align: baseline; z-index: 1;" onfocus="javascript:SetComboOptions(\'find\')" onChange="javascript:ChangeComboInput(\'find\');">';
	html += '</select>';
	html += '</span>';

	html += '<img class="wikEdButton" src="' + image['find_next']          + '" width="16" height="16" alt="Find next"        title="Find next match"                                 onClick="javascript:Edit(\'findnext\');">';
	html += '<img class="wikEdButton" src="' + image['jump_top_bottom']    + '" width="16" height="16" alt="Jump up/down"     title="Jump to the top / bottom"                        onClick="javascript:Edit(\'updown\');">';
	html += '<img class="wikEdButton" src="' + image['jump_prev']          + '" width="16" height="16" alt="Jump prev"        title="Jump to previously changed position"             onClick="javascript:Edit(\'prevpos\');">';
	html += '<img class="wikEdButton" src="' + image['jump_next']          + '" width="16" height="16" alt="Jump next"        title="Jump back to last position"                      onClick="javascript:Edit(\'lastpos\');">';

	html += '<br>';

//	html += '<img class="wikEdButton" src="' + image['get_selection_both'] + '" width="16" height="16" alt="Get both"         title="Copy selection to find and replace fields" onClick="javascript:Edit(\'getboth\');" ondblclick="javascript:Edit(\'getfindreplace\');">';
	html += '<img class="wikEdButton" src="' + image['clear_find']         + '" width="16" height="16" alt="Clear find"       title="Clear the find field (to search for selected text)" onClick="javascript:Button(\'clearfind\');">';
	html += '<img class="wikEdButton" src="' + image['replace_all']        + '" width="16" height="16" alt="Replace all"      title="Replace all matches in whole text or selection"             onClick="javascript:Edit(\'replaceall\');">';
	html += '<img class="wikEdButton" src="' + image['replace_prev']       + '" width="16" height="16" alt="Replace prev"     title="Replace previous match"                                     onClick="javascript:Edit(\'replaceprev\');">';

	html += '<span style="position: relative; padding: 0; margin: 0 0.2em;" id="replaceComboInput">';
	html += '<input class="wikEdCombo" type="text" value="" style="height: 1.4em; font-family: monospace; height: 1.2em; padding: 0; margin: 0; position: absolute; left: 0; top: 0; z-index: 2;" onfocus="this.setSelectionRange(0, this.textLength);" id="replaceText" title="">';
	html += '<select class="wikEdCombo" id="replaceSelect" style="height: 1.5em; font-family: monospace; border: none; padding: 0; margin: 0; position: relative; vertical-align: baseline; z-index: 1;" onfocus="SetComboOptions(\'replace\')" onChange="javascript:ChangeComboInput(\'replace\');">';
	html += '</select>';
	html += '</span>';

	html += '<img class="wikEdButton" src="'          + image['replace_next']     + '" width="16" height="16" alt="Replace next"    title="Replace next match"              onClick="javascript:Edit(\'replacenext\');">';

	html += '<img class="wikEdButtonUnchecked" src="' + image['case_sensitive']   + '" width="16" height="16" alt="Case sensitive"  title="Search is case sensitive"                               id="caseSensitive" onClick="javascript:Button(\'caseSensitive\', true);" onLoad="javascript:Button(\'caseSensitive\', null, false);" >';
	html += '<img class="wikEdButtonUnchecked" src="' + image['regexp']           + '" width="16" height="16" alt="RegExp"          title="Search field is a regular expression"                   id="regExp"        onClick="javascript:Button(\'regExp\', true);"        onLoad="javascript:Button(\'regExp\', null, false);" >';
	html += '<img class="wikEdButtonUnchecked" src="' + image['find_ahead']       + '" width="16" height="16" alt="Find ahead"      title="Find ahead as you type (only for non-regexp searches)"  id="findAhead"     onClick="javascript:Button(\'findAhead\', true);"     onLoad="javascript:Button(\'findAhead\', null, findAheadSelected);" >';

	html += '</div>';

// fixing buttons
	html += '<div class="wikEdButtonsFix" id="wikEdButtonsFix">';

	html += '<img class="wikEdButton" src="' + image['fix_basic']        + '" width="16" height="16" alt="Fix basic"        title="Fix blanks and empty lines, always done by other fixing functions" onClick="javascript:Edit(\'fixbasic\');">';

	html += '<img class="wikEdButton" src="' + image['fix_pipes']        + '" width="16" height="16" alt="Pipe spaces"      title="Add blanks around vertical bars in wikilinks"                      onClick="javascript:Edit(\'fixpipes\');">';
	html += '<img class="wikEdButton" src="' + image['fix_punct']        + '" width="16" height="16" alt="Fix puntuation"   title="Fix spaces before puntuation"                                      onClick="javascript:Edit(\'fixpunct\');">';
	html += '<img class="wikEdButton" src="' + image['fix_math']         + '" width="16" height="16" alt="Fix math"         title="Fix math"                                                          onClick="javascript:Edit(\'fixmath\');">';
	html += '<img class="wikEdButton" src="' + image['fix_chem']         + '" width="16" height="16" alt="Fix chem"         title="Fix chemical formulas"                                             onClick="javascript:Edit(\'fixchem\');">';

	html += '<br>';

	html += '<img class="wikEdButton" src="' + image['fix_units']        + '" width="16" height="16" alt="Fix units"        title="Fix units"                                                         onClick="javascript:Edit(\'fixunits\');">';
	html += '<img class="wikEdButton" src="' + image['fix_dash']         + '" width="16" height="16" alt="Fix dashes"       title="Fix dashes"                                                        onClick="javascript:Edit(\'fixdashes\');">';
                                                                                                                                                                                                    
	html += '<img class="wikEdButton" src="' + image['fix_html']         + '" width="16" height="16" alt="Fix html"         title="Fix html to wikicode"                                              onClick="javascript:Edit(\'fixhtml\');">';
	html += '<img class="wikEdButton" src="' + image['fix_caps']         + '" width="16" height="16" alt="Fix caps"         title="Fix caps in headers and lists"                                     onClick="javascript:Edit(\'fixcaps\');">';
	html += '<img class="wikEdButton" src="' + image['fix_all']          + '" width="16" height="16" alt="Fix all"          title="Fix units, dashes, html, and caps"                                 onClick="javascript:Edit(\'fixall\');">';

	html += '</div>';

	html += '<br style="clear: both">';

	wikEditButtons.innerHTML = html;
	buttonsWrapper.appendChild(wikEditButtons);

// add elements to buttonsWrapper
	var element = document.getElementById('editpage-copywarn');
	while (element != null) {
		if (element.id == 'editpage-specialchars') {
			break;
		}
		next_element = element.nextSibling;
		buttonsWrapper.appendChild(element);
		element = next_element;
	}

// add preview box upper buttons
	var previewBoxButtons = document.createElement('div');
	previewBoxButtons.id = 'previewBoxButtons';
	previewBoxButtons.className = 'wikEdButtonsPreview';

	html = '';
	html += '<img class="wikEdButton" src="' + image['preview']       + '" width="16" height="16" alt="Preview"        title="Show preview below"        id="preview"          onClick="javascript:Button(\'preview\');"          onLoad="javascript:Button(\'preview\', null, false, \'wikEdButton\');" >';
	html += '<img class="wikEdButton" src="' + image['diff']          + '" width="16" height="16" alt="Changes"        title="Show changes below"        id="diff"             onClick="javascript:Button(\'diff\');"             onLoad="javascript:Button(\'diff\', null, false, \'wikEdButton\');" >';
	html += '<img class="wikEdButton" src="' + image['close']         + '" width="16" height="16" alt="Close"          title="Close preview box"         id="close"            onClick="javascript:Button(\'close\');"            onLoad="javascript:Button(\'close\', null, false, \'wikEdButton\');" >';
	html += '<img class="wikEdButton" src="' + image['align_buttons'] + '" width="16" height="16" alt="Scroll buttons" title="Scroll to edit buttons"    id="scrolltobuttons2" onClick="javascript:Button(\'scrolltobuttons2\');">';
	html += '<img class="wikEdButton" src="' + image['align_top']     + '" width="16" height="16" alt="Scroll top"     title="Scroll to textarea"        id="scrolltotop2"     onClick="javascript:Button(\'scrolltotop2\');">';

	previewBoxButtons.innerHTML = html;
	document.getElementById('wpSave').parentNode.insertBefore(previewBoxButtons, document.getElementById('wpSave').parentNode.firstChild);

// add preview box
	var previewBox = document.createElement('div');
	previewBox.id = 'customPreviewBox';
	previewBox.style.display = 'none';

	html = '';
	html += '<div style="clear: both; margin-top: 0.5em; margin-bottom: 0; border-width: 1px; border-style: solid; border-color: #808080 #d0d0d0 #d0d0d0 #808080;" id="PreviewBoxOutline">';
	html += '<div class="wikEdPreviewBox" style="padding: 5px; border-width: 1px; border-style: solid; border-color: #404040 #ffffff #ffffff #404040;" id="PreviewBox">';
	html += '</div>';
	html += '</div>';

	html += '<div class="wikEdButtonsWindow">';
	html += '<img class="wikEdButton" src="' + image['preview']       + '" width="16" height="16" alt="Preview"        title="Show preview above"     id="preview2"         onClick="javascript:Button(\'preview2\');"         onLoad="javascript:Button(\'preview2\', null, false, \'wikEdButton\');" >';
	html += '<img class="wikEdButton" src="' + image['diff']          + '" width="16" height="16" alt="Changes"        title="Show changes above"     id="diff2"            onClick="javascript:Button(\'diff2\');"            onLoad="javascript:Button(\'diff2\', null, false, \'wikEdButton\');" >';
	html += '<img class="wikEdButton" src="' + image['close']         + '" width="16" height="16" alt="Close"          title="Close preview box"      id="close2"           onClick="javascript:Button(\'close2\');"           onLoad="javascript:Button(\'close2\', null, false, \'wikEdButton\');" >';
	html += '<img class="wikEdButton" src="' + image['align_buttons'] + '" width="16" height="16" alt="Scroll buttons" title="Scroll to edit buttons" id="scrolltobuttons3" onClick="javascript:Button(\'scrolltobuttons3\');">';
	html += '<img class="wikEdButton" src="' + image['align_top']     + '" width="16" height="16" alt="Scroll top"     title="Scroll to textarea"     id="scrolltotop3"     onClick="javascript:Button(\'scrolltotop3\');">';
	html += '</div>';

	previewBox.innerHTML = html;
	inputWrapper.parentNode.insertBefore(previewBox, inputWrapper.nextSibling);
// move linebreak before checkboxes down
	var summary = document.getElementById('wpSummary');
	var checkboxSep = document.createTextNode('');
	summary.parentNode.replaceChild(checkboxSep, summary.nextSibling);

// move 'Summary:' into submit button div
	var summary = document.getElementById('wpSummary');
	var summaryLabel = document.getElementById('wpSummaryLabel');
	summary.parentNode.insertBefore(summaryLabel, summary.parentNode.firstChild);
	summary.parentNode.style.marginTop = '0.25em';

// make the summary a combo box
	var summary = document.getElementById('wpSummary');
	var htmlPre = '';
	var htmlPost = '';
	html = '';
	htmlPre  += ' <span style="position: relative;" id="summaryComboInput">';
	html     += ' style="padding: 0; margin: 0; position: absolute; left: 0; top: 0; z-index: 2;" onfocus="this.setSelectionRange(0, this.textLength);"';
	htmlPost += '<select style="border: none; padding: 0; margin: 0; position: relative; vertical-align: middle; z-index: 1;" id="wpSummarySelect" onfocus="javascript:SetComboOptions(\'summary\')" onchange="javascript:ChangeComboInput(\'summary\');">';
	htmlPost += '</select>';
	htmlPost += '</span>';
	summary.parentNode.innerHTML = summary.parentNode.innerHTML.replace(/\s*(<input\b[^>]*?id\=\"wpSummary\")([^>]*>)/, htmlPre + '$1' + html + '$2' + htmlPost);

// add margin around submit buttons
	var saveButton = document.getElementById('wpSave');
	saveButton.parentNode.style.marginTop = '0.5em';
	saveButton.parentNode.style.marginBottom = '0.5em';

// move copywarn down
	var copywarn = document.getElementById('editpage-copywarn');
	inputWrapper.parentNode.insertBefore(copywarn, previewBox.nextSibling);

// showikEdn submit button texts and add onclick handler
	document.getElementById('wpPreview').value = 'Preview';
	document.getElementById('wpDiff').value = 'Changes';

// set up combo input boxes with history
	fieldHist ['find'] = [];
	cookieName['find'] = 'findHistory';
	inputElement['find'] = new Object(document.getElementById('findText'));
	selectElement['find'] = new Object(document.getElementById('findSelect'));
	selectElement['find'].style.height = (inputElement['find'].clientHeight + 1) +'px';

	fieldHist ['replace'] = [];
	cookieName['replace'] = 'replaceHistory';
	inputElement['replace'] = new Object(document.getElementById('replaceText'));
	selectElement['replace'] = new Object(document.getElementById('replaceSelect'));
	selectElement['replace'].style.height = (inputElement['replace'].clientHeight + 1) +'px';

	fieldHist ['summary'] = [];
	cookieName['summary'] = 'summaryHistory';
	inputElement['summary'] = new Object(document.getElementById('wpSummary'));
	selectElement['summary'] = new Object(document.getElementById('wpSummarySelect'));
	selectElement['summary'].style.height = (inputElement['summary'].clientHeight + 1) +'px';

	ResizeComboInput('find');
	ResizeComboInput('replace');
	ResizeComboInput('summary');

// setup fullscreen mode

// save textbox properties
	normalTextareaWidth = GetStyle(textareaObj, 'width');
	normalTextareaHeight = GetStyle(textareaObj, 'height');
	normalTextareaMargin = GetStyle(textareaObj, 'margin');
	normalTextareaRows = textareaObj.rows;

// set fullscreen style fixes
	var inputWrapper = document.getElementById('inputWrapper');
	var content = document.getElementById('content');
	var content = document.getElementById('content');
	inputWrapper.style.lineHeight = GetStyle(content, 'line-height');

// move globalWrapper elements to new subGlobalWrapper
	var globalWrapper = document.getElementById('globalWrapper');
	var subGlobalWrapper = document.createElement('div');
	subGlobalWrapper.id = 'subGlobalWrapper';
	globalWrapper.appendChild(subGlobalWrapper);
	var element = globalWrapper.firstChild;
	while (element != null) {
		if (element.id == 'subGlobalWrapper') {
			break;
		}
		next_element = element.nextSibling;
		subGlobalWrapper.appendChild(element);
		element = next_element;
	}

// create iframe

// moving an iframe in design mode may crash seamonkey
	var frameWrapper = document.createElement('div');
	frameWrapper.id = 'frameWrapper';
	html = '';
	html += '<div id="frameBorderOuter" style="width: 100%; margin-top: 0.5em; margin-bottom: 0.1em; border-width: 1px; border-style: solid; border-color: #808080 #d0d0d0 #d0d0d0 #808080;">';
	html += '<div id="frameBorderInner" style="padding: 0; border-width: 1px; border-style: solid; border-color: #404040 #ffffff #ffffff #404040;">';
	html += '</div>';
	html += '<iframe id="wikEdFrame" name="wikEdFrame" style="width: 100%; height: ' + textareaHeight + 'px; padding: 0; margin: 0; border: none;"></iframe>';
	html += '</div>';
	html += '</div>';

	frameWrapper.innerHTML = html;
	inputWrapper.insertBefore(frameWrapper, textareaWrapper);

	frameWindow = document.getElementById('wikEdFrame').contentWindow;
	frameDocument = frameWindow.document;

// fill the frame with content
	html = '';
	html += '<html><head></head>';
	html += '<body id="frameBody" onload="window.document.designMode = \'on\'; window.document.execCommand(\'styleWithCSS\', false, false);">';
	html += '</body></html>';
	frameDocument.open();
	frameDocument.write(html);
	frameDocument.close();
	frameBody = frameDocument.body;

// add frame stylesheet definition
	var frameStyle = new StyleSheet(frameDocument);
	for (var rule in frameCSS) {
		frameStyle.addRule(rule, frameCSS[rule]);
	}

// set original tree position of input area
	normalTreePos = inputWrapper.nextSibling;

// set fullscreen button texts
	var fullScreenButton = document.getElementById('fullScreenButton');
	var floatButton = document.getElementById('fullScreenButtonFloat');
	fullScreenButton.value = fullButtonValue;
	fullScreenButton.title = fullButtonTitle;
	floatButton.value = normalFloatButtonValue;
	floatButton.title = normalButtonTitle;

// set frame events
	frameDocument.addEventListener('keypress', KeyFrame, true);
	frameDocument.addEventListener('mousedown', KeyFrame, true);

// set fullscreen events
	fullScreenButton.addEventListener('click', FullScreen, true);
	floatButton.addEventListener('click', NormalScreen, true);

	floatButton.onblur = function() {
		floatButton.style.right = '0.5em';
		floatButton.style.bottom = '0.5em';
		floatButton.style.top = '';
		floatButton.style.left = '';
	};

// find ahead events
	var findText = document.getElementById('findText');
	findText.addEventListener('keyup', FindAhead, true);

// submit button events
	var saveButton = document.getElementById('wpSave');
	var previewButton = document.getElementById('wpPreview');
	var diffButton = document.getElementById('wpDiff');
	saveButton.onclick = function() {
		if (useWikEd == true) {
			UpdateTextarea();
		}
		AddToHistory('summary');
		saveButton.onclick = null;
		saveButton.click();
	};
	previewButton.onclick = function() {
		if (useWikEd == true) {
			UpdateTextarea();
		}
		previewButton.onclick = null;
		previewButton.click();
	};
	diffButton.onclick = function() {
		if (useWikEd == true) {
			UpdateTextarea();
		}
		diffButton.onclick = null;
		diffButton.click();
	};

// set textarea cursor to start
//	textareaObj.setSelectionRange(0, 0);

	if (useWikEd != true) {
		document.getElementById('wikEdButtonsFormat').style.display = 'none';
		document.getElementById('wikEdButtonsFind').style.display = 'none';
		document.getElementById('wikEdButtonsFix').style.display = 'none';
		document.getElementById('wikEdButtonsWindow').style.display = 'block';
	}
	else {
		UpdateFrame();
		document.getElementById('textareaWrapper').style.display = 'none';
		document.getElementById('frameWrapper').style.display = 'block';
	}

// disable scrolling to edit window on next preview page
	document.getElementById('editform').action += '&noscroll';

// scroll to edit window if it is not a preview page
	if (window.location.search.match('noscroll') == null) {
		window.scroll(0, GetOffsetTop(inputWrapper));
	}

// reset error indicator
	SetLogo(logo);

	return;
}


//
// Button: toggle or set button checked state
//

function SetLogo(logo, error) {

	if (error == false) {
		logo.img.src = image['error'];
		logo.img.alt = 'WikEd error';
		logo.lnk.title = 'WikEd ' + programVersion + ' (' + programDate + '): Loading error';
	}
	else {
		logo.img.src = image['logo'];
		logo.img.alt = 'WikEd';
		logo.lnk.title = 'WikEd ' + programVersion + ' (' + programDate + ')';
	}
	return;
}


//
// Button: toggle or set button checked state
//

function Button(whichButton, toggleButton, setButton, classButton, doButton) {

	var buttonObj = document.getElementById(whichButton);

// init the button ////////////  onLoad doesn't work!??!
	if (setButton != null) {
		if (setButton == false) {
			buttonObj.checked = false;
			if (classButton == null) {
				buttonObj.className = 'wikEdButtonUnchecked';
			}
		}
		else {
			buttonObj.checked = true;
			if (classButton == null) {
				buttonObj.className = 'wikEdButtonChecked';
			}
		}
	}
	else if (classButton != null) {
		buttonObj.className = classButton;
	}

// toggle the button
	if (toggleButton != null) {
		if (toggleButton == true) {
			if (buttonObj.checked == true) {
				buttonObj.checked = false;
				buttonObj.className = 'wikEdButtonUnchecked';
			}
			else {
				buttonObj.checked = true;
				buttonObj.className = 'wikEdButtonChecked';
			}
		}
	}

// perform specific actions
	if ( ( (setButton == null) && (classButton == null) ) || (doButton == true) ) {

// remove active content
		removeElements(['script', 'object', 'applet', 'embed']);

		var toggle = false;
		switch (whichButton) {
			case 'syntax':
				var obj = {};
				obj.html = frameBody.innerHTML;
				if (buttonObj.checked == true) {
					highlightSyntax = true;
					HighlightSyntax(obj);
				}
				else {
					highlightSyntax = false;
					RemoveHighlighting(obj);
				}
				frameBody.innerHTML = obj.html;
				break;
			case 'source':
				var obj = {};
				if (buttonObj.checked == true) {
					Edit('sourceon');
				}
				else {
					Edit('sourceoff');
				}
				break;
			case 'scrolltotop':
			case 'scrolltotop2':
			case 'scrolltotop3':
				var wrapperObj = document.getElementById('inputWrapper');
				var wrapperTop = GetOffsetTop(wrapperObj);
				window.scroll(0, wrapperTop);
				break;
			case 'scrolltobuttons':
			case 'scrolltobuttons2':
			case 'scrolltobuttons3':
				var wrapperObj = document.getElementById('buttonsWrapper');
				var wrapperTop = GetOffsetTop(wrapperObj);
				window.scroll(0, wrapperTop);
				break;
			case 'preview':
			case 'preview2':
				NormalScreen();
				UpdateTextarea();
				document.getElementById('PreviewBox').innerHTML = wiki2html(textareaObj.value);
				document.getElementById('customPreviewBox').style.display = 'block';
				break;
			case 'diff':
			case 'diff2':
				NormalScreen();
				UpdateTextarea();
				document.getElementById('PreviewBox').innerHTML = StringDiff(editformOrig, textareaObj.value);
				document.getElementById('customPreviewBox').style.display = 'block';
				break;
			case 'close':
			case 'close2':
				document.getElementById('customPreviewBox').style.display = 'none';
				break;
			case 'wikEd':
				if (buttonObj.checked == false) {
					UpdateTextarea();
					document.getElementById('frameWrapper').style.display = 'none';
					document.getElementById('textareaWrapper').style.display = 'block';
					document.getElementById('wikEdButtonsFormat').style.display = 'none';
//document.getElementById('wikEdButtonsWindow').style.display = 'none';
					document.getElementById('wikEdButtonsFind').style.display = 'none';
					document.getElementById('wikEdButtonsFix').style.display = 'none';
					useWikEd = false;
				}
				else {
					UpdateFrame();
					document.getElementById('textareaWrapper').style.display = 'none';
					document.getElementById('frameWrapper').style.display = 'block';
					document.getElementById('wikEdButtonsFormat').style.display = 'block';
					document.getElementById('wikEdButtonsWindow').style.display = 'block';
					document.getElementById('wikEdButtonsFind').style.display = 'block';
					document.getElementById('wikEdButtonsFix').style.display = 'block';
					useWikEd = true;
				}
				break;
			case 'caseSensitive':
				toggle = true;
				break;
			case 'regExp':
				toggle = true;
				break;
			case 'findAhead':
				toggle = true;
				break;
			case 'fullScreenButton':
			case 'fullScreenFloat':
//				FullScreen();
//				fullScreenButton
//				fullScreenButtonFloat
				break;
			case 'clearhistory':
				ClearHistory('find');
				ClearHistory('replace');
				ClearHistory('summary');
				break;
			case 'clearfind':
				inputElement['find'].value = '';
				break;
			case 'placeholder'://testing
				break;
		}
	}
	return;
}


//
// editing functions
//

function Edit(whichButton) {

// add focus to textbox
//	textareaObj.focus();

// remove active content
	removeElements(['script', 'object', 'applet', 'embed', 'textarea']);

// get the scroll position
	var scrollTopPx = textareaObj.scrollTop;
	var scrollHeightPx = textareaObj.scrollHeight;

// convert strange spaces, remove non-\n linebreak characters
//	ConvertStrangeSpaces();

// generate several different text ranges to apply the changes to later
	var obj = {};

// setup whole object for the whole text
	obj.whole = {};
	obj.whole.plainArray = [];
	obj.whole.plainNode = [];
	obj.whole.plainStart = [];
	obj.whole.from = 'whole';

// get whole range
	obj.whole.range = document.createRange();
	obj.whole.range.setStartBefore(frameBody.firstChild);
	obj.whole.range.setEndAfter(frameBody.lastChild);

// get whole plain text
	GetInnerHTML(obj.whole, frameBody);

	RemoveHighlightingWikify(obj.whole);
	obj.whole.plain = obj.whole.html;
	obj.whole.plain = obj.whole.plain.replace(/<br>/g, '\n');

	obj.whole.range.setStartBefore(frameBody.firstChild);
	obj.whole.range.setEndAfter(frameBody.lastChild);

// setup selection object for the selected text
	obj.selection = {};
	obj.selection.from = 'selection';

// set selection range
 	obj.sel = frameWindow.getSelection();
	obj.selection.range = obj.sel.getRangeAt(obj.sel.rangeCount - 1);

// copy range to document fragment
	var documentFragment = obj.selection.range.cloneContents();

// get selected text
	GetInnerHTML(obj.selection, documentFragment);

	RemoveHighlightingWikify(obj.selection);
	obj.selection.plain = obj.selection.html;
	obj.selection.plain = obj.selection.plain.replace(/<br>/g, '\n');

// setup cursor object for the cursor position
	obj.cursor = {};
	obj.cursor.from = 'cursor';
	obj.cursor.range = document.createRange();
	obj.cursor.range.setStart(obj.sel.focusNode, obj.sel.focusOffset);
	obj.cursor.range.setEnd(obj.sel.focusNode, obj.sel.focusOffset);
	obj.cursor.plain = '';

// setup focusWord object for the word under the cursor
	obj.focusWord = {};
	obj.focusWord.from = 'focusWord';
	obj.focusWord.range = document.createRange();

// setup focusLine object for the line under the cursor
	obj.focusLine = {};
	obj.focusLine.from = 'focusLine';
	obj.focusLine.range = document.createRange();

// setup selectionWord object for the words under the selection
	obj.selectionWord = {};
	obj.selectionWord.from = 'selectionWord';
	obj.selectionWord.range = document.createRange();

// setup selectionLine object for the lines under the selection
	obj.selectionLine = {};
	obj.selectionLine.from = 'selectionLine';
	obj.selectionLine.range = document.createRange();

// find the respective word and line boundaries
	FindBoundaries(obj.focusWord, obj.focusLine, obj.whole, obj.cursor);
	FindBoundaries(obj.selectionWord, obj.selectionLine, obj.whole, obj.selection);

// get the wikified plain text for the word under the cursor
	var documentFragment = obj.focusWord.range.cloneContents();
	GetInnerHTML(obj.focusWord, documentFragment);
	RemoveHighlightingWikify(obj.focusWord);
	obj.focusWord.plain = obj.focusWord.html;
	obj.focusWord.plain = obj.focusWord.plain.replace(/<br>/g, '\n');

// get the wikified plain text for the line under the cursor
	var documentFragment = obj.focusLine.range.cloneContents();
	GetInnerHTML(obj.focusLine, documentFragment);
	RemoveHighlightingWikify(obj.focusLine);
	obj.focusLine.plain = obj.focusLine.html;
	obj.focusLine.plain = obj.focusLine.plain.replace(/<br>/g, '\n');

// get the wikified plain text for the words under the selection
	var documentFragment = obj.selectionWord.range.cloneContents();
	GetInnerHTML(obj.selectionWord, documentFragment);
	RemoveHighlightingWikify(obj.selectionWord);
	obj.selectionWord.plain = obj.selectionWord.html;
	obj.selectionWord.plain = obj.selectionWord.plain.replace(/<br>/g, '\n');

// get the wikified plain text for the lines under the selection
	var documentFragment = obj.selectionLine.range.cloneContents();
	GetInnerHTML(obj.selectionLine, documentFragment);
	RemoveHighlightingWikify(obj.selectionLine);
	obj.selectionLine.plain = obj.selectionLine.html;
//  obj.selectionLine.plain = obj.selectionLine.plain.replace(/\n/g, '');
	obj.selectionLine.plain = obj.selectionLine.plain.replace(/<br>/g, '\n');

// select the appropriate object to change (whole, selection, cursor, focusWord, focusLine, selectionWord, or selectionLine)
	obj.changed = {};
	switch (whichButton) {

// no text: cursor
		case 'undo':
		case 'redo':
			obj.changed = obj.cursor;
			break;

// basic wiki character formatting: selection / focusWord / cursor
		case 'bold':
		case 'italic':
		case 'underline':
		case 'sup':
		case 'sub':
		case 'wikilink':
		case 'weblink':
			if (obj.selection.plain != '') {
				obj.changed = obj.selection;
			}
			else if (obj.focusWord.plain != '') {
				obj.changed = obj.focusWord;
			}
			else  {
				obj.changed = obj.cursor;
			}
			break;

// character formatting: selection / focusWord
		case 'case':
			if (obj.selection.plain != '') {
				obj.changed = obj.selection;
			}
			else {
				obj.changed = obj.focusWord;
			}
			break;

// whole text changes: whole
		case 'undoall':
		case 'redoall':
			obj.changed = obj.whole;
			break;

// update syntax highlighting: selection / whole
		case 'update_syntax':
			if (obj.selection.plain != '') {
				obj.changed = obj.selection;
			}
			else {
				obj.changed = obj.whole;
			}
			break;

// multiple line changes: selectionLine
		case 'headingless':
		case 'headingmore':
		case 'bulletlist':
		case 'numberlist':
		case 'indentlist':
		case 'deflist':
			if (obj.selection.plain != '') {
				obj.changed = obj.selectionLine;
			}
			else {
				obj.changed = obj.focusLine;
			}
			break;

// image: selectionWord (if text is selected) / cursor
//whole, selection, cursor, focusWord, focusLine, selectionWord, or selectionLine
		case 'image':
			if (obj.selection.plain != '') {
				obj.changed = obj.selectionWord;
			}
			else  {
				obj.changed = obj.cursor;
			}
			break;

// table: selectionLine / cursor
		case 'table':
			if (obj.selection.plain != '') {
				obj.changed = obj.selectionLine;
			}
			else  {
				obj.changed = obj.cursor;
			}
			break;

// wikify, textify: selection / whole
		case 'wikify':
		case 'textify':
			if (obj.selection.plain != '') {
				obj.changed = obj.selection;
			}
			else {
				obj.changed = obj.whole;
			}
			break;

// redirect: whole
		case 'redirect':
			obj.changed = obj.whole;
			break;

// character formatting: selection / focusWord
		case 'getfind':
		case 'getfindreplace':
			if (obj.selection.plain != '') {
				obj.changed = obj.selection;
			}
			else {
				obj.changed = obj.focusWord;
			}
			break;

// find and replace: find value / selection / focusWord
		case 'findprev':
		case 'findnext':
		case 'replaceprev':
		case 'replacenext':
			if (inputElement['find'].value != '') {
				obj.changed = obj.cursor;
				obj.changed.plain = inputElement['find'].value;
			}
			else if (obj.selection.plain != '') {
				obj.changed = obj.selection;
			}
			else if (obj.focusWord.plain != '') {
				obj.changed = obj.focusWord;
			}
			else {
				obj.changed = null;
			}
			break;

// replaceall: selection / whole
		case 'findall':
		case 'replaceall':
			if (obj.selection.plain != '') {
				obj.changed = obj.selection;
			}
			else {
				obj.changed = obj.whole;
			}
			break;

//////////////////////////////////
		case 'updown':
			obj.changed = obj.cursor; //dummy
			break;
// jump to position: dummy
		case 'prevpos':
		case 'lastpos':
			obj.changed = obj.cursor; //dummy
			break;

// fixing buttons: selection / whole
		case 'fixbasic':
		case 'fixpunct':
		case 'fixmath':
		case 'fixchem':
		case 'fixunits':
		case 'fixdashes':
		case 'fixhtml':
		case 'fixcaps':
		case 'fixall':
			if (obj.selection.plain != '') {
				obj.changed = obj.selection;
			}
			else {
				obj.changed = obj.whole;
			}
			break;

// fixing buttons: selection, focusLine
		case 'fixpipes':
			if (obj.selection.plain != '') {
				obj.changed = obj.selection;
			}
			else {
				obj.changed = obj.focusLine;
			}
			break;

// source on / off: selection / whole
		case 'sourceon':
		case 'sourceoff':
//			if (obj.selection.plain != '') {
//				obj.changed = obj.selection;
//			}
//			else {
				obj.changed = obj.whole;
//			}
			break;

// unknown edit function
		default:
			alert('Unknown edit function \'' + whichButton + '\'');
	}

	if (obj.changed != null) {

// convert strange spaces
//		obj.changed.plain = obj.changed.plain.replace(/[\t\v\u2028\u2029]+/g, ' ');
//		obj.changed.plain = obj.changed.plain.replace(/[\r\f]/g, '');
	}
	
// exit
	if (obj.changed == null) {
		frameWindow.focus();
		return;
	}

// set local syntax highlighting flag
	var highlightSyntaxEdit = highlightSyntax;

// manipulate the text
	var selectChange = true;
	switch (whichButton) {

// undo
		case 'undo':
			FrameExecCommand('undo');
			obj.changed = null;
			break;

// redo
		case 'redo':
			inputElement['find'].value = FrameExecCommand('redo');
			obj.changed = null;
			break;

// bold
		case 'bold':
			if ( /\'\'\'([^\'].*?)\'\'\'/.test(obj.changed.plain) ) {
				obj.changed.plain = obj.changed.plain.replace(/\'\'\'([^\'].*?)\'\'\'/g, '$1');
			}
			else {
				obj.changed.plain = '\'\'\'' + obj.changed.plain + '\'\'\'';
				obj.changed.plain = obj.changed.plain.replace(/(\'\'\')( *)(.*?)( *)(\'\'\')/, '$2$1$3$5$4');
			}
			break;

// italic
		case 'italic':
			if ( /\'\'([^\'].*?)\'\'/.test(obj.changed.plain) ) {
				obj.changed.plain = obj.changed.plain.replace(/\'\'([^\'].*?)\'\'/g, '$1');
			}
			else {
				obj.changed.plain = '\'\'' + obj.changed.plain + '\'\'';
				obj.changed.plain = obj.changed.plain.replace(/(\'\')( *)(.*?)( *)(\'\')/, '$2$1$3$5$4');
			}
			break;

// underline
		case 'underline':
			if ( /&lt;u&gt;(.*?)&lt;\/u&gt;/i.test(obj.changed.plain) ) {
				obj.changed.plain = obj.changed.plain.replace(/&lt;u&gt;(.*?)&lt;\/u&gt;/g, '$1');
			}
			else {
				obj.changed.plain = '&lt;u&gt;' + obj.changed.plain + '&lt;\/u&gt;';
				obj.changed.plain = obj.changed.plain.replace(/(&lt;u&gt;)( *)(.*?)( *)(&lt;\/u&gt;)/, '$2$1$3$5$4');
			}
			break;

// superscript
		case 'sup':
			if ( /&lt;sup&gt;(.*?)&lt;\/sup&gt;/i.test(obj.changed.plain) ) {
				obj.changed.plain = obj.changed.plain.replace(/&lt;sup&gt;(.*?)&lt;\/sup&gt;/g, '$1');
			}
			else {
				obj.changed.plain = '&lt;sup&gt;' + obj.changed.plain + '&lt;/sup&gt;';
				obj.changed.plain = obj.changed.plain.replace(/(&lt;sup&gt;)( *)(.*?)( *)(&lt;\/sup&gt;)/, '$2$1$3$5$4');
			}
			break;

// subscript
		case 'sub':
			if ( /&lt;sub&gt;(.*?)&lt;\/sub&gt;/i.test(obj.changed.plain) ) {
				obj.changed.plain = obj.changed.plain.replace(/&lt;sub&gt;(.*?)&lt;\/sub&gt;/g, '$1');
			}
			else {
				obj.changed.plain = '&lt;sub&gt;' + obj.changed.plain + '&lt;/sub&gt;';
				obj.changed.plain = obj.changed.plain.replace(/(&lt;sub&gt;)( *)(.*?)( *)(&lt;\/sub&gt;)/, '$2$1$3$5$4');
			}
			break;

// toggle lowercase / uppercase
		case 'case':

// lowercase all uppercased text
			if (obj.changed.plain.toUpperCase() == obj.changed.plain) {
				obj.changed.plain = obj.changed.plain.toLowerCase();
			}

// first-letter-uppercase all lowercased text
			else if (obj.changed.plain.toLowerCase() == obj.changed.plain) {
				obj.changed.plain = obj.changed.plain.replace(/\b(\w)(\w*)/g,
					function (p, p1, p2) {
						return(p1.toUpperCase() + p2.toLowerCase());
					}
				);
			}

// uppercase mixed upper and lowercased text
			else {
				obj.changed.plain = obj.changed.plain.toUpperCase();
			}
			break;

		case 'undoall':
			obj.changed.plain = editformOrig;
			break;
		case 'redoall':
			if (editformLast != null) {
				obj.changed.plain = editformLast;
			}
			break;

// update syntax highlighting
		case 'update_syntax':
			highlightSyntaxEdit = true;
			break;

// various editing buttons
		case 'wikilink':
			if ( /\[\[(.*?)\]\]/.test(obj.changed.plain) ) {
				obj.changed.plain = obj.changed.plain.replace(/\[\[(.*?)\]\]/g, '$1');
			}
			else {
				obj.changed.plain = '\[\[' + obj.changed.plain + '\]\]';
				obj.changed.plain = obj.changed.plain.replace(/(\[\[)( *)(.*?)( *)(\]\])/, '$2$1$3$5$4');
			}
			break;
		case 'weblink':
			if ( /\[(.*?)\]/.test(obj.changed.plain) ) {
				obj.changed.plain = obj.changed.plain.replace(/\[(.*?)\]/g, '$1');
			}
			else {
				obj.changed.plain = '\[' + obj.changed.plain + '\]';
				obj.changed.plain = obj.changed.plain.replace(/(\[)( *)(.*?)( *)(\])/, '$2$1$3$5$4');
			}
			break;
		case 'headingless':
			obj.changed.plain = obj.changed.plain.replace(/(^|\n)=(=+) *([^\n]*?) *=+(?=\n|$)/g, '$1$2 $3 $2'); // decrease heading
			obj.changed.plain = obj.changed.plain.replace(/(^|\n)=(?!=) *([^\n]*?) *=+(?=\n|$)/g, '$1$2'); // remove heading
			obj.changed.plain = obj.changed.plain.replace(/(^|\n)(=+) *([^\n]*?) *=+(?=\n|$)/g, '$1$2 $3 $2'); // adjust closing tags
			break;
		case 'headingmore':
			obj.changed.plain = obj.changed.plain.replace(/(^|\n)(=+) *([^\n]*?) *=+(?=\n|$)/g, '$1=$2 $3 $2='); // increase heading
			obj.changed.plain = obj.changed.plain.replace(/(^|\n)([^=\n\s][^\n]*?)(?=\n|$)/g, '$1== $2 =='); // create new heading
			obj.changed.plain = obj.changed.plain.replace(/(^|\n)(=+) *([^\n]*?) *=+(?=\n|$)/g, '$1$2 $3 $2'); // adjust closing tags
			break;
		case 'bulletlist':
			obj.changed.plain = obj.changed.plain.replace(/(^|\n) +(?=\n)/g, '$1');
			obj.changed.plain = obj.changed.plain.replace(/(^|\n)([\*\#\:\;]*) */g, '$1*$2 ');
			obj.changed.plain = obj.changed.plain.replace(/(^|\n)(\*{4,})([\*\#\:\;]*) */g, '$1$3 ');
			break;
		case 'numberlist':
			obj.changed.plain = obj.changed.plain.replace(/(^|\n) +(?=\n)/g, '$1');
			obj.changed.plain = obj.changed.plain.replace(/(^|\n)([\*\#\:\;]*) */g, '$1#$2 ');
			obj.changed.plain = obj.changed.plain.replace(/(^|\n)(\#{4,})([\*\#\:\;]*) */g, '$1$3 ');
			break;
		case 'indentlist':
			obj.changed.plain = obj.changed.plain.replace(/(^|\n) +(?=\n)/g, '$1');
			obj.changed.plain = obj.changed.plain.replace(/(^|\n)([\*\#\:\;]*) */g, '$1:$2 ');
			obj.changed.plain = obj.changed.plain.replace(/(^|\n)(\:{4,})([\*\#\:\;]*) */g, '$1$3 ');
			break;
		case 'deflist':
			obj.changed.plain = obj.changed.plain.replace(/(^|\n) +(?=\n)/g, '$1');
			obj.changed.plain = obj.changed.plain.replace(/(^|\n) *([^\n\s\;]+) *([^\n]+?)/g, '$1; $2 : $3');
			break;
		case 'image':
			if (obj.changed.plain != '') {
				obj.changed.plain = '[[Image:<span class="wikEdInsertHere">filename</span>|thumb|<span class="wikEdInsertHere">width</span>px|' + obj.changed.plain + ']]';
			}
			else {
				obj.changed.plain = '[[Image:<span class="wikEdInsertHere">filename</span>|thumb|<span class="wikEdInsertHere">width</span>px|<span class="wikEdInsertHere"> </span>]]';
				if (obj.focusWord.plain != '') {
					obj.changed.plain = ' ' + obj.changed.plain + ' ';
				}
			}
			break;
		case 'table':
			if (obj.changed.plain != '') {
				obj.changed.plain = obj.changed.plain.replace(/(^|\n) */g, '\n|-\n| ');
				obj.changed.plain = obj.changed.plain.replace(/^\n\|\-\n/, '\n{| {{Prettytable}}\n');
				obj.changed.plain = obj.changed.plain.replace(/$/g, '\n|}\n');
			}
			else {
				obj.changed.plain = '\n{| {{Prettytable}}\n|+ <span class="wikEdInsertHere">caption</span>\n! <span class="wikEdinserthere">heading</span> !! <span class="wikEdInsertHere">heading</span>\n|-\n| <span class="wikEdInsertHere">cell</span> || <span class="wikEdInsertHere">cell</span>\n|-\n| <span class="wikEdInsertHere">cell</span> || <span class="wikEdInsertHere">cell</span>\n|}\n';
				if (obj.focusLine.plain != '') {
					obj.changed.plain = '\n' + obj.changed.plain + '\n';
				}
			}
			break;

// wikify: always done above
		case 'wikify':
			break;

// textify: strip html from pasted content
		case 'textify':
			var objTextify = {};

// get inner html without wikifying
			if (obj.changed.from == 'whole') {
				GetInnerHTML(objTextify, frameBody);
			}
			else {
				obj.selection.range = obj.sel.getRangeAt(obj.sel.rangeCount - 1);
				var documentFragment = obj.selection.range.cloneContents();
				GetInnerHTML(objTextify, documentFragment);
			}

// convert html to plain
			obj.changed.plain = objTextify.html;
			obj.changed.plain = obj.changed.plain.replace(/\n/g, '');

// delete tags
			obj.changed.plain = obj.changed.plain.replace(/<(style)\b[^>]*>.*?<\/\1>/g, '');

// newlines
			obj.changed.plain = obj.changed.plain.replace(/<(br)\b.*?>/g, '\n');

// blocks
			obj.changed.plain = obj.changed.plain.replace(/<\/?(address|blockquote|center|div|h1|h2|h3|h4|h5|h6|hr|isindex|p|pre)\b.*?>/g, '\n\n');

// lists
			obj.changed.plain = obj.changed.plain.replace(/<\/?(dir|dl|menu|ol|ul)\b.*?>/g, '\n');
			obj.changed.plain = obj.changed.plain.replace(/<\/(dd|dt|li)>/g, '\n');

// forms
			obj.changed.plain = obj.changed.plain.replace(/<\/?(select|textarea)\b.*?>/g, '\n');
			obj.changed.plain = obj.changed.plain.replace(/<\/(option|legend|optgroup)>/g, '\n');

// table
			obj.changed.plain = obj.changed.plain.replace(/<\/?(table|caption)\b.*?>/g, '\n');
			obj.changed.plain = obj.changed.plain.replace(/<\/(tr|th|td)>/g, '\n');

// finish html to plain conversion
			obj.changed.plain = obj.changed.plain.replace(/<.*?>/g, '');
			obj.changed.plain = obj.changed.plain.replace(/\t|\u00a0|&nbsp;/g, ' ');
			obj.changed.plain = obj.changed.plain.replace(/\n +/g, '\n');
			obj.changed.plain = obj.changed.plain.replace(/\n{3,}/g, '\n\n');
			obj.changed.plain = obj.changed.plain.replace(/^\n{2,}|\n{2,}$/g, '\n');
			obj.changed.plain = obj.changed.plain.replace(/\n/g, '<br>');
			break;

// redirect
		case 'redirect':
			var linkTarget;
			if (obj.selectionWord.plain != '') {
				linkTarget = obj.selectionWord.plain;
			}
			else {
				linkTarget = '<span class="wikEdInsertHere">article link</span>';
			}

// remove leading and trailing spaces
			linkTarget = linkTarget.replace(/^\s+|\s+$/g, '');

// remove link text
			linkTarget = linkTarget.replace(/\|.*?(\]|$)/g, '$1');

// remove square brackets
			linkTarget = linkTarget.replace(/\[|\]/g, '');
			
// remove link leftovers
			linkTarget = linkTarget.replace(/ +\| +/g, ' ');
			
			obj.changed.plain = '#redirect [[' + linkTarget + ']]';

			if (inputElement['summary'].value == '') {
				inputElement['summary'].value = '#redirect [[' + linkTarget + ']]';
			}
			selectChange = false;
			break;

// copy selection to find field
		case 'getfind':
			inputElement['find'].value = obj.changed.plain;
			obj.changed = null;
			break;

// copy selection to find and to replace field
		case 'getfindreplace':
			inputElement['find'].value = obj.changed.plain;
			inputElement['replace'].value = obj.changed.plain;
			obj.changed = null;
			break;

// find and replace
		case 'findprev':
		case 'findnext':
		case 'replaceprev':
		case 'replacenext':
		case 'findall':
		case 'replaceall':

// get the find text
			var findText = obj.changed.plain;
			if (findText == '') {
				obj.changed = null;
				break;
			}

// get the replace text
			var replaceText = inputElement['replace'].value;

// get the find and replace checkbutton states
			var caseSensitive = document.getElementById('caseSensitive');
			var regExp = document.getElementById('regExp');
			var findAhead = document.getElementById('findAhead');

// use the fast built-in find function for non-regexp searches
			if ( (regExp.checked == false) && ( (whichButton == 'findnext') || (whichButton == 'findprev') ) ) {

// get direction
				var backwards = false;
				if (whichButton == 'findprev') {
					backwards = true;
				}

// function: window.find(string, caseSensitive, backwards, wrapAround, wholeWord, searchInFrames, showDialog)
				var found = frameWindow.find(findText, caseSensitive, backwards, false, false, false, false);
				if (found == false) {
					obj.changed.range.collapse(backwards);
					obj.changed.plain = null;
				}
				else {
					obj.changed = null;
				}
			}
			
// slow javascript regexp find and replace
			else {

// format the find and replace texts as regexp or plain text
				if (regExp.checked == false) {
					findText = findText.replace(/([\\^\$\*\+\?\.\(\)\[\]\{\}\:\=\!\|\,\-])/g, '\\$1');
				}

// replace \n with newline character
				else {
					replaceText = replaceText.replace(/((^|[^\\])(\\\\)*)\\n/g, '$1\n');
				}

// set regexp flags
				var regExpFlags = 'g';
				if ( ! caseSensitive.checked ) {
					regExpFlags += 'i';
				}

// create regexp
				var regExpFind = new RegExp(findText, regExpFlags);

// replace all
				var replacedFlag = false;
				if (whichButton == 'replaceall') {
					if (regExpFind.test(obj.changed.plain)) {
						obj.changed.plain = obj.changed.plain.replace(regExpFind, replaceText);
						replacedFlag = true;
					}
					else {
						obj.changed.plain = null;
					}
				}

// find all
				if (whichButton == 'findall') {
////////////////////////// set selection with multiple ranges
					obj.changed = null;
					break;
				}

// replace an existing selection
				else if ( (whichButton == 'replaceprev') || (whichButton == 'replacenext') ) {
					if (regExpFind.test(obj.selection.plain)) {
						obj.changed.plain = obj.selection.plain.replace(regExpFind, replaceText);
						replacedFlag = true;
					}
					else {
						obj.changed.plain = null;
					}
				}
				else if ( (whichButton == 'findnext') || (whichButton == 'findprev') ) {
					obj.changed.plain = null;
				}
	
// perform find
				if (replacedFlag == false) {
					ParseDOM(obj, frameBody);
					var result = [];
	
// find next, search to the right
					if ( (whichButton == 'findnext') || (whichButton == 'replacenext') ) {
	
// set start position for search to right
						regExpFind.lastIndex = obj.plainFocus;
	
// execute the regexp search to the right
						result = regExpFind.exec(obj.plain);
	
// collapse the selection to its end for no find
						if (result == null) {
							var range = obj.sel.getRangeAt(obj.sel.rangeCount - 1);
							obj.changed.range.setEnd(range.endContainer, range.endOffset);
							obj.changed.range.collapse(false);
						}
					}
	
// find previous, search to the left
					else if ( (whichButton == 'findprev') || (whichButton == 'replaceprev') ) {
	
// cycle through the matches to the left
						var resultNext;
						do {
							result = resultNext;
							resultNext = regExpFind.exec(obj.plain);
							if (resultNext == null) {
								break;
							}
						} while (resultNext.index < obj.plainAnchor);
	
// collapse the selection to its start for no find
						if (result == null) {
							var range = obj.sel.getRangeAt(obj.sel.rangeCount - 1);
							obj.changed.range.setStart(range.startContainer, range.startOffset);
							obj.changed.range.collapse(true);
						}
					}
	
// select the find
					if (result != null) {
	
// make changed range text the next selection
						i = 0;
						while ( (obj.plainStart[i + 1] <= result.index) && (obj.plainStart[i + 1] != null) ) {
							i ++;
						}
						j = i;
						while ( (obj.plainStart[j + 1] <= result.index + result[0].length) && (obj.plainStart[j + 1] != null) ) {
							j ++;
						}
						obj.changed.range.setStart(obj.plainNode[i], result.index - obj.plainStart[i]);
						obj.changed.range.setEnd  (obj.plainNode[j], result.index + result[0].length - obj.plainStart[j]);
					}
				}
			}
			
// save search history to cookie
			if ( (whichButton == 'findprev') || (whichButton == 'findnext') ) {
				AddToHistory('find');
			}
			if ( (whichButton == 'replaceprev') || (whichButton == 'replacenext') || (whichButton == 'replaceall') ) {
				AddToHistory('find');
				AddToHistory('replace');
			}
			break;

// jump to top or bottom
		case 'updown':

// jump to bottom
/////////////////////// also check which is closer!!!!!
			if ( (obj.cursor.range.startContainer == frameBody) && (obj.cursor.range.startOffset == 0) ) {
				obj.changed.range.setEndAfter(frameBody.lastChild);
				obj.changed.range.collapse(false);
				frameBody.scrollTop = frameBody.scrollHeight;
			}

// jump to top
			else {
				obj.changed.range.setStartBefore(frameBody.firstChild);
				obj.changed.range.collapse(true);
				frameBody.scrollTop = 0;
			}
			obj.changed.plain = null;
			break;

// jump to previously changed position
		case 'prevpos':
			if ( frameDocument.queryCommandEnabled('undo') ) {
				FrameExecCommand('undo');
				FrameExecCommand('redo');
				lastPosObj = obj.cursor;
			}
			obj.changed = null
			break;

// jump back to last position
		case 'lastpos':
			if (lastPosObj != null) {
				obj.changed = lastPosObj;
				lastPosObj = null;
				obj.changed.plain = null;
			}
			else {
				obj.changed = null;
			}
			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 'fixbasic':
			FixBasic(obj.changed);
			break;

// fixpipes: add spaces around pipes in wikilinks and templates (good for link lists)
		case 'fixpipes':
			FixPipes(obj.changed);
			break;
		case 'fixpunct':
			FixPunct(obj.changed);
			break;
		case 'fixmath':
			FixMath(obj.changed);
			break;
		case 'fixchem':
			FixChem(obj.changed);
			break;
		case 'fixunits':
			FixUnits(obj.changed);
			break;
		case 'fixdashes':
			FixDashes(obj.changed);
			break;
		case 'fixhtml':
			FixHTML(obj.changed);
			break;
		case 'fixcaps':
			FixCaps(obj.changed);
			break;
		case 'fixall':
			FixAll(obj.changed);
			break;

// source on
		case 'sourceon':
			obj.changed.plain = obj.changed.plain.replace(/&lt;br&gt;/g, '');
			obj.changed.plain = obj.changed.plain.replace(/&/g, '&amp;');
			obj.changed.plain = obj.changed.plain.replace(/\n/g, '&lt;br&gt;\n');
			highlightSyntaxEdit = false;
			break;

// source off
		case 'sourceoff':
			obj.changed.plain = obj.changed.plain.replace(/&lt;br&gt;\n/gi, '\n');
			obj.changed.plain = obj.changed.plain.replace(/&amp;/g, '&');
			break;

		default:
			alert('Unknown edit function \'' + whichButton + '\'');
	}

// exit
	if (obj.changed == null) {
		frameWindow.focus();
		return;
	}

// update the selection only
	if (obj.changed.plain == null) {
		obj.sel.removeAllRanges();
		obj.sel.addRange(obj.changed.range);
	}

// apply text changes
	else {

// save last version for redo all
		switch (whichButton) {
			case 'undo':
			case 'redo':
			case 'undoall':
			case 'redoall':
				if (editformLast == null) {
					editformLast = obj.changed.plain;
				}
				break;
			default:
				editformLast = null; /////////////////  also after every key click

// highlight syntax
			obj.changed.plain = obj.changed.plain.replace(/\n/g, '<br>');
			obj.html = obj.changed.plain;
			if (highlightSyntaxEdit == true) {
				HighlightSyntax(obj, true);
			}

// make changed range text the current selection
			obj.sel.removeAllRanges();
			obj.sel.addRange(obj.changed.range);

// replace the selection with changed text
			if (obj.html != '') {
				FrameExecCommand('inserthtml', obj.html);
			}
			else {
				FrameExecCommand('delete');
			}

// get the text content of the changed text
			var div = document.createElement('div');
			div.innerHTML = obj.changed.plain;
			var plainText = div.textContent;

// select the changed text by using a backwards find
			if (selectChange != false) {
				if (plainText.length > 0) {

// function: window.find(string, caseSensitive, backwards, wrapAround, wholeWord, searchInFrames, showDialog)
					frameWindow.find(plainText, true, true, false, false, false, false);
				}
			}
		}
	}

// focus the frame
	frameWindow.focus();

	return;
}


//
// FixBasic: fix characters, spaces, empty lines, certain headings, needed for all fixing functions
//

function FixBasic(obj) {

// non-breaking space character to normal space
	obj.plain = obj.plain.replace(/(\u00a0)/g, ' ');

// remove trailing spaces
	obj.plain = obj.plain.replace(/( |&nbsp;)+\n/g, '\n');

// empty line before and after headings, spaces around word (lookahead)
	obj.plain = obj.plain.replace(/\n+(={2,}) *([^\n]*?) *(={2,})(?=\n)\n*/g, '\n\n$1 $2 $3\n\n');

// uppercase well known headings
	obj.plain = obj.plain.replace(/\n== external links? ==\n/ig, '\n== External links ==\n');
	obj.plain = obj.plain.replace(/\n== see also ==\n/ig, '\n== See also ==\n');
	obj.plain = obj.plain.replace(/\n== references? ==\n/ig, '\n== References ==\n');

// add space after * # : ; (list) and after {| |- | (table)
	obj.plain = obj.plain.replace(/(^|\n)([\*\#\:\;]+|\{\||\|\-|\|\}|\|) */g, '$1$2 ');
	obj.plain = obj.plain.replace(/ +\n/g, '\n');

// empty line before and after tables
	obj.plain = obj.plain.replace(/\n+(\{\|)/g, '\n\n$1');
	obj.plain = obj.plain.replace(/(\n\|\}) *([^\n]*)[\n|$]+/g, '$1\n\n$2\n\n');

// empty line before and after lists
	obj.plain = obj.plain.replace(/(^|\n)([^\*\#\:\;].*?)\n+([\*\#\:\;])/g, '$1$2\n\n$3');
	obj.plain = obj.plain.replace(/(^|\n)([\*\#\:\;].*?)\n+([^\*\#\:\;])/g, '$1$2\n\n$3');

// split into lines and change single lines, used to handle tables
	var lines = obj.plain.split('\n');
	obj.plain = '';
	var tableflag = false;
	for (var i = 0; i < lines.length; i++) {
		var line = lines[i];

// do not change lines starting with a blank
		if ( ! line.match(/^ /) ) {

// detect table
			if ( line.match(/^(\{\||\!|\|[^}])/) ) {
				tableflag = true;
			}
			else if ( line.match(/^\|\}/) ) {
				tableflag = false;
			}

// changes only to be done in tables
			if (tableflag) {

// add spaces around ||
				line = line.replace(/ *\|\| */g, ' || ');
			}

// changes not to be done in tables
			if ( ! tableflag) {

// empty line before and after images
				line = line.replace(/^(\[\[image:.*?\]\])/ig, '\n$1');
				line = line.replace(/(\[\[image:.*?(\[\[.*?\]\].*?)*\]\])$/ig, '$1\n');

// empty line before and after includes
				line = line.replace(/^(\{\{.*?\}\})/g, '\n$1');
				line = line.replace(/(\{\{.*?\}\})$/g, '$1\n');

// to be done: convert single newlines into spaces
//      line = line.replace(/(\n[^\n \*\#\:\;\|\{].*?)\n([^\n \*\#\:\;\|\{])/g, '$1 $2');
			}
		}

// concatenate the lines
		obj.plain += line;
		if (i < lines.length - 1) {
			obj.plain += '\n';
		}
	}

// remove spaces in wikilinks
	obj.plain = obj.plain.replace(/\[\[ *([^\n]*?) *\]\]/g, '[[$1]]');

// remove spaces in external links
	obj.plain = obj.plain.replace(/\[ *([^\n]*?) *\]/g, '[$1]');

// no space around pipes before brackets
	obj.plain = obj.plain.replace(/ +\| +\]\]/g, '|]]');

// no space around pipes before curly brackets
	obj.plain = obj.plain.replace(/ +\| +\}\}/g, '|}}');

// no empty line between headings and includes
	obj.plain = obj.plain.replace(/\n(==+ [^\n]*? ==+\n)\n+(\{\{.*?\}\})/g, '\n$1$2');

// spaces in comments
	obj.plain = obj.plain.replace(/(<!--) *([^\n]*?) *(-->)/g, '$1 $2 $3');

// empty lines around html comments
	obj.plain = obj.plain.replace(/\n+(<!--.*?-->)\n+/g, '\n$1\n\n');
	obj.plain = obj.plain.replace(/^(<!--.*?-->)\n+/g, '$1\n');
	obj.plain = obj.plain.replace(/\n+(<!--.*?-->)$/g, '\n$1');

// empty line before and after categories
	obj.plain = obj.plain.replace(/( |\n)*(\[\[category:[^\n]*?\]\])( |\n)*/gi, '\n\n$2\n\n');

// categories not separated by empty lines (lookahead)
	obj.plain = obj.plain.replace(/(\[\[category:[^\n]*?\]\])\n*(?=\[\[category:[^\n]*?\]\])/gi, '$1\n');

// single empty lines only
	obj.plain = obj.plain.replace(/\n{3,}/g, '\n\n');

// remove leading and trailing newlines
	obj.plain = obj.plain.replace(/^\n+/, '');
	obj.plain = obj.plain.replace(/\n{2,}$/, '\n');

	return;
}


//
// FixPipes: add spaces around pipes in wikilinks and templates (good for link lists)
//

function FixPipes(obj) {
	FixBasic(obj);
	obj.plain = obj.plain.replace(/(\[\[(?!image:)[^\n]+?) *\| *(.*?\]\])/ig, '$1 | $2');
	obj.plain = obj.plain.replace(/(\{\{)([^\n]+?)(\}\})/g,
		function (p, p1, p2, p3) {
			p2 = p2.replace(/ *(\|) */g, ' | ');
			return(p1 + p2 + p3);
		}
	);
	return;
}


//
// FixPunct: remove space before .,:
//

function FixPunct(obj) {
	FixBasic(obj);

// ; could be a definition
	obj.plain = obj.plain.replace(/([a-zA-Z\'\"\”\]\}\)]) +([\.\,\:])/g, '$1$2');

	return;
}


//
// FixMath: math character fixer, originally from User:Omegatron
//

function FixMath(obj) {

	FixBasic(obj);

// change only outside <math> </math> wikicode
	obj.plain = obj.plain.replace(/(.*?)<math(\b[^>]*)?>.*?<\/math>/gi,
		function (p, p1) {

// convert html entities into actual dash characters
			p1 = p1.replace(/&minus;/g, '\u2212');
			p1 = p1.replace(/&middot;/g, '·');

// convert dash next to a number into a minus sign character
			p1 = p1.replace(/([^a-zA-Z0-9\,\_\{])-(\d)/g, '$1\u2212$2');

// changes 2x3 to 2×3
			p1 = p1.replace(/(\d ?)x( ?\d)/g, '$1×$2');

// changes 10^3 to 10<sup>3</sup>
			p1 = p1.replace(/(\d*\.?\d+)\^(\u2212?\d+\.?\d*)/g, '$1<sup>$2</sup>');

// change x^3 to x<sup>3</sup>
			p1 = p1.replace(/([0-9a-zA-Z])\^(\u2212?\d+\.?\d*) /g, '$1<sup>$2</sup>');

// change +/- to ±
			p1 = p1.replace(/( |\d)\+\/(-|\u2212)( |\d)/g, '$1±$3');
			return(p1);
		}
	);
	return;
}


//
// FixChem: fix chemical formulas
//

function FixChem(obj) {

	FixBasic(obj);
/*

	var realElements = 'H|He|Li|Be|B|C|N|O|F|Ne|Na|Mg|Al|Si|P|S|Cl|Ar|K|Ca|Sc|Ti|V|Cr|Mn|Fe|Co|Ni|Cu|Zn|Ga|Ge|As|Se|Br|Kr|Rb|Sr|Y|Zr|Nb|Mo|Tc|Ru|Rh|Pd|Ag|Cd|In|Sn|Sb|Te|I|Xe|Cs|Ba|Hf|Ta|W|Re|Os|Ir|Pt|Au|Hg|Tl|Pb|Bi|Po|At|Rn|Fr|Ra|Rf|Db|Sg|Bh|Hs|Mt|Ds|Rg|La|Ce|Pr|Nd|Pm|Sm|Eu|Gd|Tb|Dy|Ho|Er|Tm|Yb|Lu|Ac|Th|Pa|U|Np|Pu|Am|Cm|Bk|Cf|Es|Fm|Md|No|Lr';
  var pseudoElements = '|D|T|Me|Et|Pr|Bu';
  
// fix formulas
	obj.plain = obj.plain.replace('/(\d*)(\s*)(((' + elements + pseudoElements')(&lt;sub&gt;)?(\d*)(&lt;\/sub&gt;)?)+)|[\(\)\[\]\-\=])\b/g',
		
		function (p, p1, p2, p3, p4, p5, p6) {
			
			var whole = p1 + p2 + p3;
			var prefixNumber = p1 + 0;
			var formula = p3;     
//			
      if (not one real element) {
      	return(whole);
      }

      
// clean prefix
			prefix = prefix.replace(/0*(\d+)/g, '$1');

// subscript and clean indices
			formula = formula.replace(/(&lt;sub&gt;)?0*(\d+)(&lt;\/sub&gt;)?/g, '&lt;sub&gt;$2&lt;\/sub&gt;');

			return(prefix + ' ' + formula);
		}
	);
*/
	return;
}


//
// FixUnits: unit formatter - new tab adds spaces between number and units, makes units consistent
// originally from User:Omegatron
//

function FixUnits(obj) {
	FixBasic(obj);

// convert all &deg; into actual ° symbol
	obj.plain = obj.plain.replace(/&deg;/g, '°');

// convert the word ohm(s) or the html entity into the actual Omega symbol (not the actual ohm symbol &#8486;) and make sure it's spaced
	obj.plain = obj.plain.replace(/(\d) ?(Y|Z|E|P|T|G|M|k|K|h|da|d|c|m|&mu;|µ|&micro;|n|p|f|a|z|y)? ?(&Omega;|&#8486;|(ohm|Ohm)s?)([\s.,:;\'\"\/\)])/g, '$1 $2\u03a9$5');

// convert various micro symbols into the actual micro symbol, make sure it's spaced
	obj.plain = obj.plain.replace(/(\d) ?(&mu;|&micro;)(g|s|m|A|K|mol|cd|rad|sr|Hz|N|J|W|Pa|lm|lx|C|V|O|F|Wb|T|H|S|Bq|Gy|Sv|kat|°C|M)([\s.,:;\'\"\/\)])/g, '$1 µ$3$4');

// convert capital K to lowercase k in units
	obj.plain = obj.plain.replace(/(\d) ?K(g|s|m|A|K|mol|cd|rad|sr|Hz|N|J|W|Pa|lm|lx|C|V|O|F|Wb|T|H|S|Bq|Gy|Sv|kat|°C|M)([\s.,:;\'\"\/\)])/g, '$1 k$2$3');

// capitalize units correctly
	obj.plain = obj.plain.replace(/(\d) ?(khz)([ ,.])/gi, '$1 kHz$3');
	obj.plain = obj.plain.replace(/(\d) ?(mhz)([ ,.])/gi, '$1 MHz$3');
	obj.plain = obj.plain.replace(/(\d) ?(ghz)([ ,.])/gi, '$1 GHz$3');
	obj.plain = obj.plain.replace(/(\d) ?(Y|Z|E|P|T|G|M|k|K|h|da|d|c|m|&mu;|µ|&micro;|n|p|f|a|z|y)?(hz|HZ)([\s.,:;\'\"\/\)])/g, '$1 $2Hz$4');
	obj.plain = obj.plain.replace(/(\d) ?(Y|Z|E|P|T|G|M|k|K|h|da|d|c|m|&mu;|µ|&micro;|n|p|f|a|z|y)?(pa|PA)([\s.,:;\'\"\/\)])/g, '$1 $2Pa$4');

// add a space before dB
	obj.plain = obj.plain.replace(/(\d) ?(dB)([\s.,:;\'\"\/\)])/g, '$1 $2$3');

// add a space before any units that were missed before
	obj.plain = obj.plain.replace(/(\d) ?(Y|Z|E|P|T|G|M|k|K|h|da|d|c|m|&mu;|µ|&micro;|n|p|f|a|z|y)?(g|m|A|K|mol|cd|rad|sr|Hz|N|J|W|Pa|lm|lx|C|V|O|F|Wb|T|H|S|Bq|Gy|Sv|kat|°C|M)([\s.,:;\'\"\/\)])/g, '$1 $2$3$4');

// separate one for seconds since they give a lot of false positives like "1970s". Only difference is mandatory prefix.
	obj.plain = obj.plain.replace(/(\d) ?(Y|Z|E|P|T|G|M|k|K|h|da|d|c|m|&mu;|µ|&micro;|n|p|f|a|z|y)(s)([\s.,:;\'\"\/\)])/g, '$1 $2$3$4');

// bps or b/s or bits/s --> bit/s
	obj.plain = obj.plain.replace(/([KkMmGgTtPpEeYyZz])(bps|bits?\/s|b\/s)/g, '$1bit/s');

// Bps or byte/s or bytes/s --> B/s
	obj.plain = obj.plain.replace(/([KkMmGgTtPpEeYyZz])(Bps|bytes?\/s)/g, '$1B/s');

// after that, make capitalization correct
	obj.plain = obj.plain.replace(/K(bit|B)\/s/g, 'k$1/s');
	obj.plain = obj.plain.replace(/m(bit|B)\/s/g, 'M$1/s');
	obj.plain = obj.plain.replace(/g(bit|B)\/s/g, 'G$1/s');
	obj.plain = obj.plain.replace(/t(bit|B)\/s/g, 'T$1/s');
	obj.plain = obj.plain.replace(/e(bit|B)\/s/g, 'E$1/s');
	obj.plain = obj.plain.replace(/y(bit|B)\/s/g, 'Y$1/s');
	obj.plain = obj.plain.replace(/z(bit|B)\/s/g, 'Z$1/s');

// fix a common error
	obj.plain = obj.plain.replace(/mibi(bit|byte)/g, 'mebi$1');

	return;
}


//
// FixDashes: dash fixer - adds a tab that fixes several obvious en/em dash, minus sign, and such special characters.
// originally from User:Omegatron
//

function FixDashes(obj) {
	FixBasic(obj);

// convert html entities into actual dash characters
	obj.plain = obj.plain.replace(/&mdash;/g, '—');
	obj.plain = obj.plain.replace(/&ndash;/g, '–');
	obj.plain = obj.plain.replace(/&minus;/g, '\u2212');

// convert -- and em dashes with or without spaces to em dash surrounded by spaces
	obj.plain = obj.plain.replace(/([a-zA-Z\'\"”\]\}\)]) *(--|—|&mdash;) *([a-zA-Z\'\"“\[\{\(])/g, '$1 — $3');

// convert - or en dashes with spaces to em dash character surrounded by spaces
	obj.plain = obj.plain.replace(/([a-zA-Z\'\"”\]\}])( |&nbsp;)+(\u2212|–|&ndash;) +([a-zA-Z\'\"“\[\{])/g, '$1$2— $4');

// convert hyphen next to lone number into a minus sign character
	obj.plain = obj.plain.replace(/([a-zA-Z\'\"”\]\>] )-(\d)/g, '$1\u2212$2');

// convert dashes to en dashes in dates
	obj.plain = obj.plain.replace(/([ \(][12]\d\d\d) ?(--?|—|&mdash;) ?([12]\d\d\d|\d\d)([ \),.;])/g, '$1–$3$4');

	return;
}


//
// FixHTML: fix html to wikicode ///////////////// obsolete, use function below
//

function FixHTML(obj) {
	FixBasic(obj);

// remove syntax highlighting
	obj.html = obj.plain;
	RemoveHighlighting(obj);

// turn visible html code into real html
	obj.html = obj.html.replace(/&lt;/g, '<');
	obj.html = obj.html.replace(/&gt;/g, '>');

// wikify
	WikifyHTML(obj);

// turn real html into visible html code
	obj.html = obj.html.replace(/<br>/g, '\n');
	obj.html = obj.html.replace(/</g, '&lt;');
	obj.html = obj.html.replace(/>/g, '&gt;');
	obj.plain = obj.html;

	return;
}


//
// FixCaps: fix capitalizing of lists, linklists, images, headings
//

function FixCaps(obj) {
	FixBasic(obj);

// uppercase lists
// start (listcode (char-ent|tag|category..|digit|non-word,non-ret))(word,non-digit..) end
	obj.plain = obj.plain.replace(/^([\*\#\:\;]+ (\&\w+\;|\<[^\n]*?\>|\{\{.*?\}\}[^\n]*|\d|[^\w\n])*)([^\W\d].*?)?$/gm,
		function (p, p1, p2, p3) {
			if ( ! p3.match(/^(http|ftp|alpha|beta|gamma|delta|epsilon|kappa|lambda|$)/) ) {
				p3 = p3.substr(0, 1).toUpperCase() + p3.substr(1);
			}
			return(p1 + p3);
		}
	);

// uppercase link lists (link)
	obj.plain = obj.plain.replace(/^([\*\#\:\;]+ \[\[)([^\n]*?)(\]\])/gm,
		function (p, p1, p2, p3) {

// uppercase link
			p2 = p2.replace(/^((\&\w+\;|\W|\d)*)([^\W\d].*)$/,
				function (p, p1, p2, p3) {
					if ( ! p3.match(/^(http|ftp|alpha|beta|gamma|delta|epsilon|kappa|lambda)/) ) {
						p3 = p3.substr(0, 1).toUpperCase() + p3.substr(1);
					}
					return(p1 + p3);
				}
			);

// uppercase comment
			p2 = p2.replace(/(\| *(\&\w+\;|<.*?>|\W|\d)*)([^\W\d].*)$/,
				function (p, p1, p2, p3) {
					if ( ! p3.match(/^(http|ftp|alpha|beta|gamma|delta|epsilon|kappa|lambda)/) ) {
						p3 = p3.substr(0, 1).toUpperCase() + p3.substr(1);
					}
					return(p1 + p3);
				}
			);
			return(p1 + p2 + p3);
		}
	);

// uppercase headings
	obj.plain = obj.plain.replace(/^(==+ (\&\w+\;|<.*?>|\d|[^\w\n])*)([^\W\d].*? ==+)$/gm,
		function (p, p1, p2, p3) {
			if ( ! p3.match(/^(http|ftp|alpha|beta|gamma|delta|epsilon|kappa|lambda)/) ) {
				p3 = p3.substr(0, 1).toUpperCase() + p3.substr(1);
			}
			return(p1 + p3);
		}
	);

// uppercase images
	obj.plain = obj.plain.replace(/(\[\[)image:(\w)([^\n]*\]\])/igm,
		function (p, p1, p2, p3) {
			return(p1 + 'Image:' + p2.toUpperCase() + p3);
		}
	);

	return;
}

//
// FixAll:
//

function FixAll(obj) {
	FixBasic(obj);
	FixUnits(obj);
	FixDashes(obj);
	FixHTML(obj);
	FixCaps(obj);
	return;
}


//
// removeElements: remove elements by tag name
//

function removeElements(tagNameArray) {

// cycle through the element names
	for each (var tagNameStr in tagNameArray) {
		var elementArray = frameDocument.getElementsByTagName(tagNameStr);
		for (i = 0; i < elementArray.length; i ++) {
			elementArray[i].parentNode.removeChild(elementArray[i]);
		}
	}
	return;
}


//
// FindBoundaries: find word boundaries and line boundaries starting from selection.range
//

function FindBoundaries(word, line, whole, selection) {

/*
textareaObj.value = '';
*/

// get the start node and offset
	var startNode = selection.range.startContainer;
	var startNodeOffset = selection.range.startOffset;

// get the end node and offset
	var endNode = selection.range.endContainer;
	var endNodeOffset = selection.range.endOffset;

	if (startNode.nodeType == 1) {
		startNode = startNode.childNodes[startNodeOffset];
		startNodeOffset = 0;
	}
	if (endNode.nodeType == 1) {
		endNode = endNode.childNodes[endNodeOffset];
		endNodeOffset = 0;
	}

// find the start and end nodes in the whole plain text arrays
	var startNodeIndex;
	var endNodeIndex;
	for (i = 0; i < whole.plainArray.length; i ++) {
		if (startNode == whole.plainNode[i]) {
			startNodeIndex = i;
		}
		if (endNode == whole.plainNode[i]) {
			endNodeIndex = i;
			break;
		}
	}

// find last previous word and line boundary
	var foundWord = false;
	var foundLine = false;
	var regExp = new RegExp('.*[^\\w\\-]', 'g');

// check text nodes left-wise for a boundary
	for (i = startNodeIndex; i >= 0; i --) {
		var plain = whole.plainArray[i];

// boundary is a newline
		if (plain == '\n') {

// current newline is the start node
			if (i == startNodeIndex) {
				if (! foundWord) {
					word.range.setStartBefore(whole.plainNode[i]);
					foundWord = true;
				}
				line.range.setStartBefore(whole.plainNode[i]);
			}
			else {
				if (! foundWord) {
					word.range.setStartAfter(whole.plainNode[i]);
					foundWord = true;
				}
				line.range.setStartAfter(whole.plainNode[i]);
			}
			foundLine = true;
			break;
		}

// check text node for a word boundary
		else if (! foundWord) {
			if (i == startNodeIndex) {
				plain = plain.substr(0, startNodeOffset);
			}
			regExp.lastIndex = 0;
			if (regExp.exec(plain) != null) {
				word.range.setStart(whole.plainNode[i], regExp.lastIndex);
				foundWord = true;
			}
		}
	}

// boundary is start of text
	if (! foundLine) {
		line.range.setStartBefore(whole.plainNode[0]);
		if (! foundWord) {
			word.range.setStartBefore(whole.plainNode[0]);
		}
	}

// find next word and line boundary
	regExp = new RegExp('[^\\w\\-]', 'g');
	foundWord = false;
	foundLine = false;

// check text nodes right-wise for a boundary
	for (i = endNodeIndex; i < whole.plainArray.length; i ++) {
		var plain = whole.plainArray[i];

// boundary is a newline
		if (plain == '\n') {
			if (! foundWord) {
				word.range.setEndBefore(whole.plainNode[i]);
				foundWord = true;
			}
			line.range.setEndBefore(whole.plainNode[i]);
			foundLine = true;
			break;
		}

// check text node for a word boundary
		else if (! foundWord) {
			if (i == endNodeIndex) {
				regExp.lastIndex = endNodeOffset;
			}
			else {
				regExp.lastIndex = 0;
			}
			var regExpArray = regExp.exec(plain);
			if (regExpArray != null) {
/*
textareaObj.value = '';
textareaObj.value += 'i: ' + i + '\n';
textareaObj.value += 'whole.plainNode[i]: ' + whole.plainNode[i] + '\n';
textareaObj.value += 'whole.plainNode[i].type: ' + whole.plainNode[i].type + '\n';
textareaObj.value += 'whole.plainNode[i].name: ' + whole.plainNode[i].name + '\n';
textareaObj.value += 'whole.plainNode[i].value: ' + whole.plainNode[i].value + '\n';
textareaObj.value += 'regExpArray.index: ' + regExpArray.index + '\n';
*/
				word.range.setEnd(whole.plainNode[i], regExpArray.index);///////////////////////// error on sourceoff ///////////////////////////////////////

// Error: uncaught exception: [Exception... "Index or size is negative or greater than the allowed amount"
// code: "1" nsresult: "0x80530001 (NS_ERROR_DOM_INDEX_SIZE_ERR)"  location: "file:///C:/editor.js Line: 1713"]

				foundWord = true;
			}
		}
	}

// boundary is end of text
	if (! foundLine) {
		line.range.setEndAfter(whole.plainNode[whole.plainArray.length - 1]);
		if (! foundWord) {
			word.range.setEndAfter(whole.plainNode[whole.plainArray.length - 1]);
		}
	}
	return;
}


//
// remove syntax highlighting and wikify
//

function RemoveHighlightingWikify(obj) {

	if (obj.html != '') {

// remove syntax highlighting
		RemoveHighlighting(obj);

// wikify
		if (obj.htmlCode == true) {
			WikifyHTML(obj);
		}
	}
	return;
}


//
// scroll the textarea if the selected text is outside the viewport
//

function ScrollTextarea(rowStart, rowEnd, lines, margin, scrollTopPx) {

// get top row
	var scrollHeightPx = textareaObj.scrollHeight;
	var scrollTopRow = scrollTopPx / scrollHeightPx * textRows.rowTotal;

// cusor direction: up
	if (lines <= 0) {
	 	if (scrollTopRow > (rowStart + lines) - margin) {
			scrollTopRow = (rowStart + lines) - margin;
			if (scrollTopRow < 0) {
				scrollTopRow = 0;
			}
		}
	}

// cusor direction: down
	if (lines >= 0) {
	 	if (scrollTopRow < (rowEnd + 1 + lines) + margin - textRows.rows) {
			scrollTopRow = (rowEnd + 1 + lines) + margin - textRows.rows;
			if (scrollTopRow > textRows.rowTotal + 1 - textRows.rows) {
				scrollTopRow = textRows.rowTotal + 1 - textRows.rows;
			}
		}
	}

// set scroll position
	textareaObj.scrollTop = scrollTopRow / textRows.rowTotal * scrollHeightPx;

	return;
}


//
// ParseRows: get row structure of textarea
//

function ParseRows() {

	textRows.selStart = textareaObj.selectionStart;
	textRows.selEnd = textareaObj.selectionEnd;

// if the text has not changed we don't need to parse lines and rows
	if (textRows.changed != true) {
		if (textRows.textarea == null) {
			textRows.changed = true;
		}
		else if (textRows.textarea.length != textareaObj.value.length) {
			textRows.changed = true;
		}
		else if (textRows.textarea != textareaObj.value) {
			textRows.changed = true;
		}
	}
	if (textRows.changed) {
		textRows.changed = false
		textRows.textarea = textareaObj.value;
		textRows.cols = textareaObj.cols;
		textRows.rows = textareaObj.rows;

// parse lines
		textRows.lineStart = [];
		textRows.lineLength = [];
		var pos;
		var posNext = 0;
		var line = 0;
		do {
			pos = posNext;
			textRows.lineStart[line] = pos;
			posNext = textRows.textarea.indexOf('\n', pos) + 1;
			textRows.lineLength[line] = posNext - pos - 1;
			line ++;
		} while (posNext > 0);
		textRows.lineLength[line - 1] = textRows.textarea.length - pos;
		textRows.lineTotal = line;

// parse rows
		textRows.rowStart = [];
		textRows.rowLength = [];
		var lineTotal = textRows.lineTotal;
		var row = 0;
		for (line = 0; line < lineTotal; line ++) {
			var rowStart;
			var rowStartNext = textRows.lineStart[line];
			var lineEnd = rowStartNext + textRows.lineLength[line];

// cycle row by row to the end of the line
			do {
				rowStart = rowStartNext;
				pos = 0;
				posNext = rowStart;
				if (rowStart + textRows.cols >= lineEnd) {
					rowStartNext = lineEnd;
				}

// find last space before or first after right border
				else {
					do {
						pos = posNext;
						posNext = textRows.textarea.indexOf(' ', pos + 1);
					} while ( (posNext >= 0) && (posNext <= rowStart + textRows.cols) && (posNext < lineEnd) );
					if (pos > rowStart) {
						rowStartNext = pos + 1;
					}
					else if ( (posNext >= 0) && (posNext < lineEnd) ) {
						rowStartNext = posNext + 1;
					}
					else {
						rowStartNext = lineEnd;
					}
				}

// jump over trailing spaces
				while (textRows.textarea.charAt(rowStartNext) == ' ') {
					rowStartNext ++;
				}

// set row start and length
				textRows.rowStart[row] = rowStart;
				textRows.rowLength[row] = rowStartNext - rowStart;
				row ++;
			} while (rowStartNext < lineEnd);
		}
		textRows.rowTotal = row;
	}

// get text selection rows by stepwise approximation
	var rowTotal = textRows.rowTotal;
	var selStart = textRows.selStart;
	var selEnd = textRows.selEnd;

// find the largest 2^n < rows
	var add = 1;
	while (add < rowTotal) {
		add = add * 2;
	}
	add = add / 2;

// approximate with decreasing add
	var selStartRow = add;
	var selEndRow = add;
	while (add >= 1) {

// approximate selection start
		if (selStartRow >= rowTotal) {
			selStartRow -= add;
		}
		else if (textRows.rowStart[selStartRow] > selStart) {
			selStartRow -= add;
		}
		else {
			selStartRow += add;
		}

// approximate selection end
		if (selEndRow >= rowTotal) {
			selEndRow -= add;
		}
		else if (textRows.rowStart[selEndRow] > selEnd) {
			selEndRow -= add;
		}
		else {
			selEndRow += add;
		}
		add = add / 2;
	}
	if (textRows.rowStart[selStartRow] > selStart) {
		selStartRow --;
	}
	if (textRows.rowStart[selEndRow] > selEnd) {
		selEndRow --;
	}
	textRows.selStartRow = selStartRow;
	textRows.selEndRow = selEndRow;

	return;
}


//
// convert strange spaces, remove non-\n linebreak characters
//

function ConvertStrangeSpaces() {

//	var text = textareaObj.value;
//	text = text.replace(/[\t\v\u00a0\u2028\u2029]+/g, ' '); // \u00a0 = &nbsp;
//	text = text.replace(/[\t\v\u2028\u2029]+/g, ' ');
//	text = text.replace(/[\r\f]/g, '');
//	textareaObj.value = text;

	return;
}



//
// wikifyHTML, obj.html contains the text to be wikified
//

/*
	allowed and converted tags:
			br|p
			h1|h2|h3|h4|h5|h6
			hr
			i|dfn|cite|em|var
			b|strong
			table|caption|col|thead|tfoot|tbody|tr|td|th
			dl|dt|dd|li|ol|ul
			a
	not allowed yet, converted to span:
			bdo|q|kbd|samp|abbr|acronym|label
	other allowed tags:
			big|blockquote|colgroup|center|code|del|div|font|ins|pre|s|small|span|strike|sub|sup|tt|u|rb|rp|rt|ruby
	mediawiki tags:
			nowiki|math|gallery|noinclude|includeonly|ref|references
*/

function WikifyHTML(obj) {

// delete tags
	obj.html = obj.html.replace(/<(style)\b[^>]*>.*?<\/\1>/g, '');

// standardize newline, remove multiple spaces
	obj.html = obj.html.replace(/<br(\b[^>]*)?>/gi, '\n');
	obj.html = obj.html.replace(/\n?\r/g, '\n');
	obj.html = obj.html.replace(/ +/g, ' ');

// escape character entities
	obj.html = obj.html.replace(/&(?!(amp;|lt;|gt;))/g, '&amp;');

// remove comments
	obj.html = obj.html.replace(/<!--.*?-->/g, '');

// <hr> horizontal rule
	obj.html = obj.html.replace(/\s*<hr(\b[^>]*)>\s*/gi, '\n----\n');

// <i> <em> <dfn> <var> <cite> italic
	obj.html = obj.html.replace(/<(i|em|dfn|var|cite)\b.*?>/gi, '\'\'');
	obj.html = obj.html.replace(/<\/(i|em|dfn|var|cite)\b.*?>/gi, '\'\'');

// <b> <strong> bold
	obj.html = obj.html.replace(/<(b|strong)\b.*?>/gi, '\'\'\'');
	obj.html = obj.html.replace(/<\/(b|strong)\b.*?>/gi, '\'\'\'');

// <h1> .. <h6> headings
	obj.html = obj.html.replace(/\s*<h1\b[^>]*>(.*?)<\/h1\b[^>]*>\s*/gi, '\n\n= $1 =\n\n');
	obj.html = obj.html.replace(/\s*<h2\b[^>]*>(.*?)<\/h2\b[^>]*>\s*/gi, '\n\n== $1 ==\n\n');
	obj.html = obj.html.replace(/\s*<h3\b[^>]*>(.*?)<\/h3\b[^>]*>\s*/gi, '\n\n=== $1 ===\n\n');
	obj.html = obj.html.replace(/\s*<h4\b[^>]*>(.*?)<\/h4\b[^>]*>\s*/gi, '\n\n==== $1 ====\n\n');
	obj.html = obj.html.replace(/\s*<h5\b[^>]*>(.*?)<\/h5\b[^>]*>\s*/gi, '\n\n===== $1 =====\n\n');
	obj.html = obj.html.replace(/\s*<h6\b[^>]*>(.*?)<\/h6\b[^>]*>\s*/gi, '\n\n====== $1 ======\n\n');

// <span> <div>
	obj.html = obj.html.replace(/<(span|div)\s+([^>]*)>/gi,
		function (p, p1, p2) {
			return('<' + p1 + SanitizeAttributes(p1, p2) +  '>');
		}
	);

// <td> <p> table cell, remove first paragraph
	obj.html = obj.html.replace(/(<td\b[^>]*>)\s*<p\b.*?>/gi, '$1');

// <thead> <tbody> <tfoot>
	obj.html = obj.html.replace(/<\/?(thead|tbody|tfoot)\b.*?>/gi, '');

// <td> table cells
	obj.html = obj.html.replace(/\s*<td\s*>\s*/gi, '\n| ');
	obj.html = obj.html.replace(/\s*<(td)\s+([^>]*)>\s*/gi,
		function (p, p1, p2) {
			return('\n|' + SanitizeAttributes(p1, p2) + ' | ');
		}
	);

// <th> table cells
	obj.html = obj.html.replace(/\s*<th\s*>\s*/gi, '\n| ');
	obj.html = obj.html.replace(/\s*<(th)\s+([^>]*)>\s*/gi,
		function (p, p1, p2) {
			return('\n!' + SanitizeAttributes(p1, p2) + ' | ');
		}
	);

// <tr> table rows
	obj.html = obj.html.replace(/\s*<tr\s*>\s*/gi, '\n|-\n');
	obj.html = obj.html.replace(/\s*<(tr)\s+([^>]*)>\s*/gi,
		function (p, p1, p2) {
			return('\n|-' + SanitizeAttributes(p1, p2) + '\n');
		}
	);

// <caption> captionCaption
	obj.html = obj.html.replace(/\s*<caption\s*>\s*/gi, '\n|+ ');
	obj.html = obj.html.replace(/\s*<(caption)\s+([^>]*)>\s*/gi,
		function (p, p1, p2) {
			return('\n|+' + SanitizeAttributes(p1, p2) + ' | ');
		}
	);

// <table> tables
	obj.html = obj.html.replace(/\s*<table\s*>\s*(\|-\n)?/gi, '\n\n{|\n');
	obj.html = obj.html.replace(/\s*<(table)\s+([^>]*)>\s*(\|-\n)?/gi,
		function (p, p1, p2) {
			return('\n{|' + SanitizeAttributes(p1, p2) + '\n');
		}
	);
	obj.html = obj.html.replace(/\s*<\/table>\s*/gi, '\n|}\n\n');

// convert images
	obj.html = obj.html.replace(/<img\b([^>]*)>/gi,
		function (p, p1) {

// get and format parameters
			var address = '';
			var regExpMatch = /\bsrc\s*=\s*(\'|\")([^\'\"]*)(\'|\")/i.exec(p1);
			if (regExpMatch != null) {
				address = regExpMatch[2].replace(/^ +| +$/g, '');
			}

			var alt = '';
			regExpMatch = /\balt\s*=\s*(\'|\")([^\'\"]*)(\'|\")/i.exec(p1);
			if (regExpMatch != null) {
				alt = regExpMatch[2].replace(/^ +| +$/g, '');
				alt = alt.replace(/&amp;nbsp;|\n/g, ' ');
				alt = alt.replace(/ {2,}/g, ' ');
				alt = alt.replace(/^ | $/g, '');
				if (alt != '') {
					alt = '|' + alt;
				}
			}

			var imgWidth = '';
			regExpMatch = /\bwidth\s*=\s*(\'|\")([^\'\"]*)(\'|\")/i.exec(p1);
			if (regExpMatch != null) {
				imgWidth = '|' + regExpMatch[2].replace(/^ +| +$/g, '') + 'px';
			}

			var longDesc = '';;
			regExpMatch = /\blongdesc\s*=\s*(\'|\")([^\'\"]*)(\'|\")/i.exec(p1);
			if (regExpMatch != null) {
				longDesc = regExpMatch[2].replace(/^ +| +$/g, '');
			}

// wiki image
			var image = '';
			regExpMatch = /^\/wiki\/Image:(.*)$/.exec(longDesc);
			if (regExpMatch != null) {
				image = regExpMatch[1];
			}

// external image
			else {
				regExpMatch = /([^\/]+)$/.exec(address);
				if (regExpMatch != null) {
					image = regExpMatch[1];
				}
			}

			if (image != '') {
				return('[[Image:' + image + imgWidth + alt + ']]');
			}
			return('');
		}
	);

// convert links
	obj.html = obj.html.replace(/<a\b([^>]*)>(.*?)<\/a>/gi,
		function (p, p1, p2) {

// get and format parameters
			var address = '';
			var regExpMatch = /\bhref\s*=\s*(\'|\")([^\'\"]*)(\'|\")/i.exec(p1);
			if (regExpMatch != null) {
				address = regExpMatch[2].replace(/^ +| +$/g, '');
			}
			if (address == '') {
				return('');
			}

			var linkText = p2;
			linkText = linkText.replace(/&amp;nbsp;|\n/g, ' ');
			linkText = linkText.replace(/ {2,}/g, ' ');
			linkText = linkText.replace(/^ | $/g, '');
			if ( /\[image:(.*?)\]/i.exec(linkText) ) {
				return(linkText);
			}

// wikilink
			var regExpString = '^';
			var urlProtocol = window.location.protocol;
			urlProtocol = urlProtocol.replace(/\./g, '\\.');
			regExpString += '(' + urlProtocol + '//|)(';
			var urlHostname = window.location.hostname;
			if (urlHostname != '') {
				urlHostname = urlHostname.replace(/\./g, '\\.');
				regExpString += urlHostname + '/';
			}
			regExpString += '|)[\\w\\./]*/wiki/(.*)$';
/*

Debug();
Debug('regExpString', regExpString);
Debug('linkText', linkText);
*/
			var regExp = new RegExp(regExpString);
			var regExpMatch = regExp.exec(address);
			if (regExpMatch != null) {
				var article = regExpMatch[3].replace(/_/g, ' ');
				article = decodeURIComponent(article);
				article = article.replace(/&/g, '&amp;');
				if (linkText == '') {
					return('[[' + article + ']]');
				}
				if ( ( (article.substr(0, 1).toLowerCase() + article.substr(1)) == linkText )
					|| ( (article.substr(0, 1).toUpperCase() + article.substr(1)) == linkText ) ) {
					return('[[' + linkText + ']]');
				}
				if ( ( (article.substr(0, 1).toLowerCase() + article.substr(1)) == linkText.substr(0, linkText.length - 1) )
					|| ( (article.substr(0, 1).toUpperCase() + article.substr(1)) == linkText.substr(0, linkText.length - 1) ) ) {
					return( '[[' + linkText.substr(0, linkText.length - 1) + ']]' + linkText.substr(linkText.length - 1) );
				}
				return('[[' + article + '|' + linkText + ']]');
			}

// normal link
			if ( (linkText == '') || ( (address.substr(0, 1).toLowerCase() + address.substr(1)) == linkText ) || ( (address.substr(0, 1).toUpperCase() + address.substr(1)) == linkText ) ) {
				return('[' + address + ']');
			}
			return('[' + address + ' ' + linkText + ']');
		}
	);

// convert lists //definition lists to be done/////////////////////
	var listObj = {};
	listObj.prefix = '';
	obj.html = obj.html.replace(/\s*<(\/?(ol|ul|li))\b[^>]*>\s*/gi,
		function (p, p1, p2, p3, p4) {
			switch (p1.toLowerCase()) {
				case 'ol':
					listObj.prefix += '#';
					return('\n\n');
				case 'ul':
					listObj.prefix += '*';
					return('\n\n');
				case '/ol':
				case '/ul':
					listObj.prefix = listObj.prefix.substr(0, listObj.prefix.length - 1);
					return('\n\n');
				case 'li':
					return('\n' + listObj.prefix + ' ');
				case '/li':
					return('');
			}
		}
	);

// <p> paragraph
	obj.html = obj.html.replace(/(.)<p\b.*?>/gi, '$1\n\n');
	obj.html = obj.html.replace(/<\/p\b.*?>/gi, '');

// <> remove not allowed tags
	obj.html = obj.html.replace(/(<\/?)(\/?)(\w+)(.*?>)/g,
		function (p, p1, p2, p3, p4) {
			if ( /^(big|blockquote|colgroup|center|code|del|div|font|ins|pre|s|small|span|strike|sub|sup|tt|u|rb|rp|rt|ruby|nowiki|math|gallery|noinclude|includeonly|ref|references)$/i.test(p3) ) {
				return(p1 + p2 + p3 + p4);
			}
			else {
				return('');
			}
		}
	);

// opening html tags
	obj.html = obj.html.replace(/<(\w+)(.*?)>/gi,
		function (p, p1, p2) {
			return('&lt;' + p1 + SanitizeAttributes(p1, p2) + '&gt;');
		}
	);

// closing html tags
	obj.html = obj.html.replace(/</g, '&lt;');
	obj.html = obj.html.replace(/>/g, '&gt;');

// newlines to <br>
	obj.html = obj.html.replace(/\n{3,}/g, '\n\n');
	obj.html = obj.html.replace(/\n/g, '<br>');

	return;
}


//
// SanitizeAttributes: see Sanitizer.php
//

function SanitizeAttributes(tag, attributes) {

	var common = 'lang|dir|style|class'; // not needed: id|title
	var tablealign = '|align|char|charoff|valign';
	var tablecell = '|abbr|axis|headers|scope|rowspan|colspan|nowrap|width|height|bgcolor';
	tag = tag.toLowerCase();
	var sanitized = '';
	var regExp = /(\w+)\s*=\s*(\'|\")([^\'\"]*)(\'|\")/g;
	var regExpMatch;
	while (regExpMatch = regExp.exec(attributes)) {
		var attrib = regExpMatch[1];
		var attribValue = regExpMatch[3];
		if (attribValue == '') {
			continue;
		}
		var valid = false;
		if ('center|em|strong|cite|code|var|sub|supdl|dd|dt|tt|b|i|big|small|strike|s|u|rb|rp|ruby'.indexOf(tag) >= 0) {
			if (common.indexOf(attrib) >= 0) { valid = true; }
		}
		else if ('div|span|h1|h2|h3|h4|h5|h6|p'.indexOf(tag) >= 0) {
			if ((common + '|align').indexOf(attrib) >= 0) { valid = true; }
		}
		else if ('blockquote'.indexOf(tag) >= 0) {
			if ((common + '|cite').indexOf(attrib) >= 0) { valid = true; }
		}
		else if ('br'.indexOf(tag) >= 0) {
			if ('style|clear'.indexOf(attrib) >= 0) { valid = true; }
		}
		else if ('pre'.indexOf(tag) >= 0) {
			if ((common + '|width').indexOf(attrib) >= 0) { valid = true; }
		}
		else if ('ins|del'.indexOf(tag) >= 0) {
			if ((common + '|cite|datetime').indexOf(attrib) >= 0) { valid = true; }
		}
		else if ('ul'.indexOf(tag) >= 0) {
			if ((common + '|type').indexOf(attrib) >= 0) { valid = true; }
		}
		else if ('ol'.indexOf(tag) >= 0) {
			if ((common + '|type|start').indexOf(attrib) >= 0) { valid = true; }
		}
		else if ('li'.indexOf(tag) >= 0) {
			if ((common + '|type|value').indexOf(attrib) >= 0) { valid = true; }
		}
		else if ('table'.indexOf(tag) >= 0) {
			if ((common + '|summary|width|border|frame|rules|cellspacing|cellpadding|align|bgcolor|frame|rules|border').indexOf(attrib) >= 0) { valid = true; }
		}
		else if ('caption'.indexOf(tag) >= 0) {
			if ((common + '|align').indexOf(attrib) >= 0) { valid = true; }
		}
		else if ('thead|tfoot|tbody'.indexOf(tag) >= 0) {
			if ((common + tablealign).indexOf(attrib) >= 0) { valid = true; }
		}
		else if ('colgroup|col'.indexOf(tag) >= 0) {
			if ((common + '|span|width' + tablealign).indexOf(attrib) >= 0) { valid = true; }
		}
		else if ('tr'.indexOf(tag) >= 0) {
			if ((common + '|bgcolor' + tablealign).indexOf(attrib) >= 0) { valid = true; }
		}
		else if ('td|th'.indexOf(tag) >= 0) {
			if ((common + tablecell + tablealign).indexOf(attrib) >= 0) { valid = true; }
		}
		else if ('font'.indexOf(tag) >= 0) {
			if ((common + '|size|color|face').indexOf(attrib) >= 0) { valid = true; }
		}
		else if ('hr'.indexOf(tag) >= 0) {
			if ((common + '|noshade|size|width').indexOf(attrib) >= 0) { valid = true; }
		}
		else if ('rt'.indexOf(tag) >= 0) {
			if ((common + '|rbspan').indexOf(attrib) >= 0) { valid = true; }
		}
		if (valid == true) {

// remove non-standard styles and clean up
			if (attrib == 'style') {
				attribValue = attribValue.replace(/ *(\-moz[\w\-]+|windowtext) */g, '');
				attribValue = attribValue.replace(/\b0(%|in|cm|mm|em|ex|pt|pc|px)\b/g, '0');
				attribValue = attribValue.replace(/[\w\-]+ *\: *\; */g, '');
				attribValue = attribValue.replace(/ *(;|:) */g, '$1 ');
				attribValue = attribValue.replace(/( |;)+$/g, ';');
			}
			sanitized += ' ' + attrib + '="' + attribValue + '"';
		}
	}
	return(sanitized);
}


//
//
// RemoveHighlighting: remove syntax highlighting in obj.plain; sets obj.htmlCode if text contains html code
//

function RemoveHighlighting(obj) {

// remove highlighting-only div, span, and xmp
	var isRemove = [];
	obj.html = obj.html.replace(/(<(\/?)(div|span|xmp)(.*?)>)/g,
		function (p, p1, p2, p3, p4) {
			if (p2 == '') {
				if ( p4.match(/\bclass=\"wikEd\w+\"/) ) {
					isRemove.push(true);
					return('');
				}
				else if (p4 == '') {
					isRemove.push(true);
					return('');
				}
				isRemove.push(false);
				return(p1);
			}
			if (isRemove.pop() == true) {
				return('');
			}
			return(p1);
		}
	);

	obj.html = obj.html.replace(/<!--wikEd\w+-->/g, '');
	obj.html = obj.html.replace(/\n|\r/g, '');
	if (obj.html.match(/<(?!br)/)) {
		obj.htmlCode = true;
	}
	else {
		obj.htmlCode = false;
	}


	return;
}


//
//
// HighlightSyntax: highlight syntax in obj.html; if singleLine is set, no block syntax will be highlighted; call RemoveHighlighting first
//

function HighlightSyntax(obj, singleLine) {

// convert newlines
        obj.html = obj.html.replace(/\n|\r/g, '');
        obj.html = obj.html.replace(/<br(\b[^>]*)?>/g, '\n');

// escape character entities
	obj.html = obj.html.replace(/&(?!(amp;|lt;|gt;|nbsp;))/g, '&amp;');





////blocks start
// various blocks
	if (singleLine != true) {
		obj.html = obj.html.replace(/(&lt;(blockquote|center|div|pre)\b.*?&gt;)/gi, '<span class="wikEdBlock">$1');
		obj.html = obj.html.replace(/(&lt;\/(blockquote|center|div|pre)\b.*?&gt;)/gi, '$1</span><!--wikEdBlock-->');
	}

// lists * # : ;
	obj.html = obj.html.replace(/^([\*\#\:\;]+)(.*?)$/gm, '<span class="wikEdListLine"><span class="wikEdListTag">$1</span><!--wikEdListTag-->$2</span><!--wikEdListLine-->');
	if (singleLine != true) {
		obj.html = obj.html.replace(/((<span class=\"wikEdListLine\">[^\n]*\n)+)/g, '<span class="wikEdListBlock">$1');
		obj.html = obj.html.replace(/(<span class=\"wikEdListLine\">[^\n]*)(\n)(?!<span class=\"wikEdListLine\">)/g, '$1</span><!--wikEdListBlock-->$2');
	}

// #redirect (finish)
	obj.html = obj.html.replace(/(<span class=\"wikEdWikiRedir\">)(.*?<\/span><!--wikEdWikiRedir-->)/g, '$1#$2');

// space-pre
	if (singleLine != true) {
		obj.html = obj.html.replace(/^( +)(.*?)$/gm, '<span class="wikEdSpaceLine"><span class="wikEdSpaceTag">$1</span><!--wikEdSpaceTag-->$2</span><!--wikEdSpaceLine-->');
		obj.html = obj.html.replace(/((<span class=\"wikEdSpaceLine\">[^\n]*\n)+)/g, '<span class="wikEdSpaceBlock">$1');
		obj.html = obj.html.replace(/(<span class=\"wikEdSpaceLine\">[^\n]*)(\n)(?!<span class="wikEdSpaceLine">)/g, '$1</span><!--wikEdSpaceBlock-->$2');
	}

// ---- <hr> horizontal rule
	obj.html = obj.html.replace(/(^|\n|<[^>]*>)(----)(\n|<[^>]*>|$)/g, '$1<span class="wikEdHR">$2</span><!--wikEdHR-->$3');
	obj.html = obj.html.replace(/(&lt;hr&gt;)/g, '<span class="wikEdHRInline">$1</span><!--wikEdHRInline-->');

// == headings
	obj.html = obj.html.replace(/(^|\n|<[^>]*>)(=+ *)([^\n]*?)( *=+ *)(\n|<[^>]*>|$)/g,
		function (p, p1, p2, p3, p4, p5) {
			p2 = p2.replace(/(=+)/g, '<span class="wikEdWiki">$1</span><!--wikEdWiki-->');
			p4 = p4.replace(/(=+)/g, '<span class="wikEdWiki">$1</span><!--wikEdWiki-->');
			if ( /^(external links?|see also|references?)$/i.test(p3) ) {
				p1 = p1 + '<span class="wikEdHeadingWp">';
				p5 = '</span><!--wikEdHeadingWp-->' + p5;
			}
			else {
				p1 = p1 + '<span class="wikEdHeading">';
				p5 = '</span><!--wikEdHeading-->' + p5;
			}
			return(p1 + p2 + p3 + p4 + p5);
		}
	);

// tables                       (    |    |    |  |    |  )
	obj.html = obj.html.replace(/^(\{\||\|\+|\|\-|\!|\|\}|\|)(.*?)$/gm, '<span class="wikEdTableLine"><span class="wikEdTableTag">$1</span><!--wikEdTableTag-->$2</span><!--wikEdTableLine-->');
	if (singleLine != true) {
		obj.html = obj.html.replace(/(^|\n)((<[^>]*>)*\{\|)/g, '$1<span class="wikEdTableBlock">$2');
		obj.html = obj.html.replace(/(^|\n)((<[^>]*>)*\|\}(<[^>]*>)*)/g, '$1$2</span><!--wikEdTableBlock-->');
		obj.html = obj.html.replace(/(&lt;table\b.*?&gt;)/gi, '<span class="wikEdTableBlock">$1');
		obj.html = obj.html.replace(/(&lt;\/table\b.*?&gt;)/gi, '$1</span><!--wikEdTableBlock-->');
	}

// <gallery> wiki markup
	if (singleLine != true) {
		obj.html = obj.html.replace(/(&lt;(gallery)\b.*?&gt;)/gi, '$1<span class="wikEdWiki">$1');
		obj.html = obj.html.replace(/(&lt;\/(gallery)\b.*?&gt;)/gi, '$1</span><!--wikEdWiki-->');
	}
////blocks end



// <sup> </sub> <ins> <del>
	obj.html = obj.html.replace(/((&lt;)sup\b.*?(&gt;)(.*?)(&lt;)\/sup\b.*?(&gt;))/gi, '<span class="wikEdSup">$1</span><!--wikEdSup-->');
	obj.html = obj.html.replace(/((&lt;)sub\b.*?(&gt;)(.*?)(&lt;)\/sub\b.*?(&gt;))/gi, '<span class="wikEdSub">$1</span><!--wikEdSub-->');
	obj.html = obj.html.replace(/((&lt;)(ins|u)\b.*?(&gt;)(.*?)(&lt;)\/(ins|u)\b.*?(&gt;))/gi, '<span class="wikEdIns">$1</span><!--wikEdIns-->');
	obj.html = obj.html.replace(/((&lt;)(del|s|strike)\b.*?(&gt;)(.*?)(&lt;)\/(del|s|strike)\b.*?(&gt;))/gi, '<span class="wikEdDel">$1</span><!--wikEdDel-->');

// various inlines
	obj.html = obj.html.replace(/(&lt;\/?(sub|sup|ins|u|del|s|strike|big|br|colgroup|code|font|small|span|tt|rb|rp|rt|ruby)\b.*?&gt;)/gi, '<span class="wikEdInline">$1</span><!--wikEdInline-->');

// unsupported or not needed <> tags
	obj.html = obj.html.replace(/(&lt;\/?)(\w+)(.*?\/?&gt;)/g,
		function (p, p1, p2, p3) {
			if ( ! /^(col|thead|tfoot|tbody|big|br|blockquote|colgroup|center|code|del|div|font|ins|pre|s|small|span|strike|sub|sup|tt|u|rb|rp|rt|ruby|nowiki|math|gallery|noinclude|includeonly|ref|references)$/i.test(p2) ) {
				p1 = '<span class="wikEdUnknown">' + p1;
				p3 = p3 + '</span><!--wikEdUnknown-->';
			}
			return(p1 + p2 + p3);
		}
	);

// comments
	obj.html = obj.html.replace(/(&lt;!--.*?--&gt;)/g, '<span class="wikEdComment">$1</span><!--wikEdComment-->');

// <nowiki> <math> <noinclude> <includeonly> <ref> <references> wiki markup
	obj.html = obj.html.replace(/((&lt;)(nowiki|math|gallery|noinclude|includeonly|ref|references)\b.*?(&gt;)(.*?)(&lt;)\/(nowiki|math|gallery|noinclude|includeonly|ref|references)\b.*?(&gt;))/gi, '<span class="wikEdWiki">$1</span><!--wikEdWiki-->');
/* disabled, eats text
// [] URL links
	obj.html = obj.html.replace(/(\[?)((http:\/\/|https:\/\/|ftp:\/\/|irc:\/\/|gopher:\/\/|news:|mailto:)\S*[\w\/])([^\]*?)([^\n\]]*)(.)/gi,
		function (p, p1, p2, p3, p4, p5) {

// link URL, text
			p2 = p2.replace(/(.*)/, '<span class="wikEdURLLink">$1</span><!--wikEdURLLink-->');
			p4 = p4.replace(/^(\s*)(.*?)(\s*)$/, '$1<span class="wikEdURLText">$2</span><!--wikEdURLText-->$3');

// link tags
			if ( (/\[/.test(p1)) && (/\]/.test(p5)) ) {
				p1 = p1.replace(/(\[)/, '<span class="wikEdLinkTag">$1</span><!--wikEdLinkTag-->');
				p5 = p5.replace(/(\])/, '<span class="wikEdLinkTag">$1</span><!--wikEdLinkTag-->');
			}
			return(p1 + p2 + p4 + p5);
		}
	);
*/
// [[ ]] links, images, categories
	obj.html = obj.html.replace(/(\[\[)([^\]]*)(\]\])/g,
		function (p, p1, p2, p3) {

// image
			if ( /^\s*image:/i.test(p2) ) {
				if (p2.match(/^(\s*)(.*:)+/)) {
					p1 = '<span class="wikEdImageInter">' + p1;
					p3 = p3 + '</span><!--wikEdImageInter-->';
				}
				else {
					p1 = '<span class="wikEdImage">' + p1;
					p3 = p3 + '</span><!--wikEdImage-->';
				}
				p2 = p2.replace(/^(\s*)(.*:)+/, '$1<span class="wikEdInter">$2</span><!--wikEdInter-->');
				p2 = p2.replace(/(\s*)([^>:\|]+)(\s*\|\s*|$)/, '$1<span class="wikEdImageName">$2</span><!--wikEdImageName-->$3');
				p2 = p2.replace(/(\|\s*)(.*)/,
					function (p, p1, p2) {
						p2 = p2.replace(/(.*?)(\s*(\||$))/g, '<span class="wikEdImageText">$1</span><!--wikEdImageText-->$2');
						return(p1 + p2);
					}
				);
			}

// category
			else if ( /^\s*category:/i.test(p2) ) {
				if (p2.match(/^(\s*)(.*:)+/)) {
					p1 = '<span class="wikEdCatInter">' + p1;
					p3 = p3 + '</span><!--wikEdCatInter-->';
				}
				else {
					p1 = '<span class="wikEdCat">' + p1;
					p3 = p3 + '</span><!--wikEdCat-->';
				}
				p2 = p2.replace(/^(\s*)(.*:)+/, '$1<span class="wikEdInter">$2</span><!--wikEdInter-->');
				p2 = p2.replace(/(\s*)([^>:\|]+)(\s*\|\s*|$)/, '$1<span class="wikEdCatName">$2</span><!--wikEdCatName-->$3');
				p2 = p2.replace(/(\|\s*)(.*)/,
					function (p, p1, p2) {
						p2 = p2.replace(/(.*?)(\s*(\||$))/g, '<span class="wikEdCatText">$1</span><!--wikEdCatText-->$2');
						return(p1 + p2);
					}
				);
			}

// wikilink
			else {
				if (p2.match(/^(\s*)(.*:)+/)) {
					p1 = '<span class="wikEdLinkInter">' + p1;
					p3 = p3 + '</span><!--wikEdLinkInter-->';
				}
				else {
					p1 = '<span class="wikEdLink">' + p1;
					p3 = p3 + '</span><!--wikEdLink-->';
				}
				p2 = p2.replace(/^(\s*)(.*:)+/, '$1<span class="wikEdInter">$2</span><!--wikEdInter-->');
				p2 = p2.replace(/(\s*)([^>:\|]+)((\s*\|\s*)(.*))?$/,
					function (p, p1, p2, p3, p4, p5) {
                                          if (!p5)
                                          {
                                            return   p1 
                                                   + '<span class="wikEdLinkLiteral">' + p2 + '</span><!--wikEdLinkLiteral-->'
                                                   + p3;
                                          }
                                          else
                                          {
                                            return   p1 
                                                   + '<span class="wikEdLinkName">' + p2 + '</span><!--wikEdLinkName-->'
                                                   + p4
                                                   + '<span class="wikEdLinkText">' + p5 + '</span><!--wikEdLinkText-->';
                                          }
                                        }
				);
			}

// link tags
			p1 = p1.replace(/(\[+)/, '<span class="wikEdLinkTag">$1</span><!--wikEdLinkTag-->');
			p2 = p2.replace(/(\|)/gi, '<span class="wikEdLinkTag">$1</span><!--wikEdLinkTag-->');
			p3 = p3.replace(/(\]+)/, '<span class="wikEdLinkTag">$1</span><!--wikEdLinkTag-->');
			return(p1 + p2 + p3);
		}
	);

// {{ }}, {{{ }}} templates
	obj.html = obj.html.replace(/(\{\{+)([^\}]*)(\}\}+)/g,
		function (p, p1, p2, p3) {
			if (p2.match(/^(\s*)(.*:)+/)) {
				p1 = '<span class="wikEdTemplInter">' + p1;
				p3 = p3 + '</span><!--wikEdTemplInter-->';
			}
			else {
				p1 = '<span class="wikEdTempl">' + p1;
				p3 = p3 + '</span><!--wikEdTempl-->';
			}
			p2 = p2.replace(/^(\s*)(.*:)+/, '$1<span class="wikEdInter">$2</span><!--wikEdInter-->');
			p2 = p2.replace(/(\s*)([^>:\|]+)(\s*\|\s*|$)/, '$1<span class="wikEdTemplName">$2</span><!--wikEdTemplName-->$3');
			p2 = p2.replace(/(\|\s*)(.*)/,
				function (p, p1, p2) {
					p2 = p2.replace(/(.*?)(\s*(\||$))/g, '<span class="wikEdTemplText">$1</span><!--wikEdTemplText-->$2');
					return(p1 + p2);
				}
			);

// template tags
			p1 = p1.replace(/(\{+)/, '<span class="wikEdLinkTag">$1</span><!--wikEdLinkTag-->');
			p2 = p2.replace(/(\|)/g, '<span class="wikEdLinkTag">$1</span><!--wikEdLinkTag-->');
			p3 = p3.replace(/(\}+)/, '<span class="wikEdLinkTag">$1</span><!--wikEdLinkTag-->');
			return(p1 + p2 + p3);
		}
	);

// #redirect
	obj.html = obj.html.replace(/(^|\n)(#)(redirect\b)/g, '$1<span class="wikEdWikiRedir">$3</span><!--wikEdWikiRedir-->');


/////////// blocks original place


// <b> <i>
	obj.html = obj.html.replace(/(\'\'\')(\'*)(.*?)(\'*)(\'\'\')/g, '<span class="wikEdBold">$2$3$4</span><!--wikEdBold-->');
	obj.html = obj.html.replace(/(\'\')(.*?)(\'\')/g, '<span class="wikEdItalic">$1$2$3</span><!--wikEdItalic-->');
	obj.html = obj.html.replace(/(<span class=\"wikEdBold\">)/g, '$1\'\'\'');
	obj.html = obj.html.replace(/(<\/span><!--wikEdBold-->)/g, '\'\'\'$1');
	obj.html = obj.html.replace(/(\'{2,})/g, '<span class="wikEdWiki">$1</span><!--wikEdWiki-->');

// named colors
	obj.html = obj.html.replace(/(\b(red|orange|yellow|fuchsia|white|lime|aqua|silver)\b)/g, '<span style="background-color: $1;" class="wikEdColors">$1</span><!--wikEdColors-->');
	obj.html = obj.html.replace(/(\b(maroon|olive|purple|green|navy|teal|blue|black|gray)\b)/g, '<span style="color: white; background-color: $1;" class="wikEdColors">$1</span><!--wikEdColors-->');

// RGB colors
	obj.html = obj.html.replace(/(#[0-9a-fA-F]{6})([\s\'\";])/g, '<span style="background-color: $1;" class="wikEdColors">$1</span><!--wikEdColors-->$2');
	obj.html = obj.html.replace(/(rgb\(\s*\d+,\s*\d+,\s*\d+\s*\))/gi, '<span style="background-color: $1;" class="wikEdColors">$1</span><!--wikEdColors-->');

// newlines to <br>
        obj.html = '<span class="wikEdLine">' 
                 + obj.html.replace(/\n/g, '</span><!--wikEdLine--><br><span class="wikEdLine">') 
                 + '</span><!--wikEdLine-->';

// remove comments ///////
	obj.html = obj.html.replace(/<!--wikEd\w+-->/g, ''); ///////

// remove <span> ... </span>
	var isRemove = [];
	obj.html = obj.html.replace(/(&lt;(\/?)span(.*?)&gt;)/g,
		function (p, p1, p2, p3) {
			if (p2 == '') {
				if (p3 == '') {
					isRemove.push(true);
					return('');
				}
				isRemove.push(false);
				return(p1);
			}
			if (isRemove.pop() == true) {
				return('');
			}
			return(p1);
		}
	);

// display tabs and strange blanks
	obj.html = obj.html.replace(/(\t)(?!<\/xmp><!--wikEdTab-->)/g, '<xmp class="wikEdTab">$1</xmp><!--wikEdTab-->');
	obj.html = obj.html.replace(/([\v\u2028\u2029])(?!<\/xmp><!--wikEdBlank-->)/g, '<xmp class="wikEdBlank">$1</xmp><!--wikEdBlank-->');

	return;
}


//
// HighlightSyntaxFrame: highlight syntax in frame
//

function HighlightSyntaxFrame() {

	if (highlightSyntax != true) {
		return;
	}

// get the selection
	var obj = {};
	obj.sel = frameWindow.getSelection();

// highlight the whole frame
	if (obj.sel.isCollapsed) {
		obj.html = frameBody.innerHTML;

// remove syntax highlighting
		RemoveHighlighting(obj);

// wikify, highlight, and replace
		if (obj.htmlCode == true) {
			WikifyHTML(obj);
		}
		HighlightSyntax(obj);
		FrameExecCommand('selectall');
		if (obj.html != '') {
			FrameExecCommand('inserthtml', obj.html);
		}
		else {
			FrameExecCommand('delete');
		}
	}

// highlight a selection
	else {
		obj.selRange = obj.sel.getRangeAt(obj.sel.rangeCount - 1);
		var documentFragment = obj.selRange.cloneContents();

// get the inner HTML of the document fragment
		GetInnerHTML(obj, documentFragment);
		if (obj.html != '') {

// remove syntax highlighting
			RemoveHighlighting(obj);

// wikify, highlight, and replace selection
			if (obj.htmlCode == true) {
				WikifyHTML(obj);
			}
			HighlightSyntax(obj);
			if (obj.html != '') {
				FrameExecCommand('inserthtml', obj.html);
			}
			else {
				FrameExecCommand('delete');
			}
		}
	}

// get new cursor container and offset
	obj.startPos = obj.startContainerPos + obj.selRange.startOffset;
	obj.endPos = obj.endContainerPos + obj.selRange.endOffset;
	obj.selRange = null;
	GetTextPosContainer(obj, frameBody);
/*
// set the new cursor position
	var range = document.createRange();
	range.setStart(obj.startContainer, obj.startOffset);
	range.setEnd(obj.endContainer, obj.endOffset);
	obj.sel.removeAllRanges();
	obj.sel.addRange(range);
*/
// focus the frame
	frameWindow.focus();

	return;
}


//
// UpdateTextarea: copy frame content to textarea
//

function UpdateTextarea() {

// get frame content
	var obj = {};
	obj.html = frameBody.innerHTML;

// wikify the text
	RemoveHighlightingWikify(obj);

// textify
	obj.plain = obj.html;
	obj.plain = obj.plain.replace(/<br>/g, '\n');
	obj.plain = obj.plain.replace(/<.*?>/g, '');
	obj.plain = obj.plain.replace(/&lt;/g, '<');
	obj.plain = obj.plain.replace(/&gt;/g, '>');
	obj.plain = obj.plain.replace(/\u00a0|&nbsp;/g, ' ');
	obj.plain = obj.plain.replace(/&amp;/g, '&'); ///?

// copy to textarea
	textareaObj.value = obj.plain;

	return;
}


//
// UpdateFrame: copy textarea content to frame
//

function UpdateFrame() {

// get frame content
	var obj = {};
	obj.html = textareaObj.value;
	obj.html = obj.html.replace(/</g, '&lt;');
	obj.html = obj.html.replace(/>/g, '&gt;');
	obj.html = obj.html.replace(/(\n?\r|\n)/g, '<br>');

// display multiple blanks
	obj.html = obj.html.replace(/  /g, ' &nbsp;');
	obj.html = obj.html.replace(/(\u00a0|&nbsp;) /g, '&nbsp;&nbsp;');

// highlight the syntax
	if (highlightSyntax == true) {
		HighlightSyntax(obj);
	}

// set frame content
	frameBody.innerHTML = obj.html;
	return;
}


//
// KeyFrame: event handler for keypress in frame
//

function KeyFrame(event) {

	return;
}


//
// SetFrameSelection: wrapper for execCommand method
//

function FrameExecCommand(command, option) {
/*
Debug(null);
Debug('command', command);
Debug('option', option);
*/

	frameDocument.execCommand(command, false, option);
	return;
}


//
// FindAhead: non-regexp and case-insensitive find-as-you-type, event handler for find field
//

function FindAhead() {

	if (document.getElementById('findAhead').checked == true) {

// get the find text
		var findText = document.getElementById('findText').value;
		if (findText == '') {
			return;
		}
		
// function: window.find(string, caseSensitive, backwards, wrapAround, wholeWord, searchInFrames, showDialog)
		var found = frameWindow.find(findText, false, false, true, false, false, false);
		if (found == false) {
 			var sel = frameWindow.getSelection();
			sel.collapse(sel.anchorNode, sel.anchorOffset);
		}
	}
	return;
}


//
// FullScreen: change to fullscreen input area; event handler for fullscreen buttons
//

function FullScreen(event) {

	fullScreenMode = true;

// get heights
	var windowHeight = window.innerHeight;
	var buttonsWrapper = document.getElementById('buttonsWrapper');
	var buttonsWrapperHeight = buttonsWrapper.offsetHeight;
/*// set buttons margin
	buttonsWrapper.style.paddingLeft = '0.2em'
	buttonsWrapper.style.paddingBottom = '0.2em'

// textareaObj.value = windowHeight + ' - ' + buttonsWrapperHeight + ' = ' + (windowHeight - buttonsWrapperHeight);

// save window scroll position
//	normalPageYOffset = window.pageYOffset;
//	normalPageXOffset = window.pageXOffset;

// get fullscreen button coordinates
//	var buttonOffsetLeft = event.pageX - window.pageXOffset;
//	var buttonOffsetTop = event.pageY - window.pageYOffset;

// move the input area up in the tree // moving iframe in design
	var inputWrapper = document.getElementById('inputWrapper');
	var globalWrapper = document.getElementById('globalWrapper');
	var subGlobalWrapper = document.getElementById('subGlobalWrapper');
	globalWrapper.insertBefore(inputWrapper, subGlobalWrapper);
*/
/*
// set input area to fullscreen
	inputWrapper.style.position = 'fixed';
	inputWrapper.style.top = '0';
	inputWrapper.style.left = '0';
	inputWrapper.style.right = '0';
	inputWrapper.style.bottom = '0';
// set color
	var content = document.getElementById('content');
	inputWrapper.style.backgroundColor = GetStyle(content, 'background-color');

// set the textarea to maximal height
	frameBody.style.height = (windowHeight - buttonsWrapperHeight - 4) + 'px';

// hide the rest of the page
	subGlobalWrapper.style.display = 'none';
// set floating 'back to normal' button
	var floatButton = document.getElementById('fullScreenButtonFloat');
	floatButton.style.right = '';
	floatButton.style.bottom = '';
	floatButton.style.display = 'inline';
	floatButton.style.left = (buttonOffsetLeft - floatButton.offsetWidth / 2) + 'px';
	floatButton.style.top = (buttonOffsetTop - floatButton.offsetHeight / 2) + 'px';
	floatButton.focus();

// change fullscreen button text and handler
	var fullScreenButton = document.getElementById('fullScreenButton');
	fullScreenButton.value = normalButtonValue;
	fullScreenButton.title = normalButtonTitle;
	fullScreenButton.onclick = NormalScreen;
*/
// scroll to frame top
	var wrapperObj = document.getElementById('frameWrapper');
	var wrapperTop = GetOffsetTop(wrapperObj);
	window.scroll(0, wrapperTop);

	return;
}


//
// NormalScreen: change back to normal page view; event handler for fullscreen buttons
//

function NormalScreen() {

// check if we are in fullscreen mode
	if (fullScreenMode != true) {
		return;
	}
	fullScreenMode = false;

// hide floating 'back to normal' button
	var floatButton = document.getElementById('fullScreenButtonFloat').style.display = 'none';

// show the rest of the page
	document.getElementById('subGlobalWrapper').style.display = 'block';

// set input area back to the original position
	var inputWrapper = document.getElementById('inputWrapper');
	normalTreePos.parentNode.insertBefore(inputWrapper, normalTreePos);
	inputWrapper.style.position = 'static';
	inputWrapper.style.height = '';
	inputWrapper.style.backgroundColor = '';

// reset textarea settings
	textareaObj.style.width = normalTextareaWidth;
	textareaObj.style.height = normalTextareaHeight;
	textareaObj.style.margin = normalTextareaMargin;
	textareaObj.rows = normalTextareaRows;
	document.getElementById('buttonsWrapper').style.padding = '';

// change fullscreen button text and handler
	var fullScreenButton = document.getElementById('fullScreenButton');
	fullScreenButton.value = fullButtonValue;
	fullScreenButton.title = fullButtonTitle;
	fullScreenButton.onclick = FullScreen;

// reset window scroll position
	window.scrollTo(normalPageXOffset, normalPageYOffset);


	return;
}


//
// ResizeComboInput: set the size of the background select boxes so that the button is visible
//

function ResizeComboInput(field) {

// add a dummy option
	var dummy;
	if (selectElement[field].options.length == 0) {
		selectElement[field].options[0] = new Option('');
		dummy = true;
	}

// set option widths to 0
	for (i = 0; i < selectElement[field].options.length; i ++) {
		selectElement[field].options[i].style.width = '0';
	}

// calculate select width
	var inputWidth = inputElement[field].clientWidth;
	var selectWidth = selectElement[field].clientWidth;
	var optionWidth = selectElement[field].options[0].offsetWidth;
	var border = inputElement[field].offsetWidth - inputElement[field].clientWidth;
	selectElement[field].style.width = (selectWidth - optionWidth + inputWidth - border) + 'px';

// delete dummy option
	if (dummy) {
		selectElement[field].options[0] = null;
	}

// set option widths to auto
	for (i = 0; i < selectElement[field].options.length; i ++) {
		selectElement[field].options[i].style.width = 'auto';
	}
	return;
}


//
// ChangeComboInput: set the input value to selected option; onchange event handler for select boxes
//

function ChangeComboInput(field) {

// get selection index (-1 for unselected)
	var selected = selectElement[field].selectedIndex;
	if (selected >= 0) {

// get selected option
		var option = selectElement[field].options[selected];
		if (option.text != '') {

// add a tag to the summary box
			if (field == 'summary') {
				var text = inputElement[field].value;
				if ( (text != '') && (!text.match(/ \*\/ $/) ) ) {
					if (option.text.match(/^\w/)) {
						text += ', ';
					}
					else {
						text += ' ';
					}
				}
				text += option.text;
				inputElement[field].value = text;
			}

// add case and regexp checkboxes to find / replace fields
			else if (option.value == 'setcheck') {
				Button('caseSensitive', null, (option.text.charAt(0) == checkMarker[true]) );
				Button('regExp',        null, (option.text.charAt(1) == checkMarker[true]) );
				inputElement[field].value = option.text.substr(3);
			}

// add option text
			else {
				inputElement[field].value = option.text;
			}
		}
	}
	return;
}


//
// AddToHistory: add an input value to the cookie history
//

function AddToHistory(field) {

	if (inputElement[field].value != '') {

// load history from cookie
		LoadHistoryFromCookie(field);

// add current value to history
		fieldHist[field].unshift(inputElement[field].value);

// add case and regexp checkboxes to find / replace value
		if ( (field == 'find') || (field == 'replace') ) {
			fieldHist[field][0] =
				checkMarker[ document.getElementById('caseSensitive').checked ] +
				checkMarker[ document.getElementById('regExp').checked ] +
				' ' + fieldHist[field][0];
		}

// remove multiple old copies from history
		i = 1;
		while (i < fieldHist[field].length) {
			if (fieldHist[field][i] == fieldHist[field][0]) {
				fieldHist[field].splice(i, 1);
			}
			else {
				i ++;
			}
		}

// remove new value if it is a preset value
		if (presetOptions[field] != null) {
			i = 0;
			while (i < presetOptions[field].length) {
				if (presetOptions[field][i] == fieldHist[field][0]) {
					fieldHist[field].shift;
					break;
				}
				else {
					i ++;
				}
			}
		}

// cut history to maximal history length
		fieldHist[field] = fieldHist[field].slice(0, findHistoryLength);

// saved history to cookie
		SaveHistoryToCookie(field);
	}
	return;
}


//
// SetComboOptions: generate the select options from cookie history; onfocus handler for select box
//

function SetComboOptions(field) {

// load history from cookie
	LoadHistoryFromCookie(field);

	var option = {};
	var selected = null;
	j = 0;

// delete options
	var options = selectElement[field].options;
	for (i = 0; i > options.length; i ++) {
		selectElement[field].remove(i);
	}

// delete optgroup
	option = document.getElementById(field + 'Optgroup');
	if (option != null) {
		selectElement[field].removeChild(option);
	}

// workaround for onchange not firing when selecting first option from unselected dropdown
	option = document.createElement('option');
	option.style.display = 'none';
	selectElement[field].options[j++] = option;

// add history entries
	for (i = 0; i < fieldHist[field].length; i ++) {
		if (fieldHist[field][i] != null) {
			if (fieldHist[field][i] == inputElement[field].value) {
				selected = j;
			}
			option = document.createElement('option');
			option.text = fieldHist[field][i];
			if ( (field == 'find') || (field == 'replace') ) {
				option.value = 'setcheck';
			}
			selectElement[field].options[j++] = option;
		}
	}

// add preset entries
	if (presetOptions[field] != null) {
		var startPreset = j;
		for (i = 0; i < presetOptions[field].length; i ++) {
			if (presetOptions[field][i] != null) {
				if (presetOptions[field][i] == inputElement[field].value) {
					selected = j;
				}
				option = document.createElement('option');
				option.text = presetOptions[field][i];
				if (field == 'summary') {
					option.text = option.text.replace(/\{using\}/g, summaryUsing);
				}
				selectElement[field].options[j++] = option;
			}
		}

// add a blank separator
		if (startPreset > 1) {
			option = document.createElement('optgroup');
			option.label = '\u00a0';
			option.id = field + 'Optgroup';
			selectElement[field].insertBefore(option, selectElement[field].options[startPreset]);
		}
	}

// set the selection
	selectElement[field].selectedIndex = selected;
	return;
}


//
// ClearHistory: clear the history of combo input fields
//

function ClearHistory(field) {
	var cookieExpire = new Date();
	cookieExpire.setTime( cookieExpire.getTime() + cookieExpireSec * 1000 );
	SetCookie(cookieName[field], '', cookieExpire.toGMTString());
	SetComboOptions(field);
	return;
}


//
// LoadHistoryFromCookie: get the input box history from the respective cookie
//

function LoadHistoryFromCookie(field) {
	var cookie = GetCookie(cookieName[field]);
	if (cookie != '') {
		cookie = decodeURIComponent(cookie);
		fieldHist[field] = cookie.split('\n');
	}
	else {
		fieldHist[field] = [];
	}
	return;
}


//
// SaveHistoryToCookie: save the input box history to the respective cookie
//

function SaveHistoryToCookie(field) {
	var cookieExpire = new Date();
	cookieExpire.setTime( cookieExpire.getTime() + cookieExpireSec * 1000 );
	var cookie = '';
	cookie = fieldHist[field].join('\n')
	cookie = cookie.replace(/\n$/, '');
	cookie = encodeURIComponent(cookie);
	SetCookie(cookieName[field], cookie, cookieExpire.toGMTString());
	return;
}


// GetStyle: get computed style properties for non-inline css definitions
function GetStyle(element, styleProperty) {
	var style;
	if (element != null) {
		style = document.defaultView.getComputedStyle(element, null).getPropertyValue(styleProperty);
	}
	return(style);
}


//
// GetCookie
//

function GetCookie(name) {
	var cookie = ' ' + document.cookie;
	var search = ' ' + name + '=';
	var setStr = '';
	var offset = 0;
	var end = 0;
	offset = cookie.indexOf(search);
	if (offset != -1) {
		offset += search.length;
		end = cookie.indexOf(';', offset)
		if (end == -1) {
			end = cookie.length;
		}
		setStr = cookie.substring(offset, end);
		setStr = setStr.replace(/\\+/g, ' ');
		setStr = decodeURIComponent(setStr);
	}
	return(setStr);
}


//
// SetCookie
//

function SetCookie(name, value, expires, path, domain, secure) {
	var cookie = name + '=' + encodeURIComponent(value);
	if (expires != null) {
		cookie += '; expires=' + expires
	}
	if (path != null) {
		cookie += '; path=' + path;
	}
	if (domain != null)  {
		cookie += '; domain=' + domain;
	}
	if (secure != null) {
		cookie += '; secure';
	}
	document.cookie = cookie;
}


//
// GetOffsetTop: get element offset relative to left window border
//

function GetOffsetTop(element) {
	var offset = 0;
	do {
		offset += element.offsetTop;
	} while ( (element = element.offsetParent) != null );
	return(offset);
}


//
// GetOffsetLeft: get element offset relative to left window border
//

function GetOffsetLeft (element) {
	var offset = 0;
	do {
		offset += element.offsetLeft;
	} while ( (element = element.offsetParent) != null );
	return(offset);
}

//
// GetCursorTextPos
//

function GetCursorTextPos(obj, currentNode) {

	for (var i = 0; i < currentNode.childNodes.length; i ++) {
		var childNode = currentNode.childNodes.item(i);

// get the position for a given container
		if (childNode == obj.selRange.startContainer) {
			obj.startContainerPos = obj.plain.length;
		}
		if (childNode == obj.selRange.endContainer) {
			obj.endContainerPos = obj.plain.length;
			return;
		}

		switch (childNode.nodeType) {
			case 1:
				if ( (childNode.childNodes.length == 0) && leafElements[childNode.nodeName] ) {
					if (childNode.nodeName == 'BR') {
						obj.plain += '\n';
					}
				}
				else {
					GetCursorTextPos(obj, childNode);
				}
				break;
			case 3:
				var value = childNode.nodeValue;
				value = value.replace(/</g, '&lt;');
				value = value.replace(/>/g, '&gt;');
				obj.plain += value;
				break;
			case 5:
				var value = '&' + childNode.nodeName + ';';
				obj.plain += value;
				break;
		}
	}
	return;
}


//
// GetTextPosContainer
// sets obj.startContainerm, obj.startOffset, obj.endContainer, obj.endOffset for obj.startPos, obj.endPos



function GetTextPosContainer(obj, currentNode) {

	for (var i = 0; i < currentNode.childNodes.length; i ++) {
		var childNode = currentNode.childNodes.item(i);
		var textLength = obj.plain.length;
		switch (childNode.nodeType) {
			case 1:
				if ( (childNode.childNodes.length == 0) && leafElements[childNode.nodeName] ) {
					if (childNode.nodeName == 'BR') {
						obj.plain += '\n';
					}
				}
				else {
					GetTextPosContainer(obj, childNode);
					if (obj.endOffset != null) {
						return;
					}
				}
				break;
			case 3:
				var value = childNode.nodeValue;
				value = value.replace(/</g, '&lt;');
				value = value.replace(/>/g, '&gt;');
				obj.plain += value;
				break;
			case 5:
				var value = '&' + childNode.nodeName + ';';
				obj.plain += value;
				break;
		}

// get the container for a given position
		if (obj.startOffset == null) {
			if (obj.plain.length >= obj.startPos) {
			 	obj.startContainer = childNode;
			 	obj.startOffset = obj.startPos - textLength;
			}
		}
		if (obj.plain.length >= obj.endPos) {
		 	obj.endContainer = childNode;
		 	obj.endOffset = obj.endPos - textLength;
			return;
		}
	}
	return;
}


// define leaf elements for GetInnerHTML
var leafElements = [];
leafElements['IMG'] = true;
leafElements['HR'] = true;
leafElements['BR'] = true;
leafElements['INPUT'] = true;



//
// ParseDOM:
//

function ParseDOM(obj, topNode) {

	obj.plainLength = 0;
	obj.plainArray = [];
	obj.plainNode = [];
	obj.plainStart = [];
	obj.plainPos = [];
	ParseDOMRecursive(obj, topNode);
	obj.plain = obj.plainArray.join('');

	return;
}


//
// ParseDOMRecursive:
//

function ParseDOMRecursive(obj, currentNode) {

// cycle through the child nodes of currentNode
	for each (var childNode in currentNode.childNodes) {

// check for selection
		if (childNode == obj.sel.focusNode) {
			obj.plainFocus = obj.plainLength + obj.sel.focusOffset;
		}
		if (childNode == obj.sel.anchorNode) {
			obj.plainAnchor = obj.plainLength + obj.sel.anchorOffset;
		}
		var value = null;

// get text of child node
		switch (childNode.nodeType) {
			case 1:
				if ( (childNode.childNodes.length == 0) && (leafElements[childNode.nodeName] == true) ) {
					if (childNode.nodeName == 'BR') {
						value = '\n';
					}
				}
				else {
					ParseDOMRecursive(obj, childNode);
				}
				break;
			case 3:
				value = childNode.nodeValue;
				break;
			case 5:
				value = '&' + childNode.nodeName + ';';
				break;
		}

// add text to text object
		if (value != null) {

// array of text fragments
			obj.plainArray.push(value);

// array of text fragment node references
			obj.plainNode.push(childNode);

// array of text fragment text positions
			obj.plainStart.push(obj.plainLength);

// node references containing text positions
 			obj.plainPos[childNode] = obj.plainLength;

// current text length
 			obj.plainLength += value.length;
		}
	}
	return;
}


//
// GetInnerHTML: get innerHTML from document fragment
//

function GetInnerHTML(obj, currentNode) {

// initialize string
	if (obj.html == null) {
		obj.html = '';
	}
	if (obj.plain == null) {
		obj.plain = '';
	}
	if (obj.plainArray == null) {
		obj.plainArray = [];
		obj.plainNode = [];
		obj.plainStart = [];
	}

	for (var i = 0; i < currentNode.childNodes.length; i ++) {
		var childNode = currentNode.childNodes.item(i);
		switch (childNode.nodeType) {
			case 1:
				obj.html += '<' + childNode.nodeName.toLowerCase();
				for (var j = 0; j < childNode.attributes.length; j ++) {
					if (childNode.attributes.item(j).nodeValue != null) {
						obj.html += ' ' + childNode.attributes.item(j).nodeName + '="' + childNode.attributes.item(j).nodeValue.replace(/</g, '&lt;').replace(/>/g, '&gt;') + '"';
					}
				}
				if ( (childNode.childNodes.length == 0) && leafElements[childNode.nodeName] ) {
					obj.html += '>';
					if (childNode.nodeName == 'BR') {
						obj.plainArray.push('\n');
						obj.plainNode.push(childNode);
						obj.plainStart.push(obj.plain.length);
						obj.plain += '\n';
					}
				}
				else {
					obj.html += '>';
					GetInnerHTML(obj, childNode);
					obj.html += '</' + childNode.nodeName.toLowerCase() + '>'
				}
				break;
			case 3:
				var value = childNode.nodeValue;
				value = value.replace(/</g, '&lt;');
				value = value.replace(/>/g, '&gt;');
				obj.html += value;
				obj.plainArray.push(value);
				obj.plainNode.push(childNode);
				obj.plainStart.push(obj.plain.length);
				obj.plain += value;
				break;
			case 4: obj.html += '<![CDATA[' + childNode.nodeValue + ']]>';
				break;
			case 5:
				var value = '&' + childNode.nodeName + ';';
				obj.html += value;
				obj.plainArray.push(value);
				obj.plainNode.push(childNode);
				obj.plainStart.push(obj.plain.length);
				obj.plain += value;
				break;
			case 8: obj.html += '<!--' + childNode.nodeValue + '-->';
				break;
		}
	}
	return;
}


// StyleSheet: create a new style sheet object
function StyleSheet(documentObject) {

	this.styleElement = null;
	if (documentObject == null) {
		documentObject = document;
	}

// IE
	if (documentObject.createStyleSheet) {
		this.styleElement = documentObject.createStyleSheet();
	}

// standards compliant browsers
	else {
		this.styleElement = documentObject.createElement('style');
		this.styleElement.from = 'text/css';
		var insert = documentObject.getElementsByTagName('head')[0];
		if (insert != null) {
			insert.appendChild(this.styleElement);
		}
	}

// add-a-rule method

// IE
	this.addRule = function(selector, declaration) {
		if (this.styleElement.addRule) {
			this.styleElement.addRule(selector, declaration);
		}

// standards compliant browsers
		else {
			if (this.styleElement.sheet != null) {
				if (this.styleElement.sheet.insertRule != null) {
					this.styleElement.sheet.insertRule(selector + ' { ' + declaration + ' } ', 0);
				}
			}
		}
	};
	return;
}

// Debug: print variable content
function Debug(objectName, object) {

	document.getElementById('textareaWrapper').style.display = 'block';
	if (objectName == null) {
		textareaObj.value = '';
		textareaObj.style.height = '10em';
	}
	else {
		textareaObj.value += objectName + ': ' + object + '\n';
	}
	return;
}

/* </nowiki></pre> */