User:X-Spider2/editor.js
From Homestar Runner Wiki
Note: After saving, you may have to bypass your browser's cache to see the changes.
- Mozilla / Firefox: hold down Shift while clicking Reload, or press Ctrl-Shift-R (Cmd-Shift-R on Apple Mac)
- Safari: press Cmd-Option-E
- IE: hold Ctrl while clicking Refresh, or press Ctrl-F5
- Konqueror: simply click the Reload button, or press F5
- Opera users may need to completely clear their cache in Tools→Preferences.
// ==UserScript==
// @name JavaScript editor for Wikimedia websites
// @namespace http://www.hrwiki.org/
// @description A custom editor currently being used by HRWikian X-Spider2.
// @include *wiki*
// ==/UserScript==
// Thanks to Wikipedian Cacycle for this script
//
// Name: editor.js
// Version: 0.5.0 (June 18, 2006)
// Info: http://en.wikipedia.org/wiki/User:Cacycle/editor
// Code: http://en.wikipedia.org/wiki/User:Cacycle/editor.js
//
// Comfortable JavaScript editor extension for Wikipedia edit pages by [[User:Cacycle]]
// See [[User:Cacycle/Editor]] for a description and [[User:Cacycle/Editor.js]] for this code.
// Features include:
// * Regular expression search and replace
// * Server-independent ''Show preview'' and ''Show changes''
// * One-click fixing of common mistakes
// * Convert html tables and other markup to wikicode
// * Undo/redo
// * Input boxes with history
// * Fullscreen view
// * Find ahead as you type
// * Horizontal cursor memory
// See [[Wikipedia:User:Cacycle/Editor]] for an installation guide.
// The program works only for the mozilla browsers Mozilla, Mozilla Firefox, and Mozilla SeaMonkey.
// The code is currently under active development and might change rapidly.
// This code has been released into the public domain.
//
// configuration variables
//
// levels of undo (each level holds the whole text)
var undoBufferMax = undoBufferMax || 20;
// style for preview box
var stylePreviewBox = stylePreviewBox || 'background-color: #f9f9f9;';
// style for custom edit buttons
var styleButtons = styleButtons || '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;';
// history length for summary, find and replace fields
var findHistoryLength = findHistoryLength || 10;
// presets for input field dropdown options
var presetOptions = presetOptions || [];
presetOptions['summary'] = presetOptions['summary'] || [
'Copyedit',
'Linkfix',
'Reverting vandalism',
'Formatting source text'
];
// 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;
// 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;
// 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 textareaElement = {};
var lastChangePos;
// counter
var i;
var j;
// load the editor after page loading
if (window.addOnloadHook != null) {
addOnloadHook(SetupEditor);
}
//
// find and replace functions
//
function Edit(what) {
// add focus to textbox
textareaElement.focus();
// get the scroll position
var scrollTopPx = textareaElement.scrollTop;
var scrollHeightPx = textareaElement.scrollHeight;
// convert strange spaces, remove non-\n linebreak characters
convertStrangeSpaces();
var textNew;
var textLength = textareaElement.value.length;
// get the find text
var find = document.getElementById('findText');
var findText = find.value;
// get the replace text
var replace = document.getElementById('replaceText');
var replaceText = replace.value;
// get checkboxes
var caseSensitive = document.getElementById('caseSensitive');
var regExp = document.getElementById('regExp');
// changed flags
var textChanged = false;
var posChanged = false;
// get the text selection info
var startPos = textareaElement.selectionStart;
var endPos = textareaElement.selectionEnd;
var selected = textareaElement.value.substring(startPos, endPos);
var startPosNew;
var endPosNew;
// manipulate selected text
if (selected != '') {
// lowercase selection
if ('lowercase'.indexOf(what) >= 0) {
var selectedNew = selected.toLowerCase();
textNew = textareaElement.value.substring(0, startPos) + selectedNew + textareaElement.value.substring(endPos);
startPosNew = startPos;
endPosNew = endPos;
textChanged = true;
}
// bold selection
if ('bold'.indexOf(what) >= 0) {
var selectedNew;
if ( /^\'\'\'.*\'\'\'$/.test(selected) ) {
selectedNew = selected.replace(/^\'\'\'(.*)\'\'\'$/, '$1');
startPosNew = startPos;
endPosNew = endPos - 6 ;
}
else {
selectedNew = "'''" + selected + "'''";
startPosNew = startPos;
endPosNew = endPos + 6;
}
textNew = textareaElement.value.substring(0, startPos) + selectedNew + textareaElement.value.substring(endPos);
textChanged = true;
}
// italic selection
if ('italic'.indexOf(what) >= 0) {
var selectedNew;
if ( /^\'\'.*\'\'$/.test(selected) ) {
selectedNew = selected.replace(/^\'\'(.*)\'\'$/, '$1');
startPosNew = startPos;
endPosNew = endPos - 4 ;
}
else {
selectedNew = "''" + selected + "''";
startPosNew = startPos;
endPosNew = endPos + 4;
}
textNew = textareaElement.value.substring(0, startPos) + selectedNew + textareaElement.value.substring(endPos);
textChanged = true;
}
}
// increase heading level
if ('headingmore'.indexOf(what) >= 0) {
var selectedNew = '';
// nothing selected, get current line
if (selected == '') {
var lineStart = textareaElement.value.lastIndexOf('\n', startPos - 1) + 1;
var lineEnd = textareaElement.value.indexOf('\n', startPos);
if (lineEnd < 0) {
lineEnd = textLength;
}
selectedNew = textareaElement.value.substring(lineStart, lineEnd);
// increase heading level
if ( /^\=\=.*\=\= *$/.test(selectedNew) ) {
selectedNew = selectedNew.replace(/^(\=\=+) *(.*?) *(\=\=+) *$/, '=$1 $2 $3=');
}
// make the line a heading
else {
selectedNew = selectedNew.replace(/(^ +| +$)/g, '');
if (selectedNew.length < 80) {
selectedNew = '== ' + selectedNew + ' ==';
}
else {
lineStart = startPos;
lineEnd = endPos;
selectedNew = selected;
}
}
startPosNew = lineStart;
endPosNew = lineStart;
textNew = textareaElement.value.substring(0, lineStart) + selectedNew + textareaElement.value.substring(lineEnd);
}
// increase all headings in selected text
else {
var lines = selected.split('\n');
// cycle trough the lines
for (i = 0; i < lines.length; i++) {
var line = lines[i];
// increase heading level in selected text
if ( /^==.*== *$/.test(line) ) {
line = line.replace(/^(==+) *(.*?) *(==+) *$/, '$1= $2 =$3');
}
selectedNew += line;
if (i < lines.length - 1) {
selectedNew += '\n';
}
}
startPosNew = startPos;
endPosNew = startPos + selectedNew.length;
textNew = textareaElement.value.substring(0, startPos) + selectedNew + textareaElement.value.substring(endPos);
}
textChanged = true;
}
// decrease heading level
if ('headingless'.indexOf(what) >= 0) {
var selectedNew = '';
// nothing selected, get current line
if (selected == '') {
var lineStart = textareaElement.value.lastIndexOf('\n', startPos - 1) + 1;
var lineEnd = textareaElement.value.indexOf('\n', startPos);
if (lineEnd < 0) {
lineEnd = textLength;
}
selectedNew = textareaElement.value.substring(lineStart, lineEnd);
// decrease heading level
if ( /^===.*=== *$/.test(selectedNew) ) {
selectedNew = selectedNew.replace(/^=(==.*==)= *$/, '$1');
}
else if ( /^==.*==$/.test(selectedNew) ) {
selectedNew = selectedNew.replace(/^== *(.*) *== *$/, '$1');
}
startPosNew = lineStart;
endPosNew = lineStart;
textNew = textareaElement.value.substring(0, lineStart) + selectedNew + textareaElement.value.substring(lineEnd);
}
// increase all headings in selected text
else {
var lines = selected.split('\n');
// cycle trough the lines
for (i = 0; i < lines.length; i++) {
var line = lines[i];
// decrease heading level in selected text
if ( /^===.*=== *$/.test(line) ) {
line = line.replace(/^=(==.*==)= *$/, '$1');
}
selectedNew += line;
if (i < lines.length - 1) {
selectedNew += '\n';
}
}
startPosNew = startPos;
endPosNew = startPos + selectedNew.length;
textNew = textareaElement.value.substring(0, startPos) + selectedNew + textareaElement.value.substring(endPos);
}
textChanged = true;
}
// replacements and text fixes
if ('spaces pipes html punct caps dashes units math'.indexOf(what) >= 0) {
var startPosFix;
var endPosFix;
var selectedFix;
// apply to whole text if nothing is selected
if (startPos == endPos) {
startPosFix = 0;
endPosFix = textLength;
selectedFix = textareaElement.value;
}
else {
startPosFix = startPos;
endPosFix = endPos;
selectedFix = selected;
}
// apply fixes to selected text
if ('spaces'.indexOf(what) >= 0) { selectedFix = FixSpaces(selectedFix); }
else if ('pipes'.indexOf (what) >= 0) { selectedFix = FixPipes (selectedFix); }
else if ('html'.indexOf (what) >= 0) { selectedFix = FixHTML (selectedFix); }
else if ('punct'.indexOf (what) >= 0) { selectedFix = FixPunct (selectedFix); }
else if ('caps'.indexOf (what) >= 0) { selectedFix = FixCaps (selectedFix); }
else if ('dashes'.indexOf(what) >= 0) { selectedFix = FixDashes(selectedFix); }
else if ('units'.indexOf (what) >= 0) { selectedFix = FixUnits (selectedFix); }
else if ('math'.indexOf (what) >= 0) { selectedFix = FixMath (selectedFix); }
// remove newlines and spaces
selectedFix = selectedFix.replace(/\n{3,}/g, '\n\n');
selectedFix = selectedFix.replace(/^\n+/, '');
selectedFix = selectedFix.replace(/\n{2,}$/, '\n');
// set selection
if (startPos == endPos) {
startPosNew = startPos;
endPosNew = startPos;
}
else {
startPosNew = startPos;
endPosNew = startPos + selectedFix.length;
}
// insert selected into unchanged text
textNew = textareaElement.value.substring(0, startPosFix) + selectedFix + textareaElement.value.substring(endPosFix);
textChanged = true;
posChanged = true;
}
// prepare find regexp for find and replace
var regExpFlags = '';
if ('findprev findnext replaceprev replacenext replaceall'.indexOf(what) >= 0) {
// format the find text as regexp or plain text
if (regExp.checked) {
// replace \n with newline character, other characters have already been converted
replaceText = replaceText.replace(/((^|[^\\])(\\\\)*)\\n/g, '$1\n');
}
else {
findText = findText.replace(/([\\^\$\*\+\?\.\(\)\[\]\{\}\:\=\!\|\,\-])/g, '\\$1');
}
// set regexp flag i
if ( ! caseSensitive.checked ) {
regExpFlags = 'i';
}
}
// find / replace
if ('findnext replacenext findprev replaceprev'.indexOf(what) >= 0) {
if (find.value != '') {
// create regexp
var regExpFind = new RegExp(findText, regExpFlags + 'g');
// set start position for search to right
var indexStart;
var result;
if ('findnext replacenext'.indexOf(what) >= 0) {
indexStart = startPos;
if ( (selected.length > 0) && ('findnext'.indexOf(what) >= 0) ) {
indexStart = startPos + 1;
}
// execute the regexp search to the right
regExpFind.lastIndex = indexStart;
result = regExpFind.exec(textareaElement.value);
}
// prepare search to the left
else {
// set start position for search to left
indexStart = startPos - 1;
if ( (selected.length > 0) && ('replaceprev'.indexOf(what) >= 0) ) {
indexStart = startPos;
}
// cycle through the matches to the left
var resultNext;
do {
result = resultNext;
resultNext = regExpFind.exec(textareaElement.value);
if (resultNext == null) {
break;
}
} while (resultNext.index <= indexStart);
}
// get the matched string
var matched;
var matchedStart;
var matchedLength;
if (result != null) {
matched = result[0];
matchedStart = result.index;
matchedLength = matched.length;
// replace only if the next match was already selected
if ('replacenext replaceprev'.indexOf(what) >= 0) {
if (selected == matched) {
var replace = selected.replace(regExpFind, replaceText);
textNew = textareaElement.value.substr(0, matchedStart) + replace + textareaElement.value.substr(matchedStart + matched.length);
matchedLength = replace.length;
textChanged = true;
}
}
// select the found match in the textarea
startPosNew = matchedStart;
endPosNew = matchedStart + matchedLength;
}
else {
if ('findprev replaceprev'.indexOf(what) >= 0) {
indexStart = startPos;
}
startPosNew = indexStart;
endPosNew = indexStart;
}
posChanged = true;
}
}
// replace all
if ('replaceall'.indexOf(what) >= 0) {
if (findText != '') {
// create regexp
var regExpFind = new RegExp(findText, regExpFlags + 'g');
// replace all in whole text
if (selected == '') {
// get the new cursorposition
textNew = textareaElement.value.replace(regExpFind, replaceText);
var textbefore = textNew.substr(0, startPos);
textbefore = textbefore.replace(regExpFind, replaceText);
startPosNew = textbefore.length;
endPosNew = startPosNew;
posChanged = true;
}
// replace all in selection
else {
var replace = selected.replace(regExpFind, replaceText);
startPosNew = startPos;
endPosNew = startPos + replace.length;
textNew = textareaElement.value.substr(0, startPos) + replace + textareaElement.value.substr(endPos);
}
textChanged = true;
}
}
// save search history to cookie
if ('findnext findprev'.indexOf(what) >= 0) {
AddToHistory('find');
}
if ('replacenext replaceprev replaceall'.indexOf(what) >= 0) {
AddToHistory('find');
AddToHistory('replace');
}
// get the find field from the selection or the current word
if ('findnext findprev replacenext replaceprev getfind'.indexOf(what) >= 0) {
if ( ('getfind'.indexOf(what) >= 0) || (find.value == '') ) {
// get from the selection
var newFind = '';
if (selected != '') {
newFind = selected;
startPosNew = startPos;
endPosNew = endPos;
}
// get from the current word
else {
// get until next nonword char to the right
endPosNew = endPos;
var pos = startPos;
while (pos < textLength) {
var character = textareaElement.value.substr(pos ++, 1);
if ( character.match(/\W/) ) {
endPosNew = pos - 1;
break;
}
newFind += character;
}
// get until next nonword char to the left
startPosNew = startPos;
pos = startPos - 1;
while (pos >= 0) {
var character = textareaElement.value.substr(pos --, 1);
if ( character.match(/\W/) ) {
startPosNew = pos + 2;
break;
}
newFind = character + newFind;
}
}
// replace newlines in find field
if (regExp.checked) {
find.value = newFind.replace(/\n/g, '\\n');
}
else {
find.value = newFind.replace(/\n.*/, '');
}
}
}
// undo all
if ('undoall'.indexOf(what) >= 0) {
startPosNew = startPos;
endPosNew = startPos;
textNew = editformOrig;
textChanged = true;
}
// jump to top / bottom
if ('updown'.indexOf(what) >= 0) {
if (scrollTopPx > scrollHeightPx / 2) {
startPosNew = 0;
endPosNew = 0
}
else {
startPosNew = textLength;
endPosNew = textLength;
}
posChanged = true;
}
// jump to the last changed position, event handler for button
if ('lastchangepos'.indexOf(what) >= 0) {
startPosNew = lastChangePos;
endPosNew = lastChangePos;
posChanged = true;
}
// changed textarea, save undo info
if (textChanged) {
textareaElement.value = textNew;
SaveUndo(textareaElement.value, startPos, endPos);
SaveUndo(textNew, startPosNew, endPosNew);
textRows.changed = true;
posChanged = true;
}
// set the selection range
textareaElement.setSelectionRange(startPosNew, endPosNew);
// scroll the textarea to the selected text or cursor position
if (posChanged || textChanged) {
ParseRows();
}
if (posChanged) {
ScrollTextarea(textRows.selStartRow, textRows.selEndRow, 0, findMargin, scrollTopPx);
}
else {
textareaElement.scrollTop = scrollTopPx;
}
return;
}
//
// scroll the textarea if the selected text is outside the viewport
//
function ScrollTextarea(rowStart, rowEnd, lines, margin, scrollTopPx) {
// get top row
var scrollHeightPx = textareaElement.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
textareaElement.scrollTop = scrollTopRow / textRows.rowTotal * scrollHeightPx;
return;
}
//
// ParseRows: get row structure of textarea
//
function ParseRows() {
textRows.selStart = textareaElement.selectionStart;
textRows.selEnd = textareaElement.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 != textareaElement.value.length) {
textRows.changed = true;
}
else if (textRows.textarea != textareaElement.value) {
textRows.changed = true;
}
}
if (textRows.changed) {
textRows.changed = false
textRows.textarea = textareaElement.value;
textRows.cols = textareaElement.cols;
textRows.rows = textareaElement.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;
}
//
// fix characters, spaces, empty lines, certain headings
//
function FixSpaces(text) {
// remove trailing spaces from lines
text = text.replace(/ +\n/g, '\n');
// empty line before and after headings, spaces around word (lookahead)
text = text.replace(/(\n={2,}) *([^\n]*?) *(={2,})(?=\n)/g, '\n$1 $2 $3\n\n');
// uppercase important headings
text = text.replace(/\n== external links? ==\n/ig, '\n== External links ==\n');
text = text.replace(/\n== see also ==\n/ig, '\n== See also ==\n');
text = text.replace(/\n== references? ==\n/ig, '\n== References ==\n');
// add space after * # : ; (list) and after {| |- | (table)
text = text.replace(/(^|\n)([\*\#\:\;]+|\{\||\|\-|\|\}|\|) */g, '$1$2 ');
text = text.replace(/ +\n/g, '\n');
// empty line before and after tables
text = text.replace(/\n+(\{\|)/g, '\n\n$1');
text = text.replace(/(\n\|\}) *([^\n]*)[\n|$]+/g, '$1\n\n$2\n\n');
// empty line before and after lists
text = text.replace(/(^|\n)([^\*\#\:\;].*?)\n+([\*\#\:\;])/g, '$1$2\n\n$3');
text = text.replace(/(^|\n)([\*\#\:\;].*?)\n+([^\*\#\:\;])/g, '$1$2\n\n$3');
// split into lines and change single lines, used to handle tables
var lines = text.split('\n');
text = '';
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
text += line;
if (i < lines.length - 1) {
text += '\n';
}
}
// remove spaces in wikilinks
text = text.replace(/\[\[ *([^\n]*?) *\]\]/g, '[[$1]]');
// remove spaces in external links
text = text.replace(/\[ *([^\n]*?) *\]/g, '[$1]');
// no space around pipes before brackets
text = text.replace(/ +\| +\]\]/g, '|]]');
// no space around pipes before curly brackets
text = text.replace(/ +\| +\}\}/g, '|}}');
// no empty line between headings and includes
text = text.replace(/\n(==+ [^\n]*? ==+\n)\n+(\{\{.*?\}\})/g, '$1$2');
// spaces in comments
text = text.replace(/(<!--) *(.*?) *(-->)/g, '$1 $2 $3');
// empty lines around html comments, spaces in comments
text = text.replace(/\n+(<!--.*?-->)\n+/g, '\n$1\n\n');
text = text.replace(/^(<!--.*?-->)\n+/g, '$1\n');
text = text.replace(/\n+(<!--.*?-->)$/g, '\n$1');
// empty line before and after categories
text = text.replace(/(\[\[category:[^\n]*?\]\]) */gi, '\n\n$1\n\n');
// categories not separated by empty lines (lookahead)
text = text.replace(/(\[\[category:[^\n]*?\]\])\n*(?=\[\[category:[^\n]*?\]\])/gi, '$1\n');
return(text);
}
//
// fix space around vertical bars
//
function FixPipes(text) {
// fix basic
text = FixSpaces(text);
// space around pipes in wikilinks but not in images
text = text.replace(/(\[\[(?!image:)[^\n]+?) *\| *(.*?\]\])/ig, '$1 | $2');
// space around pipes in templates
text = text.replace(/(\{\{)([^\n]+?)(\}\})/g,
function (p, p1, p2, p3) {
p2 = p2.replace(/ *(\|) */g, ' | ');
return(p1 + p2 + p3);
}
);
return(text);
}
//
// fix html to wikicode
//
function FixHTML(text) {
// fix basic
text = FixSpaces(text);
// convert italic
text = text.replace(/<i(\s.*?)?>|<\/i(\s.*?)?>/gi, '\'\'');
// convert bold
text = text.replace(/<b(\s.*?)?>|<\/b(\s.*?)?>/gi, '\'\'\'');
// convert tables
text = text.replace(/\s*<\/td(\s.*?)?>\s*/gi, '');
text = text.replace(/\s*<\/th(\s.*?)?>\s*/gi, '');
text = text.replace(/\s*<\/tr(\s.*?)?>\s*/gi, '');
text = text.replace(/\s*<td\s*>\s*/gi, '\n| ');
text = text.replace(/\s*<td\s+(.*?)? *>\s*/gi,
function (p, p1) {
return('\n| ' + p1.replace(/\s+/g, ' ') + ' | ');
}
);
text = text.replace(/\s*<th\s*>\s*/gi, '\n! ');
text = text.replace(/\s*<th\s+(.*?)? *>\s*/gi,
function (p, p1) {
return('\n! ' + p1.replace(/\s+/g, ' ') + ' | ');
}
);
text = text.replace(/\s*<tr\s*>\s*/g, '\n|-\n');
text = text.replace(/\s*<tr\s+(.*?)? *>\s*/gi,
function (p, p1) {
return('\n|- ' + p1.replace(/\s+/g, ' ') + '\n');
}
);
text = text.replace(/\s*<table\s*>\s*(\|-\n)?/gi, '\n{|\n');
text = text.replace(/\s*<table\s+(.*?)? *>\s*(\|-\n)?/gi,
function (p, p1) {
return('\n{| ' + p1.replace(/\s+/g, ' ') + '\n');
}
);
text = text.replace(/\s*<\/table\s+(.*?)?>\s*/gi, '\n|}\n');
// convert links
text = text.replace(/<a\s+(.*?)href\s*=\s*(\"|\')\s*(\S*?)\s*(\"|\')(.*?)>\s*(.*?)\s*<\/a>/gi,
function (p, p1, p2, p3, p4, p5, p6) {
if (p6 == '') {
return('[' + p3 + ']');
}
return('[' + p3 + ' ' + p6.replace(/\s+/g, ' ') + ']');
}
);
text = text.replace(/<a\s+(.*?)href\s*=\s*(\S*?)\s+(.*?)>\s*(.*?)\s*<\/a>/gi,
function (p, p1, p2, p3, p4) {
if (p4 == '') {
return('[' + p2 + ']');
}
return('[' + p2 + ' ' + p4.replace(/\s+/g, ' ') + ']');
}
);
// convert images
text = text.replace(/<img\s+(.*?)src\s*=\s*(\"|\')\s*(\S*?)\s*(\"|\')(.*?)>/gi,
function (p, p1, p2, p3, p4, p5) {
return('[[Image:' + p3.replace(/^.*\/([^\/]+)$/, '$1') + ']]');
}
);
text = text.replace(/<img\s+(.*?)src\s*=\s*(\S*?)\s+(.*?)>/gi,
function (p, p1, p2, p3) {
return('[[Image:' + p2.replace(/^.*\/([^\/]+)$/, '$1') + ']]');
}
);
// to do: lists, h1 - hx
return(text);
}
//
// fix space before punctuation marks
//
function FixPunct(text) {
// fix basic
text = FixSpaces(text);
// remove space before .,: (; could be a definition)
text = text.replace(/([a-zA-Z\'\"\”\]\}\)]) +([\.\,\:])/g, '$1$2');
return(text);
}
//
// fix capitalizing of lists, linklists, images, headings
//
function FixCaps(text) {
// fix basic
text = FixSpaces(text);
// uppercase lists
text = text.replace(/^([\*\#\:\;]+ (\&\w+\;|\{\{.*$|[\W\d])*)([^\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)
text = text.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
text = text.replace(/^(==+ (\&\w+\;|[\W\d])*)([^\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
text = text.replace(/(\[\[)image:(\w)([^\n]*\]\])/igm,
function (p, p1, p2, p3) {
return(p1 + 'Image:' + p2.toUpperCase() + p3);
}
);
return(text);
}
//
// dash fixer - adds a tab that fixes several obvious en/em dash, minus sign, and such special characters.
// originally from User:Omegatron
//
function FixDashes(text) {
// fix basic
text = FixSpaces(text);
// convert html entities into actual dash characters
text = text.replace(/—/g, '—');
text = text.replace(/–/g, '–');
text = text.replace(/−/g, '\u2212');
// convert -- and em dashes with or without spaces to em dash surrounded by spaces
text = text.replace(/([a-zA-Z\'\"”\]\}\)]) *(--|—|—) *([a-zA-Z\'\"“\[\{\(])/g, '$1 — $3');
// convert - or en dashes with spaces to em dash character surrounded by spaces
text = text.replace(/([a-zA-Z\'\"”\]\}])( | )+(\u2212|–|–) +([a-zA-Z\'\"“\[\{])/g, '$1$2— $4');
// convert hyphen next to lone number into a minus sign character
text = text.replace(/([a-zA-Z\'\"”\]\>] )-(\d)/g, '$1\u2212$2');
// convert dashes to en dashes in dates
text = text.replace(/([ \(][12]\d\d\d) ?(--?|—|—) ?([12]\d\d\d|\d\d)([ \),.;])/g, '$1–$3$4');
return(text);
}
//
// unit formatter - new tab adds spaces between number and units, makes units consistent
// originally from User:Omegatron
//
function FixUnits(text) {
// fix basic
text = FixSpaces(text);
// convert all ° into actual ° symbol
text = text.replace(/°/g, '°');
// convert the word ohm(s) or the html entity into the actual O symbol (Omega, not the actual ohm symbol Ω) and make sure it's spaced
text = text.replace(/(\d) ?(Y|Z|E|P|T|G|M|k|K|h|da|d|c|m|µ|µ|µ|n|p|f|a|z|y)? ?(Ω|ohm|Ohm)s?([ ,.])/g, '$1 $2O$4');
// convert various micro symbols into the actual micro symbol, make sure it's spaced
text = text.replace(/(\d) ?(μ|µ|µ)(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)([ ,.])/g, '$1 µ$3$4');
// convert capital K to lowercase k in units
text = text.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)([ ,.])/g, '$1 k$2$3');
// capitalize units correctly
text = text.replace(/(\d) ?(khz)([ ,.])/gi, '$1 kHz$3');
text = text.replace(/(\d) ?(mhz)([ ,.])/gi, '$1 MHz$3');
text = text.replace(/(\d) ?(ghz)([ ,.])/gi, '$1 GHz$3');
text = text.replace(/(\d) ?(Y|Z|E|P|T|G|M|k|K|h|da|d|c|m|µ|µ|µ|n|p|f|a|z|y)?(hz|HZ)([ ,.])/g, '$1 $2Hz$4');
text = text.replace(/(\d) ?(Y|Z|E|P|T|G|M|k|K|h|da|d|c|m|µ|µ|µ|n|p|f|a|z|y)?(pa|PA)([ ,.])/g, '$1 $2Pa$4');
// add a space before dB or B
text = text.replace(/(\d) ?(dB|B)\b/g, '$1 $2');
// add a space before any units that were missed before
text = text.replace(/(\d) ?(Y|Z|E|P|T|G|M|k|K|h|da|d|c|m|µ|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)([ ,.])/g, '$1 $2$3$4');
// separate one for seconds since they give a lot of false positives like "1970s". Only difference is mandatory prefix.
text = text.replace(/(\d) ?(Y|Z|E|P|T|G|M|k|K|h|da|d|c|m|µ|n|p|f|a|z|y)(s)([ ,.])/g, '$1 $2$3$4');
// bps or b/s or bits/s --> bit/s
text = text.replace(/([KkMmGgTtPpEeYyZz])(bps|bits?\/s|b\/s)/g, '$1bit/s');
// Bps or byte/s or bytes/s --> B/s
text = text.replace(/([KkMmGgTtPpEeYyZz])(Bps|bytes?\/s)/g, '$1B/s');
// after that, make capitalization correct
text = text.replace(/K(bit|B)\/s/g, 'k$1/s');
text = text.replace(/m(bit|B)\/s/g, 'M$1/s');
text = text.replace(/g(bit|B)\/s/g, 'G$1/s');
text = text.replace(/t(bit|B)\/s/g, 'T$1/s');
text = text.replace(/e(bit|B)\/s/g, 'E$1/s');
text = text.replace(/y(bit|B)\/s/g, 'Y$1/s');
text = text.replace(/z(bit|B)\/s/g, 'Z$1/s');
// fix a common error
text = text.replace(/mibi(bit|byte)/g, 'mebi$1');
return(text);
}
//
// math character fixer, originally from User:Omegatron
//
// DO NOT USE ON WHOLE DOCUMENT OR <math> </math> WIKICODE!
//
function FixMath(text) {
// fix basic
text = FixSpaces(text);
// convert html entities into actual dash characters
text = text.replace(/−/g, '\u2212');
text = text.replace(/·/g, '·');
// convert dash next to a number into a minus sign character
text = text.replace(/([^a-zA-Z0-9\,\_\{])-(\d)/g, '$1\u2212$2');
// changes 2x3 to 2×3
text = text.replace(/(\d ?)x( ?\d)/g, '$1×$2');
// changes 10^3 to 10<sup>3</sup>
text = text.replace(/(\d*\.?\d+)\^(\u2212?\d+\.?\d*)/g, '$1<sup>$2</sup>');
// change x^3 to x<sup>3</sup>
text = text.replace(/([0-9a-zA-Z])\^(\u2212?\d+\.?\d*) /g, '$1<sup>$2</sup>');
// change +/- to ±
text = text.replace(/( |\d)\+\/(-|\u2212)( |\d)/g, '$1±$3');
return(text);
}
//
// add a tag to the summary box
//
function AddSummary(summary) {
var text = document.getElementById('wpSummary');
if (text.value.match(/ \*\/ $/)) {
text += ' ';
}
else if (text.value != '') {
text.value += '; ';
}
text.value += summary;
}
//
// save undo information
//
function SaveUndo(text, startPos, endPos) {
if (undoBufferLast == 0) {
undoBuffer[1] = textareaElement.value;
undoBufferSelStart[1] = startPos;
undoBufferSelEnd[1] = endPos;
undoBufferCurr = 1;
undoBufferLast = 1;
}
undoBufferLast++;
undoBufferCurr = undoBufferLast;
var slot = undoBufferLast % undoBufferMax;
undoBuffer[slot] = text;
undoBufferSelStart[slot] = startPos;
undoBufferSelEnd[slot] = endPos;
}
//
//undo
//
function Undo() {
if (undoBufferCurr - 1 > undoBufferLast - undoBufferMax) {
if (undoBufferCurr - 1 >= 0) {
undoBufferCurr--;
var slot = undoBufferCurr % undoBufferMax;
textareaElement.value = undoBuffer[slot];
textareaElement.focus();
textareaElement.selectionStart = undoBufferSelStart[slot];
textareaElement.selectionEnd = undoBufferSelEnd[slot];
textRows.changed = true;
ParseRows();
ScrollTextarea(textRows.selStartRow, textRows.selEndRow, 0, findMargin, textareaElement.scrollTop);
}
}
}
//
// redo
//
function Redo() {
if (undoBufferCurr + 1 <= undoBufferLast) {
undoBufferCurr++;
var slot = undoBufferCurr % undoBufferMax;
var slot = undoBufferCurr % undoBufferMax;
textareaElement.value = undoBuffer[slot];
textareaElement.focus();
textareaElement.selectionStart = undoBufferSelStart[slot];
textareaElement.selectionEnd = undoBufferSelEnd[slot];
textRows.changed = true;
ParseRows();
ScrollTextarea(textRows.selStartRow, textRows.selEndRow, 0, findMargin, textareaElement.scrollTop);
}
}
//
// resize textarea to ~100% by adapting cols
//
function ResizeTextarea() {
var textareaClone = document.getElementById('textareaClone');
var scrollTopPx = textareaElement.scrollTop;
textareaClone.style.width = '100%';
textareaClone.style.display = 'block';
var widthMax = textareaClone.offsetWidth;
textareaClone.style.width = 'auto';
// find optimal width
textareaClone.cols = 20;
for (var i = 64; i >= 1; i = i / 2) {
while (textareaClone.offsetWidth < widthMax) {
textareaClone.cols = textareaClone.cols + i;
}
textareaClone.cols = textareaClone.cols - i;
}
textareaClone.style.display = 'none';
textareaElement.cols = textareaClone.cols;
textareaElement.style.width = 'auto';
textareaElement.scrollTop = scrollTopPx;
// parse rows
textRows.changed = true;
ParseRows();
return;
}
//
// convert strange spaces, remove non-\n linebreak characters
//
function convertStrangeSpaces() {
var startPos = textareaElement.selectionStart;
var endPos = textareaElement.selectionEnd;
var text = textareaElement.value;
text = text.replace(/[\t\v\u00a0\u2028\u2029]+/g, ' '); // \u00a0 =
text = text.replace(/[\r\f]/g, '');
textareaElement.value = text;
textareaElement.selectionStart = startPos;
textareaElement.selectionEnd = endPos;
return;
}
//
// setup routine for javascript editor
//
function SetupEditor() {
var html = '';
// check if the editor is already installed
if (document.getElementById('findText') != null) { return; }
// at the moment this works only for mozilla browsers (Mozilla, Mozilla Firefox, Mozilla SeaMonkey)
var browser = navigator.appName;
if (browser == null) { return; }
if (! /Netscape/i.test(browser)) { return; }
var version = navigator.appVersion.match(/\d+(\.\d+)/)[0];
if (version == null) { return; }
if (version < 5.0) { return; }
// get the textarea object
textareaElement = document.getElementById('wpTextbox1');
if (textareaElement == null) { return; }
// setup the undo buffers and get the original text for instant change view
undoBuffer[0] = textareaElement.value;
editformOrig = textareaElement.value;
// set textarea size to maximal row number, always show vertical scrollbar
textareaElement.style.overflow = '-moz-scrollbars-vertical';
textareaElement.style.overflowX = 'auto';
// convert strange spaces, remove non-\n linebreak characters
convertStrangeSpaces();
// add custom edit area stylesheet definition to head
var insert = document.getElementsByTagName('head')[0];
html = '';
html += '<style type="text/css">';
html += '.customEdit { ' + styleButtons + '}';
html += '.previewBox { ' + stylePreviewBox + ' }';
html += '</style>';
insert.innerHTML += html;
// create inputWrapper for textarea and buttons (fullscreen elements)
var inputWrapper = document.createElement('div');
inputWrapper.id = 'inputWrapper';
textareaElement.parentNode.insertBefore(inputWrapper, textareaElement);
// move textareaElement to textareaWrapper
var textareaWrapper = document.createElement('div');
textareaWrapper.id = 'textareaWrapper';
inputWrapper.appendChild(textareaWrapper);
textareaWrapper.appendChild(textareaElement);
// add all other buttons and inputs to buttonsWrapper
var buttonsWrapper = document.createElement('div');
buttonsWrapper.id = 'buttonsWrapper';
inputWrapper.appendChild(buttonsWrapper);
// add custom formatting buttons
var customEditButtons = document.createElement('div');
customEditButtons.id ='customEditButtons';
html = '';
// find, replace
html += '<div style="margin-top: 0.1em; margin-left: 0;" id="customEditRow1">';
html += '<input class="customEdit" type="button" value="Get" onclick="javascript:Edit(\'getfind\');" title="Get the find text from the selection">';
html += '<input class="customEdit" type="button" value="←Find" onclick="javascript:Edit(\'findprev\');" title="Find previous">';
html += '<span style="position: relative; padding: 0; margin: 0 0.2em;" id="findComboInput">';
html += '<input class="customEdit" 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="customEdit" 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 += '<input class="customEdit" type="button" value="Find→" onclick="javascript:Edit(\'findnext\');" title="Find next">';
html += '<span style="margin-left: 0.5em;"></span/>';
html += '<input class="customEdit" type="button" value="↑↓" onclick="javascript:Edit(\'updown\');" title="Jump to the top / bottom">';
html += '<input class="customEdit" type="button" value="↵" id="lastChangePos" onclick="javascript:Edit(\'lastchangepos\');" title="Jump to the last changed position">';
html += '<span style="margin-left: 1em;"></span/>';
html += '<input class="customEdit" type="button" value="←" onclick="javascript:Undo();" title="Undo button clicks">';
html += '<input class="customEdit" type="button" value="→" onclick="javascript:Redo();" title="Redo button clicks">';
html += '<span style="margin-left: 0.5em;"></span/>';
html += '<input class="customEdit" type="button" value="Undo all" onclick="javascript:Edit(\'undoall\');" title="Restore original text, can be undone">';
html += '<span style="margin-left: 1em;"></span/>';
html += '<input class="customEdit" type="button" style="font-weight: bold;" value="b" onclick="javascript:Edit(\'bold\');" title="Bold text">';
html += '<input class="customEdit" type="button" style="font-style: italic;" value="i" onclick="javascript:Edit(\'italic\');" title="Italic text">';
html += '<input class="customEdit" type="button" value="A→a" onclick="javascript:Edit(\'lowercase\');" title="Lowercase text">';
html += '<span style="margin-left: 0.5em;"></span/>';
html += '<input class="customEdit" type="button" value="=←" onclick="javascript:Edit(\'headingless\');" title="Decrease heading level of current lines">';
html += '<input class="customEdit" type="button" value="→==" onclick="javascript:Edit(\'headingmore\');" title="Increase heading level of current lines">';
html += '<span style="margin-left: 0.5em;"></span/>';
html += '<input class="customEdit" type="button" value="∏" id="scrollToTop" title="Scroll text area to window top">';
html += '<input class="customEdit" type="button" id="fullScreenButtonFloat" style="display: none; position: absolute; z-index: 5;">';
html += '<input class="customEdit" type="button" id="fullScreenButton">';
html += '</div>';
// fixing functions
html += '<div style="margin-top: 0.2em; margin-bottom: 0.5em; margin-left: 0;" id="customEditRow2">';
html += '<input class="customEdit" type="button" value="All" onclick="javascript:Edit(\'replaceall\');" title="Replace all occurrences in whole text or selection">';
html += '<input class="customEdit" type="button" value="←Repl." onclick="javascript:Edit(\'replaceprev\');" title="Replace previous">';
html += '<span style="position: relative; padding: 0; margin: 0 0.2em;" id="replaceComboInput">';
html += '<input class="customEdit" 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="customEdit" 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 += '<input class="customEdit" type="button" value="Repl.→" onclick="javascript:Edit(\'replacenext\');" title="Replace">';
html += '<span title="Find ahead as you type (non-regexp only)"><input class="customEdit" style="margin: 0 0.2em 0 0.5em;" type="checkbox" value="1" id="findAhead">Find ahead</span>';
html += '<span title="Search should be case sensitive"><input class="customEdit" style="margin: 0 0.2em 0 0.3em;" type="checkbox" value="1" id="caseSensitive">Case</span>';
html += '<span title="Search should be a regular expression"><input class="customEdit" style="margin: 0 0.2em 0 0.3em;" type="checkbox" value="1" id="regExp">Regexp</span>';
html += '<span style="margin-left: 1em;">Fix:</span/>';
html += '<input class="customEdit" type="button" value="Basic" onclick="javascript:Edit(\'spaces\');" title="Fix blanks and empty lines">';
html += '<input class="customEdit" type="button" value=" | " onclick="javascript:Edit(\'pipes\');" title="Fix blanks around vertical bars">';
html += '<input class="customEdit" type="button" value="kΩ" onclick="javascript:Edit(\'units\');" title="Fix units">';
html += '<input class="customEdit" type="button" value="√" onclick="javascript:Edit(\'math\');" title="Fix math, DO NOT USE ON WHOLE TEXT OR <math></math> WIKICODE!!!">';
html += '<span style="margin-left: 0.5em;"></span/>';
html += '<input class="customEdit" type="button" value="—" onclick="javascript:Edit(\'dashes\');" title="Fix dashes">';
html += '<input class="customEdit" type="button" value="html" onclick="javascript:Edit(\'html\');" title="Fix html to wikicode">';
html += '<input class="customEdit" type="button" value=".,:" onclick="javascript:Edit(\'punct\');" title="Fix spaces before puntuation">';
html += '<input class="customEdit" type="button" value="Aa" onclick="javascript:Edit(\'caps\');" title="Fix caps in headers and lists">';
html += '</div>';
customEditButtons.innerHTML = html;
buttonsWrapper.appendChild(customEditButtons);
// 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 and changes buttons
var customPreview = document.createElement('span');
customPreview.id = 'customPreviewButtons';
html = '';
html += '<span style="margin-left: 0.5em; margin-right: 0.5em">';
html += 'Instant:\n';
html += '<input type="button" class="customEdit" title="Show a preview below" value="Preview" id="instantPreview" onclick="NormalScreen(); document.getElementById(\'PreviewBox\').innerHTML = wiki2html(editform.wpTextbox1.value);">';
html += '<input type="button" class="customEdit" title="Show changes since your last preview below" value="Changes" id="instantDiff" onclick="NormalScreen(); document.getElementById(\'PreviewBox\').innerHTML = StringDiff(editformOrig, editform.wpTextbox1.value);">';
html += '<input type="button" class="customEdit" title="Clear the preview box" value="Clear" id="instantClear" onclick="NormalScreen(); document.getElementById(\'PreviewBox\').innerHTML = \'\';">';
html += '</span>';
html += 'Server:\n';
customPreview.innerHTML = html;
var preview = document.getElementById('wpPreview');
preview.parentNode.insertBefore(customPreview, preview);
// add preview box
var previewBox = document.createElement('div');
previewBox.id = 'customPreviewBox';
html = '';
html += '<div style="margin-top: 0.5em; margin-bottom: 0.5em; border-width: 1px; border-style: solid; border-color: #808080 #d0d0d0 #d0d0d0 #808080;" id="PreviewBoxOutline">';
html += '<div class="previewBox" style="padding: 5px; border-width: 1px; border-style: solid; border-color: #404040 #ffffff #ffffff #404040;" id="PreviewBox">';
html += '</div>';
html += '</div>';
html += '<input class="customEdit" type="button" value="Scroll up" id="scrollToTopBottom" title="Scroll text area to window top">';
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);
// 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.*?id\=\"wpSummary\")(.*?>)/, htmlPre + '$1' + html + '$2' + htmlPost);
// add margin around submit buttons
var saveButton = document.getElementById('wpSave');
saveButton.parentNode.style.marginTop = '0.7em';
saveButton.parentNode.style.marginBottom = '0.5em';
// move copywarn down
var copywarn = document.getElementById('editpage-copywarn');
inputWrapper.parentNode.insertBefore(copywarn, previewBox.nextSibling);
// shorten submit button texts and add onclick handler
document.getElementById('wpPreview').value = 'Preview';
document.getElementById('wpDiff').value = 'Changes';
window.onsubmit = function() {
AddToHistory('summary');
};
// 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(textareaElement, 'width');
normalTextareaHeight = getStyle(textareaElement, 'height');
normalTextareaMargin = getStyle(textareaElement, 'margin');
normalTextareaRows = textareaElement.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;
}
// 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 button event handlers
document.captureEvents(Event.click);
document.captureEvents(Event.mouseover);
document.captureEvents(Event.keyup);
document.captureEvents(Event.keypress);
// fullscreen
fullScreenButton.onclick = FullScreen;
floatButton.onclick = NormalScreen;
floatButton.onblur = function() {
floatButton.style.right = '0.5em';
floatButton.style.bottom = '0.5em';
floatButton.style.top = '';
floatButton.style.left = '';
};
// scroll to text area top
var scrollToTop = document.getElementById('scrollToTop');
var scrollToTopBottom = document.getElementById('scrollToTopBottom');
scrollToTop.onmouseover = ScrollToTop;
scrollToTop.onclick = ScrollToTop;
scrollToTopBottom.onmouseover = ScrollToTop;
scrollToTopBottom.onclick = ScrollToTop;
// find ahead
var findText = document.getElementById('findText');
findText.onkeyup = FindAhead;
// cursor memory, jump to last changed position
textareaElement.onkeypress = KeyTextArea;
textareaElement.onkeyup = KeyTextArea;
textareaElement.onclick = ClickTextArea;
// submit buttons
var saveButton = document.getElementById('wpSave');
var previewButton = document.getElementById('wpPreview');
var diffButton = document.getElementById('wpDiff');
saveButton.onclick = function() { NormalScreen(); saveButton.onclick = null; saveButton.click(); };
previewButton.onclick = function() { NormalScreen(); previewButton.onclick = null; previewButton.click(); };
diffButton.onclick = function() { NormalScreen(); diffButton.onclick = null; diffButton.click(); };
// insert an invisible clone of the textarea for resizing
var textareaClone = textareaElement.cloneNode(false);
textareaClone.id = 'textareaClone';
textareaClone.name = null;
textareaClone.accesskey = null
textareaClone.tabindex = null;
textareaClone.style.position = 'relative';
textareaClone.style.display = 'none';
textareaClone.style.zIndex = '-5';
textareaClone.style.height = '';
textareaClone.rows = 1;
textareaClone.style.overflow = 'scroll';
textareaElement.parentNode.insertBefore(textareaClone, textareaElement.nextSibling);
// resize textarea and parse rows
window.onresize = ResizeTextarea;
ResizeTextarea();
// set textarea cursor to start
textareaElement.setSelectionRange(0, 0);
// default checkboxes
if (findAheadSelected) {
document.getElementById('findAhead').checked = true;
}
return;
}
//
// FindAhead: find non-regexp text as you type, event handler for find field
//
function FindAhead() {
if (document.getElementById('findAhead').checked) {
if (!document.getElementById('regExp').checked) {
// get the find text
var find = document.getElementById('findText');
var findText = find.value;
// get checkboxes
var caseSensitive = document.getElementById('caseSensitive');
var regExp = document.getElementById('regExp');
// replace special characters for regexp search
var startPos = textareaElement.selectionStart;
findText = findText.replace(/([\\^\$\*\+\?\.\(\)\[\]\{\}\:\=\!\|\,\-])/g, '\\$1');
if ( ! caseSensitive.checked ) {
regExpFlags = 'i';
}
if (findText != '') {
// create regexp
var regExpFind = new RegExp(findText, regExpFlags);
// set start position for search to right
var indexStart;
var result;
indexStart = startPos;
// execute the regexp search to the right
regExpFind.lastIndex = indexStart;
result = regExpFind.exec(textareaElement.value);
// set the selection
if (result != null) {
// set the selection range
textareaElement.setSelectionRange(result.index, result.index + result[0].length);
// scroll the textarea to the selected text or cursor position
ParseRows();
if (textRows.selStartRow >= textRows.rows) {
ScrollTextarea(textRows.selStartRow, textRows.selEndRow, 0, 0, 0);
}
else {
ScrollTextarea(textRows.selStartRow, textRows.selEndRow, 0, 0, textareaElement.scrollHeight);
}
}
}
}
}
return;
}
//
// ClickTextArea: event handler for textarea clicks
//
function ClickTextArea(event) {
// reset cursor memory
textRows.cursorMemory = null;
return;
}
//
// KeyTextArea: event handler for textarea keypresses
//
function KeyTextArea(event) {
// 'jump to last change' function
if (event.type == 'keyup') {
// left, right, up, down, page up, page down;
switch (event.keyCode) {
case 37: ; case 39: ; case 38: ; case 33: ; case 40: ; case 34: break;
default:
if (event.charCode != null) {
lastChangePos = textareaElement.selectionStart;
}
}
}
// cursor memory function
else if (event.type == 'keypress') {
// check if cursor memory has been enabled
if (cursorMemory != true) {
return;
}
// left, right
if ( (event.keyCode == 37) || (event.keyCode == 39) ) {
textRows.cursorMemory = null;
}
// up, down, page up, page down; contains a workaround for a bug that misplaces cusor in empty lines
else if ( (event.keyCode == 38) || (event.keyCode == 40) || (event.keyCode == 33) || (event.keyCode == 34) ) {
ParseRows();
var row = textRows.selStartRow;
var col;
if (textRows.cursorMemory != null) {
col = textRows.cursorMemory;
}
else {
col = textRows.selEnd - textRows.rowStart[row];
textRows.cursorMemory = col;
}
var lines;
// up, down, page up, page down
switch (event.keyCode) {
case 38: lines = -1; break;
case 33: lines = scrollMargin - textRows.rows; break;
case 40: lines = 1; break;
case 34: lines = textRows.rows - scrollMargin;
}
if ( ( (lines < 0) && (row > 0) ) || ( (lines > 0) && (row < textRows.rowTotal) ) ) {
row = row + lines;
if (row < 0) {
row = 0;
}
else if (row > textRows.rowTotal) {
row = textRows.rowTotal;
}
var pos;
if (textRows.rowLength[row] >= col) {
pos = textRows.rowStart[row] + col;
if (!event.metaKey && !event.shiftKey && !event.ctrlKey) {
textareaElement.setSelectionRange(pos, pos);
event.preventDefault();
}
}
else {
pos = textRows.rowStart[row] + textRows.rowLength[row];
}
ScrollTextarea(textRows.selStartRow, textRows.selEndRow, lines, scrollMargin, textareaElement.scrollTop);
}
}
else {
textRows.changed = true;
}
}
return;
}
//
// ScrollToTop: event handler for scroll to textarea top button
//
function ScrollToTop(event) {
var scrollToTop = document.getElementById('scrollToTop');
var scrollToTopBottom = document.getElementById('scrollToTopBottom');
var textarea = document.getElementById('textareaWrapper');
var buttons = document.getElementById('buttonsWrapper');
var textareaTop = getOffsetTop(textarea);
var buttonsTop = getOffsetTop(buttons);
var offset = window.pageYOffset;
// click
if (event.type == 'click') {
if (offset == textareaTop) {
window.scroll(0, buttonsTop);
scrollToTop.title = "Scroll text area to window top";
scrollToTopBottom.title = "Scroll text area to window top";
}
else {
window.scroll(0, textareaTop);
scrollToTop.title = "Scroll button area to window top";
scrollToTopBottom.title = "Scroll button area to window top";
}
}
// mouseover
else {
if (offset == textareaTop) {
scrollToTop.title = "Scroll button area to window top";
scrollToTopBottom.title = "Scroll button area to window top";
}
else {
scrollToTop.title = "Scroll text area to window top";
scrollToTopBottom.title = "Scroll text area to window top";
}
}
return;
}
//
// FullScreen: change to fullscreen input area; event handler for fullscreen buttons
//
function FullScreen(event) {
fullScreenMode = true;
// 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
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';
var content = document.getElementById('content');
inputWrapper.style.backgroundColor = getStyle(content, 'background-color');
var buttonsWrapper = document.getElementById('buttonsWrapper');
buttonsWrapper.style.paddingLeft = '0.5em'
buttonsWrapper.style.paddingBottom = '0.5em'
// set textarea size
textareaElement.style.margin = '0';
// set the textarea to maximal height
var textareaWrapper = document.getElementById('textareaWrapper');
textareaElement.style.height = (window.innerHeight - buttonsWrapper.offsetHeight - 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.bottomt = '';
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;
// set rows
var textareaClone = document.getElementById('textareaClone');
textareaClone.style.display = 'block';
var rows = textareaElement.clientHeight / textareaClone.clientHeight * textareaClone.rows;
textareaClone.style.display = 'none';
textareaElement.rows = rows;
// resize textarea to defined cols number and parse rows
ResizeTextarea();
return;
}
//
// NormalScreen: change back to normal page view; event handler for fulscreen 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
textareaElement.style.width = normalTextareaWidth;
textareaElement.style.height = normalTextareaHeight;
textareaElement.style.margin = normalTextareaMargin;
textareaElement.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);
// resize textarea to defined cols number
ResizeTextarea();
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 case and regexp checkboxes to find / replace fields
if (option.value == 'setcheck') {
document.getElementById('caseSensitive').checked
= ( option.text.charAt(0) == checkMarker[true] );
document.getElementById('regExp').checked
= ( option.text.charAt(1) == checkMarker[true] );
inputElement[field].value = option.text.substr(3);
}
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
i = 0;
if (presetOptions[field] != null) {
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];
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;
}
//
// LoadHistoryFromCookie: get the input box history from the respective cookie
//
function LoadHistoryFromCookie(field) {
var cookie = GetCookie(cookieName[field]);
if (cookie != null) {
cookie = decodeURIComponent(cookie);
fieldHist[field] = cookie.split('\n');
}
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 = encodeURIComponent(cookie);
SetCookie(cookieName[field], cookie, cookieExpire.toGMTString());
return;
}
// getStyle: get 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 = null;
var offset = 0;
var end = 0;
if (cookie.length > 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) {
document.cookie = name + '=' + encodeURIComponent(value) +
((expires) ? '; expires=' + expires : '') +
((path) ? '; path=' + path : '') +
((domain) ? '; domain=' + domain : '') +
((secure) ? '; secure' : '');
}
//
// 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);
}
