r61502 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r61501‎ | r61502 | r61503 >
Date:21:43, 25 January 2010
Author:catrope
Status:deferred
Tags:
Comment:
UsabilityInitiative:
* Fix weird TOC bug in IE where "== Foo\n\n== Bar ==" was considered a valid header
* Refactor most of context.fn.getContents() into context.fn.htmlToText()
* Address IE8 bug where newlines were stripped from range.text by using context.fn.htmlToText( range.htmlText ) instead
* Fix bug in context.fn.beforeSelection() that caused it to return $( [] ) when the selection started at a <br>. This caused beforeSelection to fail in IE when the cursor was at the beginning of a line (Firefox doesn't put the selection in the <br> in that case)
* Refactor Traverser so going to the next node returns a new Traverser rather than modifying the existing one
* Handle <p>s correctly when calculating offsets
* Fix for r61499: bind to the document rather than to the body
* Fix an untested line of code in mark() that was throwing errors
Modified paths:
  • /trunk/extensions/UsabilityInitiative/UsabilityInitiative.hooks.php (modified) (history)
  • /trunk/extensions/UsabilityInitiative/js/plugins.combined.js (modified) (history)
  • /trunk/extensions/UsabilityInitiative/js/plugins.combined.min.js (modified) (history)
  • /trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.highlight.js (modified) (history)
  • /trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.js (modified) (history)
  • /trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.toc.js (modified) (history)

Diff [purge]

Index: trunk/extensions/UsabilityInitiative/UsabilityInitiative.hooks.php
@@ -135,12 +135,12 @@
136136 array(
137137 'src' => 'js/plugins/jquery.wikiEditor.js',
138138 'class' => 'j.wikiEditor',
139 - 'version' => 65
 139+ 'version' => 66
140140 ),
141141 array(
142142 'src' => 'js/plugins/jquery.wikiEditor.highlight.js',
143143 'class' => 'j.wikiEditor.modules.highlight',
144 - 'version' => 18
 144+ 'version' => 19
145145 ),
146146 array(
147147 'src' => 'js/plugins/jquery.wikiEditor.toolbar.js',
@@ -155,7 +155,7 @@
156156 array(
157157 'src' => 'js/plugins/jquery.wikiEditor.toc.js',
158158 'class' => 'j.wikiEditor.modules.toc',
159 - 'version' => 69
 159+ 'version' => 70
160160 ),
161161 array(
162162 'src' => 'js/plugins/jquery.wikiEditor.preview.js',
@@ -173,10 +173,10 @@
174174 'version' => 1 ),
175175 ),
176176 'combined' => array(
177 - array( 'src' => 'js/plugins.combined.js', 'version' => 172 ),
 177+ array( 'src' => 'js/plugins.combined.js', 'version' => 173 ),
178178 ),
179179 'minified' => array(
180 - array( 'src' => 'js/plugins.combined.min.js', 'version' => 172 ),
 180+ array( 'src' => 'js/plugins.combined.min.js', 'version' => 173 ),
181181 ),
182182 ),
183183 );
Index: trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.toc.js
@@ -113,7 +113,7 @@
114114 }
115115 },
116116 exp: [
117 - { 'regex': /^(={1,6})(.+?)\1\s*$/m, 'label': 'TOC_HEADER', 'markAfter': true }
 117+ { 'regex': /^(={1,6})([^\r\n]+?)\1\s*$/m, 'label': 'TOC_HEADER', 'markAfter': true }
118118 ],
119119 /**
120120 * Internally used functions
Index: trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.js
@@ -367,6 +367,22 @@
368368 .hide()
369369 .appendTo( context.$ui );
370370 },
 371+ 'htmlToText': function( html ) {
 372+ // We use .html() instead of .text() so HTML entities are handled right - setting the HTML of the textarea
 373+ // doesn't work on all browsers, use a dummy <div> instead
 374+ // Get rid of the noincludes when getting text
 375+ var $pre = $( '<pre>' +
 376+ html
 377+ .replace( /\r?\n/g, "" )
 378+ .replace( /\<br[^\>]*\>/gi, "\n" )
 379+ .replace( /&nbsp;/g, " " )
 380+ .replace( /\<p[^\>]*\>/gi, "\n" )
 381+ .replace( /\<\/p[^\>]*\>/gi, "" )
 382+ + '</pre>' );
 383+ $pre.find( '.wikiEditor-noinclude' ).each( function() { $( this ).remove(); } );
 384+ $pre.find( '.wikiEditor-tab' ).each( function() { $( this ).text( "\t" ) } );
 385+ return $pre.text();
 386+ },
371387
372388 /*
373389 * FIXME: This section needs attention! It doesn't really make sense given it's supposed to keep compatibility
@@ -379,20 +395,7 @@
380396 * Gets the complete contents of the iframe (in plain text, not HTML)
381397 */
382398 'getContents': function() {
383 - // We use .html() instead of .text() so HTML entities are handled right - setting the HTML of the textarea
384 - // doesn't work on all browsers, use a dummy <div> instead
385 - // Get rid of the noincludes when getting text
386 - var $pre = $( '<pre>' +
387 - context.$content.html()
388 - .replace( /\r?\n/g, "" )
389 - .replace( /\<br[^\>]*\>/gi, "\n" )
390 - .replace( /&nbsp;/g, " " )
391 - .replace( /\<p[^\>]*\>/gi, "\n" )
392 - .replace( /\<\/p[^\>]*\>/gi, "" )
393 - + '</pre>' );
394 - $pre.find( ".wikiEditor-noinclude" ).each( function() { $( this ).remove(); } );
395 - $pre.find( ".wikiEditor-tab" ).each( function() { $( this ).text( "\t" ) } );
396 - return $pre.text();
 399+ return context.fn.htmlToText( context.$content.html() );
397400 },
398401 /**
399402 * Gets the currently selected text in the content
@@ -408,7 +411,10 @@
409412 retval = context.$iframe[0].contentWindow.document.selection.createRange();
410413 }
411414 if ( typeof retval.text != 'undefined' ) {
412 - retval = retval.text;
 415+ // In IE8, retval.text is stripped of newlines, so we need to process retval.htmlText
 416+ // to get a reliable answer. IE7 does get this right though
 417+ // Run this fix for all IE versions anyway, it doesn't hurt
 418+ retval = context.fn.htmlToText( retval.htmlText );
413419 } else if ( retval.toString ) {
414420 retval = retval.toString();
415421 }
@@ -666,7 +672,7 @@
667673 } catch ( e ) {
668674 return $( [] );
669675 }
670 - var seekPos = range2.text.length;
 676+ var seekPos = context.fn.htmlToText( range2.htmlText ).length;
671677 var offsets = context.fn.getOffsets();
672678 e = offsets[seekPos].node;
673679 offset = offsets[seekPos].offset;
@@ -684,7 +690,7 @@
685691 while ( newE && newE.lastChild ) {
686692 newE = newE.lastChild;
687693 }
688 - e = newE;
 694+ e = newE || e;
689695 }
690696 while ( e ) {
691697 if ( $( e ).is( selector ) && !strict )
@@ -710,14 +716,21 @@
711717 * // Trying to advance past the end will set t.node to null
712718 */
713719 'traverser': function( start ) {
714 - function Traverser( start ) {
715 - this.goNext = function() {
 720+ function Traverser( node, depth, inP ) {
 721+ this.node = node;
 722+ this.depth = depth;
 723+ this.inP = inP;
 724+ this.next = function() {
716725 var p = this.node;
717 - nextDepth = this.depth;
 726+ var nextDepth = this.depth;
 727+ var nextInP = this.inP;
718728 while ( p && !p.nextSibling ) {
 729+ if ( p.nodeName == "P" ) {
 730+ nextInP = false;
 731+ }
719732 p = p.parentNode;
720733 nextDepth--;
721 - if ( this.depth == 0 ) {
 734+ if ( nextDepth == 0 ) {
722735 // We're back at the start node
723736 p = null;
724737 }
@@ -731,26 +744,32 @@
732745 if ( p && p.firstChild ) {
733746 p = p.firstChild;
734747 nextDepth++;
 748+ if ( p.nodeName == "P" ) {
 749+ nextInP = true;
 750+ }
735751 }
736752 } while ( p && p.firstChild );
737 - this.node = p;
738 - this.depth = nextDepth;
 753+ return p ? new Traverser( p, nextDepth, nextInP ) : null;
 754+ };
 755+ }
 756+ // Find the leftmost leaf node in the tree
 757+ var node = start.jquery ? start.get( 0 ) : start;
 758+ var depth = 0;
 759+ var inP = node.nodeName == "P";
 760+ do {
 761+ // Filter nodes with the wikiEditor-noinclude class
 762+ while ( node && $( node ).hasClass( 'wikiEditor-noinclude' ) ) {
 763+ node = node.nextSibling;
739764 }
740 - // Find the leftmost leaf node in the tree
741 - this.node = start.jquery ? start.get( 0 ) : start;
742 - this.depth = 0;
743 - do {
744 - // Filter nodes with the wikiEditor-noinclude class
745 - while ( this.node && $( this.node ).hasClass( 'wikiEditor-noinclude' ) ) {
746 - this.node = this.node.nextSibling;
 765+ if ( node && node.firstChild ) {
 766+ node = node.firstChild;
 767+ depth++;
 768+ if ( node.nodeName == "P" ) {
 769+ inP = true;
747770 }
748 - if ( this.node && this.node.firstChild ) {
749 - this.node = this.node.firstChild;
750 - this.depth++;
751 - }
752 - } while ( this.node && this.node.firstChild );
753 - }
754 - return new Traverser( start );
 771+ }
 772+ } while ( node && node.firstChild );
 773+ return new Traverser( node, depth, inP );
755774 },
756775 'getOffsets': function() {
757776 if ( !context.offsets ) {
@@ -765,28 +784,42 @@
766785 context.offsets = [ ];
767786 var t = context.fn.traverser( context.$content );
768787 var pos = 0, lastTextNode = null, lastTextNodeDepth = null;
769 - while ( t.node ) {
 788+ while ( t ) {
770789 if ( t.node.nodeName != '#text' && t.node.nodeName != 'BR' ) {
771 - t.goNext();
 790+ t = t.next();
772791 continue;
773792 }
774793 var nextPos = t.node.nodeName == '#text' ? pos + t.node.nodeValue.length : pos + 1;
 794+ var nextT = t.next();
 795+ var leavingP = t.inP && nextT && !nextT.inP;
775796 for ( var p = pos; p < nextPos; p++ ) {
776797 context.offsets[p] = {
777798 'node': t.node,
778799 'offset': p - pos,
779 - 'length': nextPos - pos,
 800+ 'length': nextPos - pos + ( leavingP ? 1 : 0 ),
780801 'depth': t.depth,
781802 'lastTextNode': lastTextNode,
782803 'lastTextNodeDepth': lastTextNodeDepth
783804 };
784805 }
785 - pos = nextPos;
 806+ if ( leavingP ) {
 807+ // <p>Foo</p> looks like "Foo\n", make it quack like it too
 808+ // Basically we're faking the \n character much like we're treating <br>s
 809+ context.offsets[nextPos] = {
 810+ 'node': t.node,
 811+ 'offset': nextPos - pos,
 812+ 'length': nextPos - pos + 1,
 813+ 'depth': t.depth,
 814+ 'lastTextNode': lastTextNode,
 815+ 'lastTextNodeDepth': lastTextNodeDepth
 816+ };
 817+ }
 818+ pos = nextPos + ( leavingP ? 1 : 0 );
786819 if ( t.node.nodeName == '#text' ) {
787820 lastTextNode = t.node;
788821 lastTextNodeDepth = t.depth;
789822 }
790 - t.goNext();
 823+ t = nextT;
791824 }
792825 }
793826 };
@@ -902,7 +935,7 @@
903936 // Let modules know we're ready to start working with the content
904937 context.fn.trigger( 'ready' );
905938 // Setup event handling on the iframe
906 - context.$content
 939+ $( context.$iframe[0].contentWindow.document )
907940 .bind( 'keyup mouseup paste cut encapsulateSelection', function( event ) {
908941 context.fn.trigger( 'change', event );
909942 } )
Index: trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.highlight.js
@@ -170,7 +170,7 @@
171171 // Split off the prefix
172172 // This leaves the prefix in the current node and puts
173173 // the rest in a new node which is our start node
174 - startNode = startNode.splitText( offset );
 174+ startNode = startNode.splitText( offsets[start].offset );
175175 }
176176 // Don't wrap leading BRs, produces undesirable results
177177 while ( startNode.nodeName == 'BR' && start + 1 in offsets ) {
Index: trunk/extensions/UsabilityInitiative/js/plugins.combined.js
@@ -6729,6 +6729,22 @@
67306730 .hide()
67316731 .appendTo( context.$ui );
67326732 },
 6733+ 'htmlToText': function( html ) {
 6734+ // We use .html() instead of .text() so HTML entities are handled right - setting the HTML of the textarea
 6735+ // doesn't work on all browsers, use a dummy <div> instead
 6736+ // Get rid of the noincludes when getting text
 6737+ var $pre = $( '<pre>' +
 6738+ html
 6739+ .replace( /\r?\n/g, "" )
 6740+ .replace( /\<br[^\>]*\>/gi, "\n" )
 6741+ .replace( /&nbsp;/g, " " )
 6742+ .replace( /\<p[^\>]*\>/gi, "\n" )
 6743+ .replace( /\<\/p[^\>]*\>/gi, "" )
 6744+ + '</pre>' );
 6745+ $pre.find( '.wikiEditor-noinclude' ).each( function() { $( this ).remove(); } );
 6746+ $pre.find( '.wikiEditor-tab' ).each( function() { $( this ).text( "\t" ) } );
 6747+ return $pre.text();
 6748+ },
67336749
67346750 /*
67356751 * FIXME: This section needs attention! It doesn't really make sense given it's supposed to keep compatibility
@@ -6741,20 +6757,7 @@
67426758 * Gets the complete contents of the iframe (in plain text, not HTML)
67436759 */
67446760 'getContents': function() {
6745 - // We use .html() instead of .text() so HTML entities are handled right - setting the HTML of the textarea
6746 - // doesn't work on all browsers, use a dummy <div> instead
6747 - // Get rid of the noincludes when getting text
6748 - var $pre = $( '<pre>' +
6749 - context.$content.html()
6750 - .replace( /\r?\n/g, "" )
6751 - .replace( /\<br[^\>]*\>/gi, "\n" )
6752 - .replace( /&nbsp;/g, " " )
6753 - .replace( /\<p[^\>]*\>/gi, "\n" )
6754 - .replace( /\<\/p[^\>]*\>/gi, "" )
6755 - + '</pre>' );
6756 - $pre.find( ".wikiEditor-noinclude" ).each( function() { $( this ).remove(); } );
6757 - $pre.find( ".wikiEditor-tab" ).each( function() { $( this ).text( "\t" ) } );
6758 - return $pre.text();
 6761+ return context.fn.htmlToText( context.$content.html() );
67596762 },
67606763 /**
67616764 * Gets the currently selected text in the content
@@ -6770,7 +6773,10 @@
67716774 retval = context.$iframe[0].contentWindow.document.selection.createRange();
67726775 }
67736776 if ( typeof retval.text != 'undefined' ) {
6774 - retval = retval.text;
 6777+ // In IE8, retval.text is stripped of newlines, so we need to process retval.htmlText
 6778+ // to get a reliable answer. IE7 does get this right though
 6779+ // Run this fix for all IE versions anyway, it doesn't hurt
 6780+ retval = context.fn.htmlToText( retval.htmlText );
67756781 } else if ( retval.toString ) {
67766782 retval = retval.toString();
67776783 }
@@ -7028,7 +7034,7 @@
70297035 } catch ( e ) {
70307036 return $( [] );
70317037 }
7032 - var seekPos = range2.text.length;
 7038+ var seekPos = context.fn.htmlToText( range2.htmlText ).length;
70337039 var offsets = context.fn.getOffsets();
70347040 e = offsets[seekPos].node;
70357041 offset = offsets[seekPos].offset;
@@ -7046,7 +7052,7 @@
70477053 while ( newE && newE.lastChild ) {
70487054 newE = newE.lastChild;
70497055 }
7050 - e = newE;
 7056+ e = newE || e;
70517057 }
70527058 while ( e ) {
70537059 if ( $( e ).is( selector ) && !strict )
@@ -7072,14 +7078,21 @@
70737079 * // Trying to advance past the end will set t.node to null
70747080 */
70757081 'traverser': function( start ) {
7076 - function Traverser( start ) {
7077 - this.goNext = function() {
 7082+ function Traverser( node, depth, inP ) {
 7083+ this.node = node;
 7084+ this.depth = depth;
 7085+ this.inP = inP;
 7086+ this.next = function() {
70787087 var p = this.node;
7079 - nextDepth = this.depth;
 7088+ var nextDepth = this.depth;
 7089+ var nextInP = this.inP;
70807090 while ( p && !p.nextSibling ) {
 7091+ if ( p.nodeName == "P" ) {
 7092+ nextInP = false;
 7093+ }
70817094 p = p.parentNode;
70827095 nextDepth--;
7083 - if ( this.depth == 0 ) {
 7096+ if ( nextDepth == 0 ) {
70847097 // We're back at the start node
70857098 p = null;
70867099 }
@@ -7093,26 +7106,32 @@
70947107 if ( p && p.firstChild ) {
70957108 p = p.firstChild;
70967109 nextDepth++;
 7110+ if ( p.nodeName == "P" ) {
 7111+ nextInP = true;
 7112+ }
70977113 }
70987114 } while ( p && p.firstChild );
7099 - this.node = p;
7100 - this.depth = nextDepth;
 7115+ return p ? new Traverser( p, nextDepth, nextInP ) : null;
 7116+ };
 7117+ }
 7118+ // Find the leftmost leaf node in the tree
 7119+ var node = start.jquery ? start.get( 0 ) : start;
 7120+ var depth = 0;
 7121+ var inP = node.nodeName == "P";
 7122+ do {
 7123+ // Filter nodes with the wikiEditor-noinclude class
 7124+ while ( node && $( node ).hasClass( 'wikiEditor-noinclude' ) ) {
 7125+ node = node.nextSibling;
71017126 }
7102 - // Find the leftmost leaf node in the tree
7103 - this.node = start.jquery ? start.get( 0 ) : start;
7104 - this.depth = 0;
7105 - do {
7106 - // Filter nodes with the wikiEditor-noinclude class
7107 - while ( this.node && $( this.node ).hasClass( 'wikiEditor-noinclude' ) ) {
7108 - this.node = this.node.nextSibling;
 7127+ if ( node && node.firstChild ) {
 7128+ node = node.firstChild;
 7129+ depth++;
 7130+ if ( node.nodeName == "P" ) {
 7131+ inP = true;
71097132 }
7110 - if ( this.node && this.node.firstChild ) {
7111 - this.node = this.node.firstChild;
7112 - this.depth++;
7113 - }
7114 - } while ( this.node && this.node.firstChild );
7115 - }
7116 - return new Traverser( start );
 7133+ }
 7134+ } while ( node && node.firstChild );
 7135+ return new Traverser( node, depth, inP );
71177136 },
71187137 'getOffsets': function() {
71197138 if ( !context.offsets ) {
@@ -7127,28 +7146,42 @@
71287147 context.offsets = [ ];
71297148 var t = context.fn.traverser( context.$content );
71307149 var pos = 0, lastTextNode = null, lastTextNodeDepth = null;
7131 - while ( t.node ) {
 7150+ while ( t ) {
71327151 if ( t.node.nodeName != '#text' && t.node.nodeName != 'BR' ) {
7133 - t.goNext();
 7152+ t = t.next();
71347153 continue;
71357154 }
71367155 var nextPos = t.node.nodeName == '#text' ? pos + t.node.nodeValue.length : pos + 1;
 7156+ var nextT = t.next();
 7157+ var leavingP = t.inP && nextT && !nextT.inP;
71377158 for ( var p = pos; p < nextPos; p++ ) {
71387159 context.offsets[p] = {
71397160 'node': t.node,
71407161 'offset': p - pos,
7141 - 'length': nextPos - pos,
 7162+ 'length': nextPos - pos + ( leavingP ? 1 : 0 ),
71427163 'depth': t.depth,
71437164 'lastTextNode': lastTextNode,
71447165 'lastTextNodeDepth': lastTextNodeDepth
71457166 };
71467167 }
7147 - pos = nextPos;
 7168+ if ( leavingP ) {
 7169+ // <p>Foo</p> looks like "Foo\n", make it quack like it too
 7170+ // Basically we're faking the \n character much like we're treating <br>s
 7171+ context.offsets[nextPos] = {
 7172+ 'node': t.node,
 7173+ 'offset': nextPos - pos,
 7174+ 'length': nextPos - pos + 1,
 7175+ 'depth': t.depth,
 7176+ 'lastTextNode': lastTextNode,
 7177+ 'lastTextNodeDepth': lastTextNodeDepth
 7178+ };
 7179+ }
 7180+ pos = nextPos + ( leavingP ? 1 : 0 );
71487181 if ( t.node.nodeName == '#text' ) {
71497182 lastTextNode = t.node;
71507183 lastTextNodeDepth = t.depth;
71517184 }
7152 - t.goNext();
 7185+ t = nextT;
71537186 }
71547187 }
71557188 };
@@ -7264,7 +7297,7 @@
72657298 // Let modules know we're ready to start working with the content
72667299 context.fn.trigger( 'ready' );
72677300 // Setup event handling on the iframe
7268 - context.$content
 7301+ $( context.$iframe[0].contentWindow.document )
72697302 .bind( 'keyup mouseup paste cut encapsulateSelection', function( event ) {
72707303 context.fn.trigger( 'change', event );
72717304 } )
@@ -7619,7 +7652,7 @@
76207653 // Split off the prefix
76217654 // This leaves the prefix in the current node and puts
76227655 // the rest in a new node which is our start node
7623 - startNode = startNode.splitText( offset );
 7656+ startNode = startNode.splitText( offsets[start].offset );
76247657 }
76257658 // Don't wrap leading BRs, produces undesirable results
76267659 while ( startNode.nodeName == 'BR' && start + 1 in offsets ) {
@@ -8709,7 +8742,7 @@
87108743 }
87118744 },
87128745 exp: [
8713 - { 'regex': /^(={1,6})(.+?)\1\s*$/m, 'label': 'TOC_HEADER', 'markAfter': true }
 8746+ { 'regex': /^(={1,6})([^\r\n]+?)\1\s*$/m, 'label': 'TOC_HEADER', 'markAfter': true }
87148747 ],
87158748 /**
87168749 * Internally used functions
Index: trunk/extensions/UsabilityInitiative/js/plugins.combined.min.js
@@ -440,10 +440,10 @@
441441 for(module in context.modules){if(module in $.wikiEditor.modules&&'evt'in $.wikiEditor.modules[module]&&name in $.wikiEditor.modules[module].evt){$.wikiEditor.modules[module].evt[name](context,event);}}},'addButton':function(options){context.$controls.show();context.$buttons.show();return $('<button />').text($.wikiEditor.autoMsg(options,'caption')).click(options.action).appendTo(context.$buttons);},'addView':function(options){function addTab(options){context.$controls.show();context.$tabs.show();return $('<div></div>').attr('rel','wikiEditor-ui-view-'+options.name).addClass(context.view==options.name?'current':null).append($('<a></a>').attr('href','#').click(function(event){context.$ui.find('.wikiEditor-ui-view').hide();context.$ui.find('.'+$(this).parent().attr('rel')).show();context.$tabs.find('div').removeClass('current');$(this).parent().addClass('current');$(this).blur();if('init'in options&&typeof options.init=='function'){options.init(context);}
442442 event.preventDefault();return false;}).text($.wikiEditor.autoMsg(options,'title'))).appendTo(context.$tabs);}
443443 if(!context.$tabs.children().size()){addTab({'name':'wikitext','titleMsg':'wikieditor-wikitext-tab'});}
444 -addTab(options);return $('<div></div>').addClass('wikiEditor-ui-view wikiEditor-ui-view-'+options.name).hide().appendTo(context.$ui);},'getContents':function(){var $pre=$('<pre>'+
445 -context.$content.html().replace(/\r?\n/g,"").replace(/\<br[^\>]*\>/gi,"\n").replace(/&nbsp;/g," ").replace(/\<p[^\>]*\>/gi,"\n").replace(/\<\/p[^\>]*\>/gi,"")
446 -+'</pre>');$pre.find(".wikiEditor-noinclude").each(function(){$(this).remove();});$pre.find(".wikiEditor-tab").each(function(){$(this).text("\t")});return $pre.text();},'getSelection':function(){var retval;if(context.$iframe[0].contentWindow.getSelection){retval=context.$iframe[0].contentWindow.getSelection();}else if(context.$iframe[0].contentWindow.document.selection){retval=context.$iframe[0].contentWindow.document.selection.createRange();}
447 -if(typeof retval.text!='undefined'){retval=retval.text;}else if(retval.toString){retval=retval.toString();}
 444+addTab(options);return $('<div></div>').addClass('wikiEditor-ui-view wikiEditor-ui-view-'+options.name).hide().appendTo(context.$ui);},'htmlToText':function(html){var $pre=$('<pre>'+
 445+html.replace(/\r?\n/g,"").replace(/\<br[^\>]*\>/gi,"\n").replace(/&nbsp;/g," ").replace(/\<p[^\>]*\>/gi,"\n").replace(/\<\/p[^\>]*\>/gi,"")
 446++'</pre>');$pre.find('.wikiEditor-noinclude').each(function(){$(this).remove();});$pre.find('.wikiEditor-tab').each(function(){$(this).text("\t")});return $pre.text();},'getContents':function(){return context.fn.htmlToText(context.$content.html());},'getSelection':function(){var retval;if(context.$iframe[0].contentWindow.getSelection){retval=context.$iframe[0].contentWindow.getSelection();}else if(context.$iframe[0].contentWindow.document.selection){retval=context.$iframe[0].contentWindow.document.selection.createRange();}
 447+if(typeof retval.text!='undefined'){retval=context.fn.htmlToText(retval.htmlText);}else if(retval.toString){retval=retval.toString();}
448448 return retval;},'encapsulateSelection':function(options){var selText=$(this).textSelection('getSelection');var selTextArr;var selectAfter=false;var pre=options.pre,post=options.post;if(!selText){selText=options.peri;selectAfter=true;}else if(options.splitlines){selTextArr=selText.split(/\n/);}else if(options.replace){selText=options.peri;}else if(selText.charAt(selText.length-1)==' '){selText=selText.substring(0,selText.length-1);post+=' ';}
449449 if(context.$iframe[0].contentWindow.getSelection){var range=context.$iframe[0].contentWindow.getSelection().getRangeAt(0);if(options.ownline){var body=context.$content.get(0);if(range.startOffset!=0&&range.startContainer!=body){pre="\n"+options.pre;}
450450 if(range.endContainer!=body){post+="\n";}}
@@ -464,29 +464,30 @@
465465 var topBound=html.scrollTop()>body.scrollTop()?html.scrollTop():body.scrollTop(),bottomBound=topBound+context.$iframe.height();if(force||y<topBound||y>bottomBound){html.scrollTop(y);body.scrollTop(y);}
466466 $element.trigger('scrollToTop');},'beforeSelection':function(selector,strict){if(typeof selector=='undefined'){selector='*';}
467467 var e,offset;if(context.$iframe[0].contentWindow.getSelection){var selection=context.$iframe[0].contentWindow.getSelection();if(selection.baseNode!==null){e=selection.getRangeAt(0).startContainer;offset=selection.startOffset;}else{return $([]);}}else if(context.$iframe[0].contentWindow.document.selection){var range=context.$iframe[0].contentWindow.document.selection.createRange();var range2=context.$iframe[0].contentWindow.document.body.createTextRange();try{range2.setEndPoint('EndToStart',range);}catch(e){return $([]);}
468 -var seekPos=range2.text.length;var offsets=context.fn.getOffsets();e=offsets[seekPos].node;offset=offsets[seekPos].offset;if(!e)
 468+var seekPos=context.fn.htmlToText(range2.htmlText).length;var offsets=context.fn.getOffsets();e=offsets[seekPos].node;offset=offsets[seekPos].offset;if(!e)
469469 return $([]);}
470470 if(e.nodeName!='#text'){var newE=e.firstChild;for(var i=0;i<offset-1&&newE;i++){newE=newE.nextSibling;}
471471 while(newE&&newE.lastChild){newE=newE.lastChild;}
472 -e=newE;}
 472+e=newE||e;}
473473 while(e){if($(e).is(selector)&&!strict)
474474 return $(e);var next=e.previousSibling;while(next&&next.lastChild){next=next.lastChild;}
475475 e=next||e.parentNode;strict=false;}
476 -return $([]);},'traverser':function(start){function Traverser(start){this.goNext=function(){var p=this.node;nextDepth=this.depth;while(p&&!p.nextSibling){p=p.parentNode;nextDepth--;if(this.depth==0){p=null;}}
 476+return $([]);},'traverser':function(start){function Traverser(node,depth,inP){this.node=node;this.depth=depth;this.inP=inP;this.next=function(){var p=this.node;var nextDepth=this.depth;var nextInP=this.inP;while(p&&!p.nextSibling){if(p.nodeName=="P"){nextInP=false;}
 477+p=p.parentNode;nextDepth--;if(nextDepth==0){p=null;}}
477478 p=p?p.nextSibling:null;do{while(p&&$(p).hasClass('wikiEditor-noinclude')){p=p.nextSibling;}
478 -if(p&&p.firstChild){p=p.firstChild;nextDepth++;}}while(p&&p.firstChild);this.node=p;this.depth=nextDepth;}
479 -this.node=start.jquery?start.get(0):start;this.depth=0;do{while(this.node&&$(this.node).hasClass('wikiEditor-noinclude')){this.node=this.node.nextSibling;}
480 -if(this.node&&this.node.firstChild){this.node=this.node.firstChild;this.depth++;}}while(this.node&&this.node.firstChild);}
481 -return new Traverser(start);},'getOffsets':function(){if(!context.offsets){context.fn.refreshOffsets();}
482 -return context.offsets;},'purgeOffsets':function(){context.offsets=null;},'refreshOffsets':function(){context.offsets=[];var t=context.fn.traverser(context.$content);var pos=0,lastTextNode=null,lastTextNodeDepth=null;while(t.node){if(t.node.nodeName!='#text'&&t.node.nodeName!='BR'){t.goNext();continue;}
483 -var nextPos=t.node.nodeName=='#text'?pos+t.node.nodeValue.length:pos+1;for(var p=pos;p<nextPos;p++){context.offsets[p]={'node':t.node,'offset':p-pos,'length':nextPos-pos,'depth':t.depth,'lastTextNode':lastTextNode,'lastTextNodeDepth':lastTextNodeDepth};}
484 -pos=nextPos;if(t.node.nodeName=='#text'){lastTextNode=t.node;lastTextNodeDepth=t.depth;}
485 -t.goNext();}}};context.$textarea.wrap($('<div></div>').addClass('wikiEditor-ui')).wrap($('<div></div>').addClass('wikiEditor-ui-view wikiEditor-ui-view-wikitext')).wrap($('<div></div>').addClass('wikiEditor-ui-left')).wrap($('<div></div>').addClass('wikiEditor-ui-bottom')).wrap($('<div></div>').addClass('wikiEditor-ui-text'));context.$ui=context.$textarea.parent().parent().parent().parent().parent();context.$wikitext=context.$textarea.parent().parent().parent().parent();context.$wikitext.before($('<div></div>').addClass('wikiEditor-ui-controls').append($('<div></div>').addClass('wikiEditor-ui-tabs').hide()).append($('<div></div>').addClass('wikiEditor-ui-buttons'))).before($('<div style="clear:both;"></div>'));context.$controls=context.$ui.find('.wikiEditor-ui-buttons').hide();context.$buttons=context.$ui.find('.wikiEditor-ui-buttons');context.$tabs=context.$ui.find('.wikiEditor-ui-tabs');context.$ui.after($('<div style="clear:both;"></div>'));context.$wikitext.append($('<div></div>').addClass('wikiEditor-ui-right'));context.$wikitext.find('.wikiEditor-ui-left').prepend($('<div></div>').addClass('wikiEditor-ui-top'));context.view='wikitext';$(window).resize(function(event){context.fn.trigger('resize',event)});context.$iframe=$('<iframe></iframe>').attr({'frameBorder':0,'border':0,'src':wgScriptPath+'/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.html?'+'instance='+context.instance+'&ts='+(new Date()).getTime(),'id':'wikiEditor-iframe-'+context.instance}).css({'backgroundColor':'white','width':'100%','height':context.$textarea.height(),'display':'none','overflow-y':'scroll','overflow-x':'hidden'}).insertAfter(context.$textarea).load(function(){if(!this.isSecondRun){context.$iframe[0].contentWindow.document.designMode='on';if($.browser.msie){this.isSecondRun=true;return;}}
 479+if(p&&p.firstChild){p=p.firstChild;nextDepth++;if(p.nodeName=="P"){nextInP=true;}}}while(p&&p.firstChild);return p?new Traverser(p,nextDepth,nextInP):null;};}
 480+var node=start.jquery?start.get(0):start;var depth=0;var inP=node.nodeName=="P";do{while(node&&$(node).hasClass('wikiEditor-noinclude')){node=node.nextSibling;}
 481+if(node&&node.firstChild){node=node.firstChild;depth++;if(node.nodeName=="P"){inP=true;}}}while(node&&node.firstChild);return new Traverser(node,depth,inP);},'getOffsets':function(){if(!context.offsets){context.fn.refreshOffsets();}
 482+return context.offsets;},'purgeOffsets':function(){context.offsets=null;},'refreshOffsets':function(){context.offsets=[];var t=context.fn.traverser(context.$content);var pos=0,lastTextNode=null,lastTextNodeDepth=null;while(t){if(t.node.nodeName!='#text'&&t.node.nodeName!='BR'){t=t.next();continue;}
 483+var nextPos=t.node.nodeName=='#text'?pos+t.node.nodeValue.length:pos+1;var nextT=t.next();var leavingP=t.inP&&nextT&&!nextT.inP;for(var p=pos;p<nextPos;p++){context.offsets[p]={'node':t.node,'offset':p-pos,'length':nextPos-pos+(leavingP?1:0),'depth':t.depth,'lastTextNode':lastTextNode,'lastTextNodeDepth':lastTextNodeDepth};}
 484+if(leavingP){context.offsets[nextPos]={'node':t.node,'offset':nextPos-pos,'length':nextPos-pos+1,'depth':t.depth,'lastTextNode':lastTextNode,'lastTextNodeDepth':lastTextNodeDepth};}
 485+pos=nextPos+(leavingP?1:0);if(t.node.nodeName=='#text'){lastTextNode=t.node;lastTextNodeDepth=t.depth;}
 486+t=nextT;}}};context.$textarea.wrap($('<div></div>').addClass('wikiEditor-ui')).wrap($('<div></div>').addClass('wikiEditor-ui-view wikiEditor-ui-view-wikitext')).wrap($('<div></div>').addClass('wikiEditor-ui-left')).wrap($('<div></div>').addClass('wikiEditor-ui-bottom')).wrap($('<div></div>').addClass('wikiEditor-ui-text'));context.$ui=context.$textarea.parent().parent().parent().parent().parent();context.$wikitext=context.$textarea.parent().parent().parent().parent();context.$wikitext.before($('<div></div>').addClass('wikiEditor-ui-controls').append($('<div></div>').addClass('wikiEditor-ui-tabs').hide()).append($('<div></div>').addClass('wikiEditor-ui-buttons'))).before($('<div style="clear:both;"></div>'));context.$controls=context.$ui.find('.wikiEditor-ui-buttons').hide();context.$buttons=context.$ui.find('.wikiEditor-ui-buttons');context.$tabs=context.$ui.find('.wikiEditor-ui-tabs');context.$ui.after($('<div style="clear:both;"></div>'));context.$wikitext.append($('<div></div>').addClass('wikiEditor-ui-right'));context.$wikitext.find('.wikiEditor-ui-left').prepend($('<div></div>').addClass('wikiEditor-ui-top'));context.view='wikitext';$(window).resize(function(event){context.fn.trigger('resize',event)});context.$iframe=$('<iframe></iframe>').attr({'frameBorder':0,'border':0,'src':wgScriptPath+'/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.html?'+'instance='+context.instance+'&ts='+(new Date()).getTime(),'id':'wikiEditor-iframe-'+context.instance}).css({'backgroundColor':'white','width':'100%','height':context.$textarea.height(),'display':'none','overflow-y':'scroll','overflow-x':'hidden'}).insertAfter(context.$textarea).load(function(){if(!this.isSecondRun){context.$iframe[0].contentWindow.document.designMode='on';if($.browser.msie){this.isSecondRun=true;return;}}
486487 context.$content=$(context.$iframe[0].contentWindow.document.body);var html=context.$textarea.val().replace(/\</g,'&lt;').replace(/\>/g,'&gt;');if($.browser.msie){if($.browser.versionNumber<=7){var prefix='',suffix=html;while(suffix){var match=suffix.match(/(^|\n) /);if(match){prefix+=suffix.substr(0,match.index+match[0].length-1)+'&nbsp;';suffix=suffix.substr(match.index+match[0].length);}else{break;}}
487488 html=prefix+suffix;}else{html=html.replace(/(^|\n) /g,"$1&nbsp;");}
488489 html=html.replace(/\t/g,'<span class="wikiEditor-tab"></span>');}
489490 context.$content.html(html.replace(/\r?\n/g,'<br />'));if($('body').is('.rtl')){context.$content.addClass('rtl').attr('dir','rtl');}
490 -context.$textarea.attr('disabled',true);context.$textarea.hide();context.$iframe.show();context.fn.trigger('ready');context.$content.bind('keyup mouseup paste cut encapsulateSelection',function(event){context.fn.trigger('change',event);}).delayedBind(250,'keyup mouseup paste cut encapsulateSelection',function(event){context.fn.trigger('delayedChange',event);});});context.$textarea.closest('form').submit(function(){context.$textarea.attr('disabled',false);context.$textarea.val(context.$textarea.textSelection('getContents'));});}
 491+context.$textarea.attr('disabled',true);context.$textarea.hide();context.$iframe.show();context.fn.trigger('ready');$(context.$iframe[0].contentWindow.document).bind('keyup mouseup paste cut encapsulateSelection',function(event){context.fn.trigger('change',event);}).delayedBind(250,'keyup mouseup paste cut encapsulateSelection',function(event){context.fn.trigger('delayedChange',event);});});context.$textarea.closest('form').submit(function(){context.$textarea.attr('disabled',false);context.$textarea.val(context.$textarea.textSelection('getContents'));});}
491492 arguments=$.makeArray(arguments);if(arguments.length>0){var call=arguments.shift();if(call in context.api){context.api[call](context,typeof arguments[0]=='undefined'?{}:arguments[0]);}}
492493 return $(this).data('wikiEditor-context',context);};})(jQuery);RegExp.escape=function(s){return s.replace(/([.*+?^${}()|\/\\[\]])/g,'\\$1');};(function($){$.wikiEditor.modules.dialogs={api:{addDialog:function(context,data){$.wikiEditor.modules.dialogs.fn.create(context,data)},openDialog:function(context,module){if(module in $.wikiEditor.modules.dialogs.modules){$('#'+$.wikiEditor.modules.dialogs.modules[module].id).dialog('open');}},closeDialog:function(context,data){if(module in $.wikiEditor.modules.dialogs.modules){$('#'+$.wikiEditor.modules.dialogs.modules[module].id).dialog('close');}}},fn:{create:function(context,config){for(module in config){$.wikiEditor.modules.dialogs.modules[module]=config[module];}
493494 mw.load(['$j.ui','$j.ui.dialog','$j.ui.draggable','$j.ui.resizable'],function(){for(module in $.wikiEditor.modules.dialogs.modules){var module=$.wikiEditor.modules.dialogs.modules[module];if($('#'+module.id).size()==0){var configuration=module.dialog;configuration.bgiframe=true;configuration.autoOpen=false;configuration.modal=true;configuration.title=$.wikiEditor.autoMsg(module,'title');configuration.newButtons={};for(msg in configuration.buttons)
@@ -498,7 +499,7 @@
499500 match=text.match(regex);var oldOffset=0;while(match!=null){var markOffset=0;var tokenStart=match.index+oldOffset+markOffset;if(markAfter){markOffset+=match[0].length;}
500501 tokenArray.push(new Token(match.index+oldOffset+markOffset,label,tokenStart,match));oldOffset+=match.index+match[0].length;newSubstring=text.substring(oldOffset);match=newSubstring.match(regex);}}}}
501502 tokenArray.sort(function(a,b){return a.offset-b.offset||a.tokenStart-b.tokenStart;});context.fn.trigger('scan');},mark:function(context,division,tokens){var markers=context.modules.highlight.markers=[];context.fn.trigger('mark');markers.sort(function(a,b){return a.start-b.start||a.end-b.end;});var offsets=context.fn.getOffsets();for(var i=0;i<markers.length;i++){var start=markers[i].start;if(!(start in offsets)){continue;}
502 -var startNode=offsets[start].node;var startDepth=offsets[start].depth;if(offsets[start].offset>0){startNode=startNode.splitText(offset);}
 503+var startNode=offsets[start].node;var startDepth=offsets[start].depth;if(offsets[start].offset>0){startNode=startNode.splitText(offsets[start].offset);}
503504 while(startNode.nodeName=='BR'&&start+1 in offsets){start++;startNode=offsets[start].node;startDepth=offsets[start].depth;}
504505 var end=markers[i].end;if(!(end in offsets)){continue;}
505506 var endNode=offsets[end].node;var endDepth=offsets[end].depth;if(offsets[end].offset<offsets[end].length-1){endNode.splitText(offsets[end].offset+1);}
@@ -582,7 +583,7 @@
583584 context.modules.toc.$toc.height(context.$ui.find('.wikiEditor-ui-left').height()-
584585 context.$ui.find('.tab-toc').outerHeight());context.modules.toc.$toc.data('previousWidth',context.$wikitext.width());},mark:function(context,event){var markers=context.modules.highlight.markers;var tokenArray=context.modules.highlight.tokenArray;var outline=context.data.outline=[];var h=0;for(var i=0;i<tokenArray.length;i++){if(tokenArray[i].label!='TOC_HEADER'){continue;}
585586 h++;markers.push({index:h,start:tokenArray[i].tokenStart,end:tokenArray[i].offset,anchor:'before',afterWrap:function(node){var marker=$(node).data('marker');$(node).addClass('wikiEditor-toc-header').addClass('wikiEditor-toc-section-'+marker.index).data('section',marker.index);},onSkip:function(node){var marker=$(node).data('marker');$(node).removeClass('wikiEditor-toc-section-'+$(node).data('section')).addClass('wikiEditor-toc-section-'+marker.index).data('section',marker.index);},getAnchor:function(ca1,ca2){return $(ca1.previousSibling).is('div.wikiEditor-toc-header')?ca1.previousSibling:null;}});outline.push({'text':tokenArray[i].match[2],'level':tokenArray[i].match[1].length,'index':h});}
586 -$.wikiEditor.modules.toc.fn.build(context);$.wikiEditor.modules.toc.fn.update(context);}},exp:[{'regex':/^(={1,6})(.+?)\1\s*$/m,'label':'TOC_HEADER','markAfter':true}],fn:{create:function(context,config){if('$toc'in context.modules.toc){return;}
 587+$.wikiEditor.modules.toc.fn.build(context);$.wikiEditor.modules.toc.fn.update(context);}},exp:[{'regex':/^(={1,6})([^\r\n]+?)\1\s*$/m,'label':'TOC_HEADER','markAfter':true}],fn:{create:function(context,config){if('$toc'in context.modules.toc){return;}
587588 $.wikiEditor.modules.toc.cfg.rtl=config.rtl;var height=context.$ui.find('.wikiEditor-ui-left').height();context.modules.toc.$toc=$('<div />').addClass('wikiEditor-ui-toc').data('context',context).data('positionMode','regular').data('collapsed',false);context.$ui.find('.wikiEditor-ui-right').append(context.modules.toc.$toc);context.modules.toc.$toc.height(context.$ui.find('.wikiEditor-ui-left').height());$.wikiEditor.modules.toc.fn.redraw(context,$.wikiEditor.modules.toc.cfg.defaultWidth);},redraw:function(context,fixedWidth){var fixedWidth=parseFloat(fixedWidth);if(context.modules.toc.$toc.data('positionMode')=='regular'){context.$ui.find('.wikiEditor-ui-right').css('width',fixedWidth+'px');context.$ui.find('.wikiEditor-ui-left').css('marginRight',(-1*fixedWidth)+'px').children().css('marginRight',fixedWidth+'px');}else if(context.modules.toc.$toc.data('positionMode')=='goofy'){context.$ui.find('.wikiEditor-ui-left').css('width',fixedWidth);context.$ui.find('.wikiEditor-ui-right').css($.wikiEditor.modules.toc.cfg.rtl?'right':'left',fixedWidth);context.$wikitext.css('height',context.$ui.find('.wikiEditor-ui-right').height());}},switchLayout:function(context){var width,height=context.$ui.find('.wikiEditor-ui-right').height();if(context.modules.toc.$toc.data('positionMode')=='regular'&&!context.modules.toc.$toc.data('collapsed')){context.modules.toc.$toc.data('positionMode','goofy');context.modules.toc.$toc.data('positionModeChangeAt',context.$ui.find('.wikiEditor-ui-right').width());width=$.wikiEditor.modules.toc.cfg.textMinimumWidth;context.$ui.find('.wikiEditor-ui-left').css({'marginRight':'','position':'absolute','float':'none','left':$.wikiEditor.modules.toc.cfg.rtl?'auto':0,'right':$.wikiEditor.modules.toc.cfg.rtl?0:'auto'}).children().css('marginRight','');context.$ui.find('.wikiEditor-ui-right').css({'width':'auto','position':'absolute','float':'none','right':$.wikiEditor.modules.toc.cfg.rtl?'auto':0,'left':$.wikiEditor.modules.toc.cfg.rtl?0:'auto'});context.$wikitext.css('position','relative');}else if(context.modules.toc.$toc.data('positionMode')=='goofy'){context.modules.toc.$toc.data('positionMode','regular');width=context.$wikitext.width()-context.$ui.find('.wikiEditor-ui-left').width();if(width>context.modules.toc.$toc.data('positionModeChangeAt')){width=context.modules.toc.$toc.data('positionModeChangeAt');}
588589 context.$wikitext.css({'position':'','height':''});context.$ui.find('.wikiEditor-ui-right').css({'marginRight':'','position':'','left':'','right':'','float':'','top':'','height':''});context.$ui.find('.wikiEditor-ui-left').css({'width':'','position':'','left':'','float':'','right':''});}
589590 $.wikiEditor.modules.toc.fn.redraw(context,width);},disable:function(context){if(context.modules.toc.$toc.data('collapsed')){context.$ui.find('.wikiEditor-ui-toc-expandControl').hide();}else{if(context.modules.toc.$toc.data('positionMode')=='goofy'){$.wikiEditor.modules.toc.fn.switchLayout(context);}

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r61499Moved the JS for event binding within the iframe to the outter frame, since t...tparscal20:13, 25 January 2010

Status & tagging log