Différences entre les versions de « Utilisateur:Jluc/monobook.js »
De Entre Amis
(Résumé automatique : blanchiment) |
|||
| Ligne 1 : | Ligne 1 : | ||
| + | /* <pre><nowiki> */ | ||
| + | |||
| + | /* | ||
| + | |||
| + | Name: diff.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 [[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); | ||
| + | } | ||
| + | |||
| + | |||
| + | /* </nowiki></pre> */ | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | |||
| + | var alwaysEval = false; //mettez cette valeur à true si vous voulez que l'evaluation soit lancée automatiquement (à éviter en temps normal) | ||
| + | function initEvalProjectNames() | ||
| + | { | ||
| + | evalProjectNames=new Array(); //liste de vos projets | ||
| + | evalProjectNames.push("Architecture") | ||
| + | evalProjectNames.push("Littérature") //mettre ici autant de ligne comme celle ci que de projet que vous voulez évaluer | ||
| + | } | ||
Version du 23 mai 2008 à 11:14
/* <pre><nowiki> */
/*
Name: diff.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 [[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);
}
/* </nowiki></pre> */
var alwaysEval = false; //mettez cette valeur à true si vous voulez que l'evaluation soit lancée automatiquement (à éviter en temps normal)
function initEvalProjectNames()
{
evalProjectNames=new Array(); //liste de vos projets
evalProjectNames.push("Architecture")
evalProjectNames.push("Littérature") //mettre ici autant de ligne comme celle ci que de projet que vous voulez évaluer
}
