|
[MediaWiki-CVS] SVN: [54041] trunk/extensions/UsabilityInitiative: msg#01419mediawiki-cvs
http://www.mediawiki.org/wiki/Special:Code/MediaWiki/54041 Revision: 54041 Author: tparscal Date: 2009-07-30 20:11:57 +0000 (Thu, 30 Jul 2009) Log Message: ----------- Restructure the UI, cleaned up code in the textSelection plugin and fixed impropper section 0 behavior. Modified Paths: -------------- trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.css trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.js trunk/extensions/UsabilityInitiative/NavigableTOC/NavigableTOC.css trunk/extensions/UsabilityInitiative/NavigableTOC/NavigableTOC.js trunk/extensions/UsabilityInitiative/js/jquery.combined.js trunk/extensions/UsabilityInitiative/js/jquery.combined.min.js trunk/extensions/UsabilityInitiative/js/jquery.textSelection.js trunk/extensions/UsabilityInitiative/js/jquery.wikiOutline.js Modified: trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.css =================================================================== --- trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.css 2009-07-30 19:29:04 UTC (rev 54040) +++ trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.css 2009-07-30 20:11:57 UTC (rev 54041) @@ -13,9 +13,11 @@ } /* ... */ div#edit-ui { + position: relative; border: solid silver 1px; background-color: #f3f3f3; clear: both; + line-height: 1em; } div#edit-toolbar { background-color: #F3F3F3; Modified: trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.js =================================================================== --- trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.js 2009-07-30 19:29:04 UTC (rev 54040) +++ trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.js 2009-07-30 20:11:57 UTC (rev 54041) @@ -1,26 +1,22 @@ /* JavaScript for EditToolbar extension */ js2AddOnloadHook( function() { - $j( 'textarea#wpTextbox1' ).wrap( + $j( 'textarea#wpTextbox1' ) + .wrap( $j( '<div></div>' ) .attr( 'id', 'edit-ui' ) ) + .wrap( $j( '<div></div>' ).attr( 'id', 'edit-ui-bottom' ) ) + .wrap( $j( '<div></div>' ).attr( 'id', 'edit-ui-text' ) ); + $j( 'div#edit-ui' ).prepend( $j( '<div></div>' ) - .attr( 'id', 'edit-ui' ) + .attr( 'id', 'edit-ui-top' ) + .append( + $j( '<div></div>' ) + .attr( 'id', 'edit-toolbar' ) + .toolbar( + $j( 'textarea#wpTextbox1' ), + editToolbarConfiguration + ) + ) ); - $j( 'textarea#wpTextbox1' ).wrap( - $j( '<div></div>' ) - .attr( 'id', 'edit-ui-left' ) - ); - $j( 'div#edit-ui' ).append( - $j( '<div></div>' ) - .attr( 'id', 'edit-ui-right' ) - ); - $j( 'div#edit-ui-left' ).prepend( - $j( '<div></div>' ) - .attr( 'id', 'edit-toolbar' ) - ); - $j( 'div#edit-toolbar' ).toolbar( - $j( 'textarea#wpTextbox1' ), - editToolbarConfiguration - ); }); /** Modified: trunk/extensions/UsabilityInitiative/NavigableTOC/NavigableTOC.css =================================================================== --- trunk/extensions/UsabilityInitiative/NavigableTOC/NavigableTOC.css 2009-07-30 19:29:04 UTC (rev 54040) +++ trunk/extensions/UsabilityInitiative/NavigableTOC/NavigableTOC.css 2009-07-30 20:11:57 UTC (rev 54041) @@ -1,29 +1,39 @@ /* CSS for NavigableTOC extension */ -div#edit-toc { - background-color: #f3f3f3; +div#edit-ui-bottom { + position: relative; } -div#edit-toc ul { - margin: 0.5em; +div#edit-ui-text { + margin-right: 12em; +} +div#edit-ui-toc { + position: absolute; + right: -1px; + top: 0; + width: 12em; padding: 0; + border-left: solid silver 1px; + overflow: auto; +} +div#edit-ui-toc ul { + padding: 0; + margin: 0.5em 1em; list-style: none; } -div#edit-toc ul ul { +div#edit-ui-toc ul ul { + padding: 0; margin: 0; - margin-left: 1em; + margin-left: 0.75em; + list-style: none; } -div#edit-toc ul li a.currentSelection { +div#edit-ui-toc ul li a { + display: block; + font-size: 0.9em; +} +div#edit-ui-toc ul li a.currentSelection { font-weight: bold; } -div#edit-ui-left { - margin-right: 12em; - border-right: solid silver 1px; -} -div#edit-ui-right { - position: absolute; - right: 0; - top: 0; - width: 12em; - border-right: solid silver 1px; - overflow: auto; +div#edit-ui-toc ul li a.section-0 { + font-size: 1em; + border-bottom: solid 1px #DDDDDD; } \ No newline at end of file Modified: trunk/extensions/UsabilityInitiative/NavigableTOC/NavigableTOC.js =================================================================== --- trunk/extensions/UsabilityInitiative/NavigableTOC/NavigableTOC.js 2009-07-30 19:29:04 UTC (rev 54040) +++ trunk/extensions/UsabilityInitiative/NavigableTOC/NavigableTOC.js 2009-07-30 20:11:57 UTC (rev 54041) @@ -1,17 +1,19 @@ /* JavaScript for NavigableTOC extension */ js2AddOnloadHook( function() { - var list = $j( '<div></div>' ) - .attr( 'id', 'edit-toc' ) - .appendTo( $j( 'div#edit-ui-right' ) ); - $j( '#wpTextbox1' ) + var list = $j( '<div></div>' ).attr( 'id', 'edit-ui-toc' ); + $j( 'div#edit-ui-bottom' ).append( list ); + $j( 'div#edit-ui-toc' ).height( $j( 'div#edit-ui-bottom' ).height() ); + $j( 'textarea#wpTextbox1' ) .eachAsync( { bulk: 0, loop: function() { $j(this) + .scrollToCaretPosition( 0 ) .parseOutline() .buildOutline( list ) .updateOutline( list ); + $j( 'div#edit-ui' ).trigger( 'layout' ); } } ) .bind( 'keyup encapsulateSelection', { 'list': list }, Modified: trunk/extensions/UsabilityInitiative/js/jquery.combined.js =================================================================== --- trunk/extensions/UsabilityInitiative/js/jquery.combined.js 2009-07-30 19:29:04 UTC (rev 54040) +++ trunk/extensions/UsabilityInitiative/js/jquery.combined.js 2009-07-30 20:11:57 UTC (rev 54041) @@ -4631,281 +4631,268 @@ } }; -/* +/** + * These plugins provide extra functionality for interaction with textareas. + */ +( function( $ ) { $.fn.extend( { +/** * Ported from skins/common/edit.js by Trevor Parscal * (c) 2009 Wikimedia Foundation (GPLv2) - http://www.wikimedia.org + * + * Inserts text at the begining and end of a text selection, optionally + * inserting text at the caret when selection is empty. + * + * @param pre Text to insert before selection + * @param peri Text to insert at caret if selection is empty + * @param post Text to insert after selection */ -(function($) { - $.fn.extend({ - encapsulateSelection: function( pre, peri, post ) { - /** - * CLEAN THIS UP PLEASE! - */ - var e = this.jquery ? this[0] : this; - var selText; - var isSample = false; - if (document.selection && document.selection.createRange) { // IE/Opera - - //save window scroll position - if (document.documentElement && document.documentElement.scrollTop) - var winScroll = document.documentElement.scrollTop - else if (document.body) - var winScroll = document.body.scrollTop; - //get current selection - e.focus(); - var range = document.selection.createRange(); - selText = range.text; - //insert tags - checkSelectedText(); - range.text = pre + selText + post; - //mark sample text as selected - if (isSample && range.moveStart) { - if (window.opera) - post = post.replace(/\n/g,''); - range.moveStart('character', - post.length - selText.length); - range.moveEnd('character', - post.length); - } - range.select(); - //restore window scroll position - if (document.documentElement && document.documentElement.scrollTop) - document.documentElement.scrollTop = winScroll - else if (document.body) - document.body.scrollTop = winScroll; - - } else if (e.selectionStart || e.selectionStart == '0') { // Mozilla - - //save textarea scroll position - var textScroll = e.scrollTop; - //get current selection - e.focus(); - var startPos = e.selectionStart; - var endPos = e.selectionEnd; - selText = e.value.substring(startPos, endPos); - //insert tags - checkSelectedText(); - e.value = e.value.substring(0, startPos) - + pre + selText + post - + e.value.substring(endPos, e.value.length); - //set new selection - if (isSample) { - e.selectionStart = startPos + pre.length; - e.selectionEnd = startPos + pre.length + selText.length; - } else { - e.selectionStart = startPos + pre.length + selText.length + post.length; - e.selectionEnd = e.selectionStart; - } - //restore textarea scroll position - e.scrollTop = textScroll; +encapsulateSelection: function( pre, peri, post ) { + /** + * Check if the selected text is the same as the insert text + */ + function checkSelectedText() { + if ( !selText ) { + selText = peri; + isSample = true; + } else if ( selText.charAt( selText.length - 1 ) == ' ' ) { + // Exclude ending space char + selText = selText.substring(0, selText.length - 1); + post += ' ' + } + } + var e = this.jquery ? this[0] : this; + var selText; + var isSample = false; + if ( document.selection && document.selection.createRange ) { + // IE/Opera + if ( document.documentElement && document.documentElement.scrollTop ) { + var winScroll = document.documentElement.scrollTop; + } else if ( document.body ) { + var winScroll = document.body.scrollTop; + } + e.focus(); + var range = document.selection.createRange(); + selText = range.text; + checkSelectedText(); + range.text = pre + selText + post; + if ( isSample && range.moveStart ) { + if ( window.opera ) { + post = post.replace( /\n/g, '' ); } - // Checks if the selected text is the same as the insert text - function checkSelectedText(){ - if (!selText) { - selText = peri; - isSample = true; - } else if (selText.charAt(selText.length - 1) == ' ') { //exclude ending space char - selText = selText.substring(0, selText.length - 1); - post += ' ' - } - } - $(this).trigger( 'encapsulateSelection' ); - /** - * /CLEAN THIS UP PLEASE! + range.moveStart( 'character', - post.length - selText.length ); + range.moveEnd( 'character', - post.length ); + } + range.select(); + if ( document.documentElement && document.documentElement.scrollTop ) { + document.documentElement.scrollTop = winScroll + } else if ( document.body ) { + document.body.scrollTop = winScroll; + } + } else if ( e.selectionStart || e.selectionStart == '0' ) { + // Mozilla + var textScroll = e.scrollTop; + e.focus(); + var startPos = e.selectionStart; + var endPos = e.selectionEnd; + selText = e.value.substring( startPos, endPos ); + checkSelectedText(); + e.value = e.value.substring( 0, startPos ) + pre + selText + post + + e.value.substring( endPos, e.value.length ); + if ( isSample ) { + e.selectionStart = startPos + pre.length; + e.selectionEnd = startPos + pre.length + selText.length; + } else { + e.selectionStart = + startPos + pre.length + selText.length + post.length; + e.selectionEnd = e.selectionStart; + } + e.scrollTop = textScroll; + } + $(this).trigger( 'encapsulateSelection' ); +}, +/** + * Ported from Wikia's LinkSuggest extension + * https://svn.wikia-code.com/wikia/trunk/extensions/wikia/LinkSuggest + * Some code copied from + * http://www.dedestruct.com/2008/03/22/howto-cross-browser-cursor-position-in-textareas/ + * + * Get the position (in resolution of bytes not nessecarily characters) + * in a textarea + */ + getCaretPosition: function() { + function getCaret( e ) { + var caretPos = 0; + if($.browser.msie) { + // IE Support + var postFinished = false; + var periFinished = false; + var postFinished = false; + var preText, rawPreText, periText; + var rawPeriText, postText, rawPostText; + // Create range containing text in the selection + var periRange = document.selection.createRange().duplicate(); + // Create range containing text before the selection + var preRange = document.body.createTextRange(); + // Select all the text + preRange.moveToElementText(e); + // Move the end where we need it + preRange.setEndPoint("EndToStart", periRange); + // Create range containing text after the selection + var postRange = document.body.createTextRange(); + // Select all the text + postRange.moveToElementText(e); + // Move the start where we need it + postRange.setEndPoint("StartToEnd", periRange); + // Load the text values we need to compare + preText = rawPreText = preRange.text; + periText = rawPeriText = periRange.text; + postText = rawPostText = postRange.text; + /* + * Check each range for trimmed newlines by shrinking the range by 1 + * character and seeing if the text property has changed. If it has + * not changed then we know that IE has trimmed a \r\n from the end. */ - }, - // The getCaret(), getLineLength() and getCaretPosition() - // functions were copied from Wikia's LinkSuggest extension and - // modified slightly. - // https://svn.wikia-code.com/wikia/trunk/extensions/wikia/LinkSuggest/LinkSuggest.js - - /** - * Get the byte position in a textarea - */ - bytePos: function() { - /** - * CLEAN THIS UP PLEASE! - */ - function getCaret(control) { - var caretPos = 0; - // IE Support - if($.browser.msie) { - // This code was copied from - // http://www.dedestruct.com/2008/03/22/howto-cross-browser-cursor-position-in-textareas/ - var selection_range = document.selection.createRange().duplicate(); - - // Create three ranges, one containing all the text before the selection, - // one containing all the text in the selection (this already exists), and one containing all - // the text after the selection. - var before_range = document.body.createTextRange(); - before_range.moveToElementText(control); // Selects all the text - before_range.setEndPoint("EndToStart", selection_range); // Moves the end where we need it - - var after_range = document.body.createTextRange(); - after_range.moveToElementText(control); // Selects all the text - after_range.setEndPoint("StartToEnd", selection_range); // Moves the start where we need it - - var before_finished = false, selection_finished = false, after_finished = false; - var before_text, untrimmed_before_text, selection_text, untrimmed_selection_text, after_text, untrimmed_after_text; - - // Load the text values we need to compare - before_text = untrimmed_before_text = before_range.text; - selection_text = untrimmed_selection_text = selection_range.text; - after_text = untrimmed_after_text = after_range.text; - - - // Check each range for trimmed newlines by shrinking the range by 1 character and seeing - // if the text property has changed. If it has not changed then we know that IE has trimmed - // a \r\n from the end. - do { - if (!before_finished) { - if (before_range.compareEndPoints("StartToEnd", before_range) == 0) { - before_finished = true; - } else { - before_range.moveEnd("character", -1) - if (before_range.text == before_text) { - untrimmed_before_text += "\r\n"; - } else { - before_finished = true; - } - } + do { + if ( !postFinished ) { + if ( preRange. + compareEndPoints( "StartToEnd", preRange ) == 0 ) { + postFinished = true; + } else { + preRange.moveEnd( "character", -1 ) + if ( preRange.text == preText ) { + rawPreText += "\r\n"; + } else { + postFinished = true; } - if (!selection_finished) { - if (selection_range.compareEndPoints("StartToEnd", selection_range) == 0) { - selection_finished = true; - } else { - selection_range.moveEnd("character", -1) - if (selection_range.text == selection_text) { - untrimmed_selection_text += "\r\n"; - } else { - selection_finished = true; - } - } - } - if (!after_finished) { - if (after_range.compareEndPoints("StartToEnd", after_range) == 0) { - after_finished = true; - } else { - after_range.moveEnd("character", -1) - if (after_range.text == after_text) { - untrimmed_after_text += "\r\n"; - } else { - after_finished = true; - } - } - } - - } while ((!before_finished || !selection_finished || !after_finished)); - - caretPos = untrimmed_before_text.replace(/\r\n/g, "\n").length; - // Firefox support - } else if (control.selectionStart || control.selectionStart == '0') { - caretPos = control.selectionStart; + } } - return caretPos; - } - - return getCaret( this.get( 0 ) ); - /** - * /CLEAN THIS UP PLEASE! - */ - }, - - /** - * Scroll a textarea to a certain offset - * @param pos Byte offset in the contents - */ - scrollToPosition: function( pos ) { - /** - * CLEAN THIS UP PLEASE! - */ - function getLineLength(control) { - var width = control.scrollWidth; - return Math.floor(width/($.os.name == 'linux' ? 7 : 8)); - } - - function getCaretPosition(control) { - var text = control.value.replace(/\r/g, ""); - var caret = $(control).bytePos(); - var lineLength = getLineLength(control); - - var row = 0; - var charInLine = 0; - var lastSpaceInLine = 0; - - for(i = 0; i < caret; i++) { - charInLine++; - if(text.charAt(i) == " ") { - lastSpaceInLine = charInLine; - } else if(text.charAt(i) == "\n") { - lastSpaceInLine = 0; - charInLine = 0; - row++; - } - if(charInLine > lineLength) { - if(lastSpaceInLine > 0) { - charInLine = charInLine - lastSpaceInLine; - - lastSpaceInLine = 0; - row++; + if ( !periFinished ) { + if ( periRange. + compareEndPoints( "StartToEnd", periRange ) == 0 ) { + periFinished = true; + } else { + periRange.moveEnd( "character", -1 ) + if ( periRange.text == periText ) { + rawPeriText += "\r\n"; + } else { + periFinished = true; } } } - var nextSpace = 0; - for(j = caret; j < caret + lineLength; j++) { - if(text.charAt(j) == " " || text.charAt(j) == "\n" || caret == text.length) { - nextSpace = j; - break; + if ( !postFinished ) { + if ( postRange. + compareEndPoints("StartToEnd", postRange) == 0 ) { + postFinished = true; + } else { + postRange.moveEnd( "character", -1 ) + if ( postRange.text == postText ) { + rawPostText += "\r\n"; + } else { + postFinished = true; + } } } - - if(nextSpace > lineLength && caret <= lineLength) { - charInLine = caret - lastSpaceInLine; + } while ( ( !postFinished || !periFinished || !postFinished ) ); + caretPos = rawPreText.replace( /\r\n/g, "\n" ).length; + } else if ( e.selectionStart || e.selectionStart == '0' ) { + // Firefox support + caretPos = e.selectionStart; + } + return caretPos; + } + return getCaret( this.get( 0 ) ); +}, +/** + * Ported from Wikia's LinkSuggest extension + * https://svn.wikia-code.com/wikia/trunk/extensions/wikia/LinkSuggest + * + * Scroll a textarea to a certain offset + * @param pos Byte offset + */ +scrollToCaretPosition: function( pos ) { + function getLineLength( e ) { + return Math.floor( e.scrollWidth / ( $.os.name == 'linux' ? 7 : 8 ) ); + } + function getCaretScrollPosition( e ) { + var text = e.value.replace( /\r/g, "" ); + var caret = $( e ).getCaretPosition(); + var lineLength = getLineLength( e ); + var row = 0; + var charInLine = 0; + var lastSpaceInLine = 0; + for ( i = 0; i < caret; i++ ) { + charInLine++; + if ( text.charAt( i ) == " " ) { + lastSpaceInLine = charInLine; + } else if ( text.charAt( i ) == "\n" ) { + lastSpaceInLine = 0; + charInLine = 0; + row++; + } + if ( charInLine > lineLength ) { + if ( lastSpaceInLine > 0 ) { + charInLine = charInLine - lastSpaceInLine; + lastSpaceInLine = 0; row++; } - - - return ($.os.name == 'mac' ? 13 : ($.os.name == 'linux' ? 15 : 16))*row; } - - return this.each(function() { - $(this).focus(); - if ( this.selectionStart || this.selectionStart == '0' ) { // Mozilla - this.selectionStart = this.selectionEnd = pos; - $(this).scrollTop( getCaretPosition( this ) ); - } else if ( document.selection && document.selection.createRange ) { // IE/Opera - // IE automatically scrolls the section - // to the bottom of the page, except - // if it's already in view and the - // cursor position hasn't changed, in - // which case it does nothing. In that - // case we'll force it to act by moving - // one character back and forth - range = document.selection.createRange(); - oldPos = $(this).bytePos(); - goBack = false; - if ( oldPos == pos ) { - pos++; - goBack = true; - } - range.moveToElementText( this ); - range.collapse(); - range.move( 'character', pos ); - range.select(); - this.scrollTop += range.offsetTop; - if ( goBack ) { - range.move( 'character', -1 ); - range.select(); - } - } - $(this).trigger( 'scrollToPosition' ); - }); - /** - * /CLEAN THIS UP PLEASE! + } + var nextSpace = 0; + for ( j = caret; j < caret + lineLength; j++ ) { + if ( + text.charAt( j ) == " " || + text.charAt( j ) == "\n" || + caret == text.length + ) { + nextSpace = j; + break; + } + } + if( nextSpace > lineLength && caret <= lineLength ) { + charInLine = caret - lastSpaceInLine; + row++; + } + return ( + $.os.name == 'mac' ? 13 : ( $.os.name == 'linux' ? 15 : 16 ) + ) * row; + } + return this.each(function() { + $(this).focus(); + if ( this.selectionStart || this.selectionStart == '0' ) { + // Mozilla + this.selectionStart = pos; + this.selectionEnd = pos; + $(this).scrollTop( getCaretScrollPosition( this ) ); + } else if ( document.selection && document.selection.createRange ) { + // IE / Opera + /* + * IE automatically scrolls the section to the bottom of the page, + * except if it's already in view and the cursor position hasn't + * changed, in which case it does nothing. In that case we'll force + * it to act by moving one character back and forth. */ + range = document.selection.createRange(); + oldPos = $(this).bytePos(); + goBack = false; + if ( oldPos == pos ) { + pos++; + goBack = true; + } + range.moveToElementText( this ); + range.collapse(); + range.move( 'character', pos ); + range.select(); + this.scrollTop += range.offsetTop; + if ( goBack ) { + range.move( 'character', -1 ); + range.select(); + } } - }); -})(jQuery); + $(this).trigger( 'scrollToPosition' ); + }); +} -/** +} ); } )( jQuery );/** * This is the toolbar plugin, which can be used like * $j( 'div#edittoolbar' ).toolbar( '#wpTextbox1', tools ); * Where tools is an array of objects which describe each tool (see below for @@ -5361,16 +5348,15 @@ }); })(jQuery);/** * Plugin for parsing wikitext, building outlines, and keeping them up to date */ -(function($){$.fn.extend({ +( function( $ ){ $.fn.extend( { -/* +/** * This function should be called on the text area to map out the section * character positions by scanning for headings, and the resulting data will * be stored as $(this).data( 'outline', { ... } ) */ parseOutline: function() { return this.each( function() { - //console.time( 'parseOutline' ); // Extract headings from wikitext var wikitext = '\n' + $(this).val() + '\n'; var headings = wikitext.match( /\n={1,5}.*={1,5}(?=\n)/g ); @@ -5414,7 +5400,7 @@ 'text': text, 'position': position, 'level': level, - 'index': h + 'index': h + 1 }; /* console.log( @@ -5428,16 +5414,16 @@ } // Cache outline $(this).data( 'outline', outline ) - //console.timeEnd( 'parseOutline' ); } ); }, -/* +/** * Generate structured UL from outline + * + * @param target jQuery selection of element of containers to place list in */ buildOutline: function( target ) { return this.each( function() { if ( target.size() ) { - //console.time( 'buildOutline' ); var outline = $(this).data( 'outline' ); // Normalize levels, adding an nLevel parameter to each node var level = 1; @@ -5492,42 +5478,59 @@ .data( 'textbox', textarea ) .data( 'position', structure[i].position ) .click( function( event ) { - $(this).data( 'textbox' ).scrollToPosition( - $(this).data( 'position' ) - ); + $(this).data( 'textbox' ) + .scrollToCaretPosition( + $(this).data( 'position' ) + ); event.preventDefault(); } ) .text( structure[i].text ) ); if ( structure[i].sections !== undefined ) { - item.append( buildList( textarea, structure[i].sections ) ); + item.append( + buildList( textarea, structure[i].sections ) + ); } list.append( item ); } return list; } - target.html( buildList( $(this), buildStructure( outline ) ) ); - //console.timeEnd( 'buildOutline' ); + // Adds special level 1 section 0 item + var structure = buildStructure( outline ); + structure.unshift( { + 'text': wgTitle, + 'level': 1, + 'index': 0, + 'position': 0 + } ); + target.html( buildList( $(this), structure ) ); } } ); }, -/* +/** * Highlight the section the cursor is currently within + * + * @param target jQuery selection of element of containers with links to update */ updateOutline: function( target ) { return this.each( function() { - //console.time( 'updateOutline' ); var outline = $(this).data( 'outline' ); - var position = $(this).bytePos(); - var i = 0; - while ( i < outline.length && outline[i].position - 1 < position ) { - i++; + var position = $(this).getCaretPosition(); + var section = 0; + if ( position < outline[section].position - 1 ) { + // Section 0 + } else { + while ( + section < outline.length && + outline[section].position - 1 < position + ) { + section++; + } + section = Math.max( 0, section ); } - i = Math.max( 0, i - 1 ); target.find( 'a' ).removeClass( 'currentSelection' ); - target.find( 'a.section-' + i ).addClass( 'currentSelection' ); - //console.timeEnd( 'updateOutline' ); + target.find( 'a.section-' + section ).addClass( 'currentSelection' ); } ); } -}); })(jQuery); \ No newline at end of file +} ); } )( jQuery ); \ No newline at end of file Modified: trunk/extensions/UsabilityInitiative/js/jquery.combined.min.js =================================================================== --- trunk/extensions/UsabilityInitiative/js/jquery.combined.min.js 2009-07-30 19:29:04 UTC (rev 54040) +++ trunk/extensions/UsabilityInitiative/js/jquery.combined.min.js 2009-07-30 20:11:57 UTC (rev 54041) @@ -448,33 +448,27 @@ var expires='';if(options.expires&&(typeof options.expires=='number'||options.expires.toUTCString)){var date;if(typeof options.expires=='number'){date=new Date();date.setTime(date.getTime()+(options.expires*24*60*60*1000));}else{date=options.expires;} expires='; expires='+date.toUTCString();} var path=options.path?'; path='+(options.path):'';var domain=options.domain?'; domain='+(options.domain):'';var secure=options.secure?'; secure':'';document.cookie=[name,'=',encodeURIComponent(value),expires,path,domain,secure].join('');}else{var cookieValue=null;if(document.cookie&&document.cookie!=''){var cookies=document.cookie.split(';');for(var i=0;i<cookies.length;i++){var cookie=jQuery.trim(cookies[i]);if(cookie.substring(0,name.length+1)==(name+'=')){cookieValue=decodeURIComponent(cookie.substring(name.length+1));break;}}} -return cookieValue;}};(function($){$.fn.extend({encapsulateSelection:function(pre,peri,post){var e=this.jquery?this[0]:this;var selText;var isSample=false;if(document.selection&&document.selection.createRange){if(document.documentElement&&document.documentElement.scrollTop) -var winScroll=document.documentElement.scrollTop -else if(document.body) -var winScroll=document.body.scrollTop;e.focus();var range=document.selection.createRange();selText=range.text;checkSelectedText();range.text=pre+selText+post;if(isSample&&range.moveStart){if(window.opera) -post=post.replace(/\n/g,'');range.moveStart('character',-post.length-selText.length);range.moveEnd('character',-post.length);} -range.select();if(document.documentElement&&document.documentElement.scrollTop) -document.documentElement.scrollTop=winScroll -else if(document.body) -document.body.scrollTop=winScroll;}else if(e.selectionStart||e.selectionStart=='0'){var textScroll=e.scrollTop;e.focus();var startPos=e.selectionStart;var endPos=e.selectionEnd;selText=e.value.substring(startPos,endPos);checkSelectedText();e.value=e.value.substring(0,startPos) -+pre+selText+post -+e.value.substring(endPos,e.value.length);if(isSample){e.selectionStart=startPos+pre.length;e.selectionEnd=startPos+pre.length+selText.length;}else{e.selectionStart=startPos+pre.length+selText.length+post.length;e.selectionEnd=e.selectionStart;} +return cookieValue;}};(function($){$.fn.extend({encapsulateSelection:function(pre,peri,post){function checkSelectedText(){if(!selText){selText=peri;isSample=true;}else if(selText.charAt(selText.length-1)==' '){selText=selText.substring(0,selText.length-1);post+=' '}} +var e=this.jquery?this[0]:this;var selText;var isSample=false;if(document.selection&&document.selection.createRange){if(document.documentElement&&document.documentElement.scrollTop){var winScroll=document.documentElement.scrollTop;}else if(document.body){var winScroll=document.body.scrollTop;} +e.focus();var range=document.selection.createRange();selText=range.text;checkSelectedText();range.text=pre+selText+post;if(isSample&&range.moveStart){if(window.opera){post=post.replace(/\n/g,'');} +range.moveStart('character',-post.length-selText.length);range.moveEnd('character',-post.length);} +range.select();if(document.documentElement&&document.documentElement.scrollTop){document.documentElement.scrollTop=winScroll}else if(document.body){document.body.scrollTop=winScroll;}}else if(e.selectionStart||e.selectionStart=='0'){var textScroll=e.scrollTop;e.focus();var startPos=e.selectionStart;var endPos=e.selectionEnd;selText=e.value.substring(startPos,endPos);checkSelectedText();e.value=e.value.substring(0,startPos)+pre+selText+post+ +e.value.substring(endPos,e.value.length);if(isSample){e.selectionStart=startPos+pre.length;e.selectionEnd=startPos+pre.length+selText.length;}else{e.selectionStart=startPos+pre.length+selText.length+post.length;e.selectionEnd=e.selectionStart;} e.scrollTop=textScroll;} -function checkSelectedText(){if(!selText){selText=peri;isSample=true;}else if(selText.charAt(selText.length-1)==' '){selText=selText.substring(0,selText.length-1);post+=' '}} -$(this).trigger('encapsulateSelection');},bytePos:function(){function getCaret(control){var caretPos=0;if($.browser.msie){var selection_range=document.selection.createRange().duplicate();var before_range=document.body.createTextRange();before_range.moveToElementText(control);before_range.setEndPoint("EndToStart",selection_range);var after_range=document.body.createTextRange();after_range.moveToElementText(control);after_range.setEndPoint("StartToEnd",selection_range);var before_finished=false,selection_finished=false,after_finished=false;var before_text,untrimmed_before_text,selection_text,untrimmed_selection_text,after_text,untrimmed_after_text;before_text=untrimmed_before_text=before_range.text;selection_text=untrimmed_selection_text=selection_range.text;after_text=untrimmed_after_text=after_range.text;do{if(!before_finished){if(before_range.compareEndPoints("StartToEnd",before_range)==0){before_finished=true;}else{before_range.moveEnd("character",-1) -if(before_range.text==before_text){untrimmed_before_text+="\r\n";}else{before_finished=true;}}} -if(!selection_finished){if(selection_range.compareEndPoints("StartToEnd",selection_range)==0){selection_finished=true;}else{selection_range.moveEnd("character",-1) -if(selection_range.text==selection_text){untrimmed_selection_text+="\r\n";}else{selection_finished=true;}}} -if(!after_finished){if(after_range.compareEndPoints("StartToEnd",after_range)==0){after_finished=true;}else{after_range.moveEnd("character",-1) -if(after_range.text==after_text){untrimmed_after_text+="\r\n";}else{after_finished=true;}}}}while((!before_finished||!selection_finished||!after_finished));caretPos=untrimmed_before_text.replace(/\r\n/g,"\n").length;}else if(control.selectionStart||control.selectionStart=='0'){caretPos=control.selectionStart;} +$(this).trigger('encapsulateSelection');},getCaretPosition:function(){function getCaret(e){var caretPos=0;if($.browser.msie){var postFinished=false;var periFinished=false;var postFinished=false;var preText,rawPreText,periText;var rawPeriText,postText,rawPostText;var periRange=document.selection.createRange().duplicate();var preRange=document.body.createTextRange();preRange.moveToElementText(e);preRange.setEndPoint("EndToStart",periRange);var postRange=document.body.createTextRange();postRange.moveToElementText(e);postRange.setEndPoint("StartToEnd",periRange);preText=rawPreText=preRange.text;periText=rawPeriText=periRange.text;postText=rawPostText=postRange.text;do{if(!postFinished){if(preRange.compareEndPoints("StartToEnd",preRange)==0){postFinished=true;}else{preRange.moveEnd("character",-1) +if(preRange.text==preText){rawPreText+="\r\n";}else{postFinished=true;}}} +if(!periFinished){if(periRange.compareEndPoints("StartToEnd",periRange)==0){periFinished=true;}else{periRange.moveEnd("character",-1) +if(periRange.text==periText){rawPeriText+="\r\n";}else{periFinished=true;}}} +if(!postFinished){if(postRange.compareEndPoints("StartToEnd",postRange)==0){postFinished=true;}else{postRange.moveEnd("character",-1) +if(postRange.text==postText){rawPostText+="\r\n";}else{postFinished=true;}}}}while((!postFinished||!periFinished||!postFinished));caretPos=rawPreText.replace(/\r\n/g,"\n").length;}else if(e.selectionStart||e.selectionStart=='0'){caretPos=e.selectionStart;} return caretPos;} -return getCaret(this.get(0));},scrollToPosition:function(pos){function getLineLength(control){var width=control.scrollWidth;return Math.floor(width/($.os.name=='linux'?7:8));} -function getCaretPosition(control){var text=control.value.replace(/\r/g,"");var caret=$(control).bytePos();var lineLength=getLineLength(control);var row=0;var charInLine=0;var lastSpaceInLine=0;for(i=0;i<caret;i++){charInLine++;if(text.charAt(i)==" "){lastSpaceInLine=charInLine;}else if(text.charAt(i)=="\n"){lastSpaceInLine=0;charInLine=0;row++;} +return getCaret(this.get(0));},scrollToCaretPosition:function(pos){function getLineLength(e){return Math.floor(e.scrollWidth/($.os.name=='linux'?7:8));} +function getCaretScrollPosition(e){var text=e.value.replace(/\r/g,"");var caret=$(e).getCaretPosition();var lineLength=getLineLength(e);var row=0;var charInLine=0;var lastSpaceInLine=0;for(i=0;i<caret;i++){charInLine++;if(text.charAt(i)==" "){lastSpaceInLine=charInLine;}else if(text.charAt(i)=="\n"){lastSpaceInLine=0;charInLine=0;row++;} if(charInLine>lineLength){if(lastSpaceInLine>0){charInLine=charInLine-lastSpaceInLine;lastSpaceInLine=0;row++;}}} var nextSpace=0;for(j=caret;j<caret+lineLength;j++){if(text.charAt(j)==" "||text.charAt(j)=="\n"||caret==text.length){nextSpace=j;break;}} if(nextSpace>lineLength&&caret<=lineLength){charInLine=caret-lastSpaceInLine;row++;} return($.os.name=='mac'?13:($.os.name=='linux'?15:16))*row;} -return this.each(function(){$(this).focus();if(this.selectionStart||this.selectionStart=='0'){this.selectionStart=this.selectionEnd=pos;$(this).scrollTop(getCaretPosition(this));}else if(document.selection&&document.selection.createRange){range=document.selection.createRange();oldPos=$(this).bytePos();goBack=false;if(oldPos==pos){pos++;goBack=true;} +return this.each(function(){$(this).focus();if(this.selectionStart||this.selectionStart=='0'){this.selectionStart=pos;this.selectionEnd=pos;$(this).scrollTop(getCaretScrollPosition(this));}else if(document.selection&&document.selection.createRange){range=document.selection.createRange();oldPos=$(this).bytePos();goBack=false;if(oldPos==pos){pos++;goBack=true;} range.moveToElementText(this);range.collapse();range.move('character',pos);range.select();this.scrollTop+=range.offsetTop;if(goBack){range.move('character',-1);range.select();}} $(this).trigger('scrollToPosition');});}});})(jQuery);(function($){$.fn.extend({toolbar:function(textbox,tools){return this.each(function(){if('main'in tools){$(this).addToolbarSection(tools.main,textbox,'main');} var tabDiv=$('<div></div>').attr('class','tabs').appendTo($(this));var sectionsDiv=$('<div></div>').attr('class','sections').appendTo($(this));$(this).append($('<div></div>').addClass('break'));var sectionCookie='edittoolbar-'+$(this).attr('id')+'-section';var sectionQueue=[];for(section in tools){if(section=='main'){continue;} @@ -509,15 +503,16 @@ return retval;}});})(jQuery);(function($){$.fn.extend({parseOutline:function(){return this.each(function(){var wikitext='\n'+$(this).val()+'\n';var headings=wikitext.match(/\n={1,5}.*={1,5}(?=\n)/g);var outline=[];var offset=0;for(var h=0;h<headings.length;h++){text=headings[h];var position=wikitext.indexOf(text,offset);if(position>offset){offset=position;}else if(position==-1){continue;} text=$.trim(text);var startLevel=0;for(var c=0;c<text.length;c++){if(text.charAt(c)=='='){startLevel++;}else{break;}} var endLevel=0;for(var c=text.length-1;c>=0;c--){if(text.charAt(c)=='='){endLevel++;}else{break;}} -var level=Math.min(startLevel,endLevel);text=$.trim(text.substr(level,text.length-(level*2)));outline[h]={'text':text,'position':position,'level':level,'index':h};} +var level=Math.min(startLevel,endLevel);text=$.trim(text.substr(level,text.length-(level*2)));outline[h]={'text':text,'position':position,'level':level,'index':h+1};} $(this).data('outline',outline)});},buildOutline:function(target){return this.each(function(){if(target.size()){var outline=$(this).data('outline');var level=1;var trunc=0;for(var i=0;i<outline.length;i++){if(i>0){if(outline[i].level>outline[i-1].level){level++;}else if(outline[i].level<outline[i-1].level){if(trunc<=1){level-=Math.max(1,outline[i-1].level-outline[i].level);}} trunc=outline[i].level-outline[i-1].level;} outline[i].nLevel=level;} function buildStructure(outline,offset,level){if(offset==undefined)offset=0;if(level==undefined)level=1;var sections=[];for(var i=offset;i<outline.length;i++){if(outline[i].nLevel==level){var sub=buildStructure(outline,i+1,level+1);if(sub.length){outline[i].sections=sub;} sections[sections.length]=outline[i];}else if(outline[i].nLevel<level){break;}} return sections;} -function buildList(textarea,structure){var list=$('<ul></ul>');for(i in structure){var item=$('<li></li>').append($('<a></a>').attr('href','#').addClass('section-'+structure[i].index).data('textbox',textarea).data('position',structure[i].position).click(function(event){$(this).data('textbox').scrollToPosition($(this).data('position'));event.preventDefault();}).text(structure[i].text));if(structure[i].sections!==undefined){item.append(buildList(textarea,structure[i].sections));} +function buildList(textarea,structure){var list=$('<ul></ul>');for(i in structure){var item=$('<li></li>').append($('<a></a>').attr('href','#').addClass('section-'+structure[i].index).data('textbox',textarea).data('position',structure[i].position).click(function(event){$(this).data('textbox').scrollToCaretPosition($(this).data('position'));event.preventDefault();}).text(structure[i].text));if(structure[i].sections!==undefined){item.append(buildList(textarea,structure[i].sections));} list.append(item);} return list;} -target.html(buildList($(this),buildStructure(outline)));}});},updateOutline:function(target){return this.each(function(){var outline=$(this).data('outline');var position=$(this).bytePos();var i=0;while(i<outline.length&&outline[i].position-1<position){i++;} -i=Math.max(0,i-1);target.find('a').removeClass('currentSelection');target.find('a.section-'+i).addClass('currentSelection');});}});})(jQuery); \ No newline at end of file +var structure=buildStructure(outline);structure.unshift({'text':wgTitle,'level':1,'index':0,'position':0});target.html(buildList($(this),structure));}});},updateOutline:function(target){return this.each(function(){var outline=$(this).data('outline');var position=$(this).getCaretPosition();var section=0;if(position<outline[section].position-1){}else{while(section<outline.length&&outline[section].position-1<position){section++;} +section=Math.max(0,section);} +target.find('a').removeClass('currentSelection');target.find('a.section-'+section).addClass('currentSelection');});}});})(jQuery); \ No newline at end of file Modified: trunk/extensions/UsabilityInitiative/js/jquery.textSelection.js =================================================================== --- trunk/extensions/UsabilityInitiative/js/jquery.textSelection.js 2009-07-30 19:29:04 UTC (rev 54040) +++ trunk/extensions/UsabilityInitiative/js/jquery.textSelection.js 2009-07-30 20:11:57 UTC (rev 54041) @@ -1,274 +1,262 @@ -/* +/** + * These plugins provide extra functionality for interaction with textareas. + */ +( function( $ ) { $.fn.extend( { +/** * Ported from skins/common/edit.js by Trevor Parscal * (c) 2009 Wikimedia Foundation (GPLv2) - http://www.wikimedia.org + * + * Inserts text at the begining and end of a text selection, optionally + * inserting text at the caret when selection is empty. + * + * @param pre Text to insert before selection + * @param peri Text to insert at caret if selection is empty + * @param post Text to insert after selection */ -(function($) { - $.fn.extend({ - encapsulateSelection: function( pre, peri, post ) { - /** - * CLEAN THIS UP PLEASE! - */ - var e = this.jquery ? this[0] : this; - var selText; - var isSample = false; - if (document.selection && document.selection.createRange) { // IE/Opera - - //save window scroll position - if (document.documentElement && document.documentElement.scrollTop) - var winScroll = document.documentElement.scrollTop - else if (document.body) - var winScroll = document.body.scrollTop; - //get current selection - e.focus(); - var range = document.selection.createRange(); - selText = range.text; - //insert tags - checkSelectedText(); - range.text = pre + selText + post; - //mark sample text as selected - if (isSample && range.moveStart) { - if (window.opera) - post = post.replace(/\n/g,''); - range.moveStart('character', - post.length - selText.length); - range.moveEnd('character', - post.length); - } - range.select(); - //restore window scroll position - if (document.documentElement && document.documentElement.scrollTop) - document.documentElement.scrollTop = winScroll - else if (document.body) - document.body.scrollTop = winScroll; - - } else if (e.selectionStart || e.selectionStart == '0') { // Mozilla - - //save textarea scroll position - var textScroll = e.scrollTop; - //get current selection - e.focus(); - var startPos = e.selectionStart; - var endPos = e.selectionEnd; - selText = e.value.substring(startPos, endPos); - //insert tags - checkSelectedText(); - e.value = e.value.substring(0, startPos) - + pre + selText + post - + e.value.substring(endPos, e.value.length); - //set new selection - if (isSample) { - e.selectionStart = startPos + pre.length; - e.selectionEnd = startPos + pre.length + selText.length; - } else { - e.selectionStart = startPos + pre.length + selText.length + post.length; - e.selectionEnd = e.selectionStart; - } - //restore textarea scroll position - e.scrollTop = textScroll; +encapsulateSelection: function( pre, peri, post ) { + /** + * Check if the selected text is the same as the insert text + */ + function checkSelectedText() { + if ( !selText ) { + selText = peri; + isSample = true; + } else if ( selText.charAt( selText.length - 1 ) == ' ' ) { + // Exclude ending space char + selText = selText.substring(0, selText.length - 1); + post += ' ' + } + } + var e = this.jquery ? this[0] : this; + var selText; + var isSample = false; + if ( document.selection && document.selection.createRange ) { + // IE/Opera + if ( document.documentElement && document.documentElement.scrollTop ) { + var winScroll = document.documentElement.scrollTop; + } else if ( document.body ) { + var winScroll = document.body.scrollTop; + } + e.focus(); + var range = document.selection.createRange(); + selText = range.text; + checkSelectedText(); + range.text = pre + selText + post; + if ( isSample && range.moveStart ) { + if ( window.opera ) { + post = post.replace( /\n/g, '' ); } - // Checks if the selected text is the same as the insert text - function checkSelectedText(){ - if (!selText) { - selText = peri; - isSample = true; - } else if (selText.charAt(selText.length - 1) == ' ') { //exclude ending space char - selText = selText.substring(0, selText.length - 1); - post += ' ' - } - } - $(this).trigger( 'encapsulateSelection' ); - /** - * /CLEAN THIS UP PLEASE! + range.moveStart( 'character', - post.length - selText.length ); + range.moveEnd( 'character', - post.length ); + } + range.select(); + if ( document.documentElement && document.documentElement.scrollTop ) { + document.documentElement.scrollTop = winScroll + } else if ( document.body ) { + document.body.scrollTop = winScroll; + } + } else if ( e.selectionStart || e.selectionStart == '0' ) { + // Mozilla + var textScroll = e.scrollTop; + e.focus(); + var startPos = e.selectionStart; + var endPos = e.selectionEnd; + selText = e.value.substring( startPos, endPos ); + checkSelectedText(); + e.value = e.value.substring( 0, startPos ) + pre + selText + post + + e.value.substring( endPos, e.value.length ); + if ( isSample ) { + e.selectionStart = startPos + pre.length; + e.selectionEnd = startPos + pre.length + selText.length; + } else { + e.selectionStart = + startPos + pre.length + selText.length + post.length; + e.selectionEnd = e.selectionStart; + } + e.scrollTop = textScroll; + } + $(this).trigger( 'encapsulateSelection' ); +}, +/** + * Ported from Wikia's LinkSuggest extension + * https://svn.wikia-code.com/wikia/trunk/extensions/wikia/LinkSuggest + * Some code copied from + * http://www.dedestruct.com/2008/03/22/howto-cross-browser-cursor-position-in-textareas/ + * + * Get the position (in resolution of bytes not nessecarily characters) + * in a textarea + */ + getCaretPosition: function() { + function getCaret( e ) { + var caretPos = 0; + if($.browser.msie) { + // IE Support + var postFinished = false; + var periFinished = false; + var postFinished = false; + var preText, rawPreText, periText; + var rawPeriText, postText, rawPostText; + // Create range containing text in the selection + var periRange = document.selection.createRange().duplicate(); + // Create range containing text before the selection + var preRange = document.body.createTextRange(); + // Select all the text + preRange.moveToElementText(e); + // Move the end where we need it + preRange.setEndPoint("EndToStart", periRange); + // Create range containing text after the selection + var postRange = document.body.createTextRange(); + // Select all the text + postRange.moveToElementText(e); + // Move the start where we need it + postRange.setEndPoint("StartToEnd", periRange); + // Load the text values we need to compare + preText = rawPreText = preRange.text; + periText = rawPeriText = periRange.text; + postText = rawPostText = postRange.text; + /* + * Check each range for trimmed newlines by shrinking the range by 1 + * character and seeing if the text property has changed. If it has + * not changed then we know that IE has trimmed a \r\n from the end. */ - }, - // The getCaret(), getLineLength() and getCaretPosition() - // functions were copied from Wikia's LinkSuggest extension and - // modified slightly. - // https://svn.wikia-code.com/wikia/trunk/extensions/wikia/LinkSuggest/LinkSuggest.js - - /** - * Get the byte position in a textarea - */ - bytePos: function() { - /** - * CLEAN THIS UP PLEASE! - */ - function getCaret(control) { - var caretPos = 0; - // IE Support - if($.browser.msie) { - // This code was copied from - // http://www.dedestruct.com/2008/03/22/howto-cross-browser-cursor-position-in-textareas/ - var selection_range = document.selection.createRange().duplicate(); - - // Create three ranges, one containing all the text before the selection, - // one containing all the text in the selection (this already exists), and one containing all - // the text after the selection. - var before_range = document.body.createTextRange(); - before_range.moveToElementText(control); // Selects all the text - before_range.setEndPoint("EndToStart", selection_range); // Moves the end where we need it - - var after_range = document.body.createTextRange(); - after_range.moveToElementText(control); // Selects all the text - after_range.setEndPoint("StartToEnd", selection_range); // Moves the start where we need it - - var before_finished = false, selection_finished = false, after_finished = false; - var before_text, untrimmed_before_text, selection_text, untrimmed_selection_text, after_text, untrimmed_after_text; - - // Load the text values we need to compare - before_text = untrimmed_before_text = before_range.text; - selection_text = untrimmed_selection_text = selection_range.text; - after_text = untrimmed_after_text = after_range.text; - - - // Check each range for trimmed newlines by shrinking the range by 1 character and seeing - // if the text property has changed. If it has not changed then we know that IE has trimmed - // a \r\n from the end. - do { - if (!before_finished) { - if (before_range.compareEndPoints("StartToEnd", before_range) == 0) { - before_finished = true; - } else { - before_range.moveEnd("character", -1) - if (before_range.text == before_text) { - untrimmed_before_text += "\r\n"; - } else { - before_finished = true; - } - } + do { + if ( !postFinished ) { + if ( preRange. + compareEndPoints( "StartToEnd", preRange ) == 0 ) { + postFinished = true; + } else { + preRange.moveEnd( "character", -1 ) + if ( preRange.text == preText ) { + rawPreText += "\r\n"; + } else { + postFinished = true; } - if (!selection_finished) { - if (selection_range.compareEndPoints("StartToEnd", selection_range) == 0) { - selection_finished = true; - } else { - selection_range.moveEnd("character", -1) - if (selection_range.text == selection_text) { - untrimmed_selection_text += "\r\n"; - } else { - selection_finished = true; - } - } - } - if (!after_finished) { - if (after_range.compareEndPoints("StartToEnd", after_range) == 0) { - after_finished = true; - } else { - after_range.moveEnd("character", -1) - if (after_range.text == after_text) { - untrimmed_after_text += "\r\n"; - } else { - after_finished = true; - } - } - } - - } while ((!before_finished || !selection_finished || !after_finished)); - - caretPos = untrimmed_before_text.replace(/\r\n/g, "\n").length; - // Firefox support - } else if (control.selectionStart || control.selectionStart == '0') { - caretPos = control.selectionStart; - } - return caretPos; - } - - return getCaret( this.get( 0 ) ); - /** - * /CLEAN THIS UP PLEASE! - */ - }, - - /** - * Scroll a textarea to a certain offset - * @param pos Byte offset in the contents - */ - scrollToPosition: function( pos ) { - /** - * CLEAN THIS UP PLEASE! - */ - function getLineLength(control) { - var width = control.scrollWidth; - return Math.floor(width/($.os.name == 'linux' ? 7 : 8)); - } - - function getCaretPosition(control) { - var text = control.value.replace(/\r/g, ""); - var caret = $(control).bytePos(); - var lineLength = getLineLength(control); - - var row = 0; - var charInLine = 0; - var lastSpaceInLine = 0; - - for(i = 0; i < caret; i++) { - charInLine++; - if(text.charAt(i) == " ") { - lastSpaceInLine = charInLine; - } else if(text.charAt(i) == "\n") { - lastSpaceInLine = 0; - charInLine = 0; - row++; } - if(charInLine > lineLength) { - if(lastSpaceInLine > 0) { - charInLine = charInLine - lastSpaceInLine; - - lastSpaceInLine = 0; - row++; + } + if ( !periFinished ) { + if ( periRange. + compareEndPoints( "StartToEnd", periRange ) == 0 ) { + periFinished = true; + } else { + periRange.moveEnd( "character", -1 ) + if ( periRange.text == periText ) { + rawPeriText += "\r\n"; + } else { + periFinished = true; } } } - var nextSpace = 0; - for(j = caret; j < caret + lineLength; j++) { - if(text.charAt(j) == " " || text.charAt(j) == "\n" || caret == text.length) { - nextSpace = j; - break; + if ( !postFinished ) { + if ( postRange. + compareEndPoints("StartToEnd", postRange) == 0 ) { + postFinished = true; + } else { + postRange.moveEnd( "character", -1 ) + if ( postRange.text == postText ) { + rawPostText += "\r\n"; + } else { + postFinished = true; + } } } - - if(nextSpace > lineLength && caret <= lineLength) { - charInLine = caret - lastSpaceInLine; + } while ( ( !postFinished || !periFinished || !postFinished ) ); + caretPos = rawPreText.replace( /\r\n/g, "\n" ).length; + } else if ( e.selectionStart || e.selectionStart == '0' ) { + // Firefox support + caretPos = e.selectionStart; + } + return caretPos; + } + return getCaret( this.get( 0 ) ); +}, +/** + * Ported from Wikia's LinkSuggest extension + * https://svn.wikia-code.com/wikia/trunk/extensions/wikia/LinkSuggest + * + * Scroll a textarea to a certain offset + * @param pos Byte offset + */ +scrollToCaretPosition: function( pos ) { + function getLineLength( e ) { + return Math.floor( e.scrollWidth / ( $.os.name == 'linux' ? 7 : 8 ) ); + } + function getCaretScrollPosition( e ) { + var text = e.value.replace( /\r/g, "" ); + var caret = $( e ).getCaretPosition(); + var lineLength = getLineLength( e ); + var row = 0; + var charInLine = 0; + var lastSpaceInLine = 0; + for ( i = 0; i < caret; i++ ) { + charInLine++; + if ( text.charAt( i ) == " " ) { + lastSpaceInLine = charInLine; + } else if ( text.charAt( i ) == "\n" ) { + lastSpaceInLine = 0; + charInLine = 0; + row++; + } + if ( charInLine > lineLength ) { + if ( lastSpaceInLine > 0 ) { + charInLine = charInLine - lastSpaceInLine; + lastSpaceInLine = 0; row++; } - - - return ($.os.name == 'mac' ? 13 : ($.os.name == 'linux' ? 15 : 16))*row; } - - return this.each(function() { - $(this).focus(); - if ( this.selectionStart || this.selectionStart == '0' ) { // Mozilla - this.selectionStart = this.selectionEnd = pos; - $(this).scrollTop( getCaretPosition( this ) ); - } else if ( document.selection && document.selection.createRange ) { // IE/Opera - // IE automatically scrolls the section - // to the bottom of the page, except - // if it's already in view and the - // cursor position hasn't changed, in - // which case it does nothing. In that - // case we'll force it to act by moving - // one character back and forth - range = document.selection.createRange(); - oldPos = $(this).bytePos(); - goBack = false; - if ( oldPos == pos ) { - pos++; - goBack = true; - } - range.moveToElementText( this ); - range.collapse(); - range.move( 'character', pos ); - range.select(); - this.scrollTop += range.offsetTop; - if ( goBack ) { - range.move( 'character', -1 ); - range.select(); - } - } - $(this).trigger( 'scrollToPosition' ); - }); - /** - * /CLEAN THIS UP PLEASE! + } + var nextSpace = 0; + for ( j = caret; j < caret + lineLength; j++ ) { + if ( + text.charAt( j ) == " " || + text.charAt( j ) == "\n" || + caret == text.length + ) { + nextSpace = j; + break; + } + } + if( nextSpace > lineLength && caret <= lineLength ) { + charInLine = caret - lastSpaceInLine; + row++; + } + return ( + $.os.name == 'mac' ? 13 : ( $.os.name == 'linux' ? 15 : 16 ) + ) * row; + } + return this.each(function() { + $(this).focus(); + if ( this.selectionStart || this.selectionStart == '0' ) { + // Mozilla + this.selectionStart = pos; + this.selectionEnd = pos; + $(this).scrollTop( getCaretScrollPosition( this ) ); + } else if ( document.selection && document.selection.createRange ) { + // IE / Opera + /* + * IE automatically scrolls the section to the bottom of the page, + * except if it's already in view and the cursor position hasn't + * changed, in which case it does nothing. In that case we'll force + * it to act by moving one character back and forth. */ + range = document.selection.createRange(); + oldPos = $(this).bytePos(); + goBack = false; + if ( oldPos == pos ) { + pos++; + goBack = true; + } + range.moveToElementText( this ); + range.collapse(); + range.move( 'character', pos ); + range.select(); + this.scrollTop += range.offsetTop; + if ( goBack ) { + range.move( 'character', -1 ); + range.select(); + } } - }); -})(jQuery); + $(this).trigger( 'scrollToPosition' ); + }); +} +} ); } )( jQuery ); \ No newline at end of file Modified: trunk/extensions/UsabilityInitiative/js/jquery.wikiOutline.js =================================================================== --- trunk/extensions/UsabilityInitiative/js/jquery.wikiOutline.js 2009-07-30 19:29:04 UTC (rev 54040) +++ trunk/extensions/UsabilityInitiative/js/jquery.wikiOutline.js 2009-07-30 20:11:57 UTC (rev 54041) @@ -1,16 +1,15 @@ /** * Plugin for parsing wikitext, building outlines, and keeping them up to date */ -(function($){$.fn.extend({ +( function( $ ){ $.fn.extend( { -/* +/** * This function should be called on the text area to map out the section * character positions by scanning for headings, and the resulting data will * be stored as $(this).data( 'outline', { ... } ) */ parseOutline: function() { return this.each( function() { - //console.time( 'parseOutline' ); // Extract headings from wikitext var wikitext = '\n' + $(this).val() + '\n'; var headings = wikitext.match( /\n={1,5}.*={1,5}(?=\n)/g ); @@ -54,7 +53,7 @@ 'text': text, 'position': position, 'level': level, - 'index': h + 'index': h + 1 }; /* console.log( @@ -68,16 +67,16 @@ } // Cache outline $(this).data( 'outline', outline ) - //console.timeEnd( 'parseOutline' ); } ); }, -/* +/** * Generate structured UL from outline + * + * @param target jQuery selection of element of containers to place list in */ buildOutline: function( target ) { return this.each( function() { if ( target.size() ) { - //console.time( 'buildOutline' ); var outline = $(this).data( 'outline' ); // Normalize levels, adding an nLevel parameter to each node var level = 1; @@ -132,42 +131,59 @@ .data( 'textbox', textarea ) .data( 'position', structure[i].position ) .click( function( event ) { - $(this).data( 'textbox' ).scrollToPosition( - $(this).data( 'position' ) - ); + $(this).data( 'textbox' ) + .scrollToCaretPosition( + $(this).data( 'position' ) + ); event.preventDefault(); } ) .text( structure[i].text ) ); if ( structure[i].sections !== undefined ) { - item.append( buildList( textarea, structure[i].sections ) ); + item.append( + buildList( textarea, structure[i].sections ) + ); } list.append( item ); } return list; } - target.html( buildList( $(this), buildStructure( outline ) ) ); - //console.timeEnd( 'buildOutline' ); + // Adds special level 1 section 0 item + var structure = buildStructure( outline ); + structure.unshift( { + 'text': wgTitle, + 'level': 1, + 'index': 0, + 'position': 0 + } ); + target.html( buildList( $(this), structure ) ); } } ); }, -/* +/** * Highlight the section the cursor is currently within + * + * @param target jQuery selection of element of containers with links to update */ updateOutline: function( target ) { return this.each( function() { - //console.time( 'updateOutline' ); var outline = $(this).data( 'outline' ); - var position = $(this).bytePos(); - var i = 0; - while ( i < outline.length && outline[i].position - 1 < position ) { - i++; + var position = $(this).getCaretPosition(); + var section = 0; + if ( position < outline[section].position - 1 ) { + // Section 0 + } else { + while ( + section < outline.length && + outline[section].position - 1 < position + ) { + section++; + } + section = Math.max( 0, section ); } - i = Math.max( 0, i - 1 ); target.find( 'a' ).removeClass( 'currentSelection' ); - target.find( 'a.section-' + i ).addClass( 'currentSelection' ); - //console.timeEnd( 'updateOutline' ); + target.find( 'a.section-' + section ).addClass( 'currentSelection' ); } ); } -}); })(jQuery); \ No newline at end of file +} ); } )( jQuery ); \ No newline at end of file _______________________________________________ MediaWiki-CVS mailing list MediaWiki-CVS@xxxxxxxxxxxxxxxxxxx https://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs
|
|
||||||||||||||||||||||||||
|
|
|
| News | Mail Home | sitemap | FAQ | advertise |