MediaWiki:Gadget-TabOverride.js
注意:在发布之后,您可能需要清除浏览器缓存才能看到所作出的变更的影响。
- Firefox或Safari:按住Shift的同时单击刷新,或按Ctrl-F5或Ctrl-R(Mac为⌘-R)
- Google Chrome:按Ctrl-Shift-R(Mac为⌘-Shift-R)
- Internet Explorer或Edge:按住Ctrl的同时单击刷新,或按Ctrl-F5
- Opera:按 Ctrl-F5。
/** * @fileOverview The JavaScript component of the Tab Override MediaWiki extension * @author Bill Bryant * @version 2.0.1-MediaWiki * @note Rewritten by Jack Phoenix to work without legacy JS globals * @url http://tinsology.net/plugins/tab-override/ Original source code etc. */ // register the keydown event listener on the content textarea element // after the window is loaded to make sure that the element is accessible // using the document's getElementById method jQuery( document ).ready( function() { // only on edit pages (action=edit in the URL) // action=submit is preview mode (the "Show preview" button has been pressed) if ( mw.config.get( 'wgAction' ) !== 'edit' || mw.config.get( 'wgAction' ) !== 'submit' ) { return; } var content = jQuery( '#wpTextbox1' ); // the MediaWiki page edit textarea // if there is no content textarea element on this page, do nothing if ( !content.length ) { return; } content.keydown( function( e ) { var text, // initial text in the textarea range, // the IE TextRange object tempRange, // used to calculate selection start and end positions in IE preNewlines, // the number of newline (\r\n) characters before the selection start (for IE) selNewlines, // the number of newline (\r\n) characters within the selection (for IE) initScrollTop, // initial scrollTop value to fix scrolling in Firefox selStart, // the selection start position selEnd, // the selection end position sel, // the selected text startLine, // for multi-line selections, the first character position of the first line endLine, // for multi-line selections, the last character position of the last line numTabs, // the number of tabs inserted / removed in the selection startTab, // if a tab was removed from the start of the first line preTab; // if a tab was removed before the start of the selection // tab key - insert / remove tab if ( e.keyCode === 9 ) { // initialize variables text = this.value; initScrollTop = this.scrollTop; // scrollTop is supported by all modern browsers numTabs = 0; startTab = 0; preTab = 0; if ( typeof this.selectionStart !== 'undefined' ) { selStart = this.selectionStart; selEnd = this.selectionEnd; sel = text.slice( selStart, selEnd ); } else if ( document.selection ) { // IE range = document.selection.createRange(); sel = range.text; tempRange = range.duplicate(); tempRange.moveToElementText( this ); tempRange.setEndPoint( 'EndToEnd', range ); selEnd = tempRange.text.length; selStart = selEnd - sel.length; // whenever the value of the textarea is changed, the range needs to be reset // IE (and Opera) use both \r and \n for newlines - this adds an extra character // that needs to be accounted for when doing position calculations // these values are used to offset the selection start and end positions preNewlines = text.slice( 0, selStart ).split( '\r\n' ).length - 1; selNewlines = sel.split( '\r\n' ).length - 1; } else { // cannot access textarea selection - do nothing return; } // special case of multi-line selection if ( selStart !== selEnd && sel.indexOf( '\n' ) !== -1 ) { // for multiple lines, only insert / remove tabs from the beginning of each line // find the start of the first selected line if ( selStart === 0 || text.charAt( selStart - 1 ) === '\n' ) { // the selection starts at the beginning of a line startLine = selStart; } else { // the selection starts after the beginning of a line // set startLine to the beginning of the first partially selected line // subtract 1 from selStart in case the cursor is at the newline character, // for instance, if the very end of the previous line was selected // add 1 to get the next character after the newline // if there is none before the selection, lastIndexOf returns -1 // when 1 is added to that it becomes 0 and the first character is used startLine = text.lastIndexOf( '\n', selStart - 1 ) + 1; } // find the end of the last selected line if ( selEnd === text.length || text.charAt( selEnd ) === '\n' ) { // the selection ends at the end of a line endLine = selEnd; } else { // the selection ends before the end of a line // set endLine to the end of the last partially selected line endLine = text.indexOf( '\n', selEnd ); if ( endLine === -1 ) { endLine = text.length; } } // if the shift key was pressed, remove tabs instead of inserting them if ( e.shiftKey ) { if ( text.charAt( startLine ) === '\t' ) { // is this tab part of the selection? if ( startLine === selStart ) { // it is, remove it sel = sel.slice( 1 ); } else { // the tab comes before the selection preTab = 1; } startTab = 1; } this.value = text.slice( 0, startLine ) + text.slice( startLine + preTab, selStart ) + sel.replace( /\n\t/g, function() { numTabs += 1; return '\n'; }) + text.slice( selEnd ); // set start and end points if ( range ) { // IE // setting end first makes calculations easier range.collapse(); range.moveEnd( 'character', selEnd - startTab - numTabs - selNewlines - preNewlines ); range.moveStart( 'character', selStart - preTab - preNewlines ); range.select(); } else { // set start first for Opera this.selectionStart = selStart - preTab; // preTab is 0 or 1 // move the selection end over by the total number of tabs removed this.selectionEnd = selEnd - startTab - numTabs; } } else { // no shift key // insert tabs at the beginning of each line of the selection this.value = text.slice( 0, startLine ) + '\t' + text.slice( startLine, selStart ) + sel.replace( /\n/g, function() { numTabs += 1; return '\n\t'; }) + text.slice( selEnd ); // set start and end points if ( range ) { // IE range.collapse(); range.moveEnd( 'character', selEnd + 1 - preNewlines ); // numTabs cancels out selNewlines range.moveStart( 'character', selStart + 1 - preNewlines ); range.select(); } else { // the selection start is always moved by 1 character this.selectionStart = selStart + 1; // move the selection end over by the total number of tabs inserted this.selectionEnd = selEnd + 1 + numTabs; } } } else { // "normal" case (no selection or selection on one line only) // if the shift key was pressed, remove a tab instead of inserting one if ( e.shiftKey ) { // if the character before the selection is a tab, remove it if ( text.charAt( selStart - 1 ) === '\t' ) { this.value = text.slice( 0, selStart - 1 ) + text.slice( selStart ); // set start and end points if ( range ) { // IE // collapses range and moves it by -1 character range.move( 'character', selStart - 1 - preNewlines ); range.select(); } else { this.selectionEnd = this.selectionStart = selStart - 1; } } } else { // no shift key - insert a tab if ( range ) { // IE // if no text is selected and the cursor is at the beginning of a line // (except the first line), IE places the cursor at the carriage return character // the tab must be placed after the \r\n pair if ( text.charAt( selStart ) === '\r' ) { this.value = text.slice( 0, selStart + 2 ) + '\t' + text.slice( selEnd + 2 ); // collapse the range and move it to the appropriate location range.move( 'character', selStart + 2 - preNewlines ); } else { this.value = text.slice( 0, selStart ) + '\t' + text.slice( selEnd ); // collapse the range and move it to the appropriate location range.move( 'character', selStart + 1 - preNewlines ); } range.select(); } else { this.value = text.slice( 0, selStart ) + '\t' + text.slice( selEnd ); this.selectionEnd = this.selectionStart = selStart + 1; } } } // this is really just for Firefox, but will be executed by all browsers // whenever the textarea value property is reset, Firefox scrolls back to the top // this will reset it to the original scroll value this.scrollTop = initScrollTop; // prevent the default action if ( e.preventDefault ) { e.preventDefault(); } e.returnValue = false; } } ).keypress( function( e ) { // Opera (and Firefox) also fire a keypress event when the tab key is pressed // Opera requires that the default action be prevented on this event, or the // textarea will lose focus (preventDefault is enough, IE never fires this // for the tab key) if ( e.keyCode === 9 && e.preventDefault ) { e.preventDefault(); } } ); } );