User:Zocky/wikEdDev.js

From Wikipedia, the free encyclopedia
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 || 'http://upload.wikimedia.org/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> */