r63679 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r63678‎ | r63679 | r63680 >
Date:15:35, 13 March 2010
Author:catrope
Status:deferred
Tags:
Comment:
UsabilityInitiative: More performance fixes
* Don't purge offsets after collapsing <p>s, turns out not to be necessary. This means we no longer have to regenerate offsets for every template we wrap
* We do need to purge offsets after removing each wrapper though
* Kill depth tracking in traverser, we don't use it for anything anymore
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.templateEditor.js (modified) (history)

Diff [purge]

Index: trunk/extensions/UsabilityInitiative/UsabilityInitiative.hooks.php
@@ -72,20 +72,20 @@
7373 array( 'src' => 'js/plugins/jquery.delayedBind.js', 'version' => 1 ),
7474 array( 'src' => 'js/plugins/jquery.suggestions.js', 'version' => 7 ),
7575 array( 'src' => 'js/plugins/jquery.textSelection.js', 'version' => 27 ),
76 - array( 'src' => 'js/plugins/jquery.wikiEditor.js', 'version' => 167 ),
77 - array( 'src' => 'js/plugins/jquery.wikiEditor.highlight.js', 'version' => 42 ),
 76+ array( 'src' => 'js/plugins/jquery.wikiEditor.js', 'version' => 168 ),
 77+ array( 'src' => 'js/plugins/jquery.wikiEditor.highlight.js', 'version' => 43 ),
7878 array( 'src' => 'js/plugins/jquery.wikiEditor.toolbar.js', 'version' => 52 ),
7979 array( 'src' => 'js/plugins/jquery.wikiEditor.dialogs.js', 'version' => 21 ),
8080 array( 'src' => 'js/plugins/jquery.wikiEditor.toc.js', 'version' => 97 ),
8181 array( 'src' => 'js/plugins/jquery.wikiEditor.preview.js', 'version' => 11 ),
82 - array( 'src' => 'js/plugins/jquery.wikiEditor.templateEditor.js', 'version' => 55 ),
 82+ array( 'src' => 'js/plugins/jquery.wikiEditor.templateEditor.js', 'version' => 56 ),
8383 array( 'src' => 'js/plugins/jquery.wikiEditor.publish.js', 'version' => 3 ),
8484 ),
8585 'combined' => array(
86 - array( 'src' => 'js/plugins.combined.js', 'version' => 332 ),
 86+ array( 'src' => 'js/plugins.combined.js', 'version' => 333 ),
8787 ),
8888 'minified' => array(
89 - array( 'src' => 'js/plugins.combined.min.js', 'version' => 332 ),
 89+ array( 'src' => 'js/plugins.combined.min.js', 'version' => 333 ),
9090 ),
9191 ),
9292 );
Index: trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.templateEditor.js
@@ -118,7 +118,7 @@
119119 }
120120 }, //mark
121121
122 - keydown: function( context, event ){
 122+ keydown: function( context, event ) {
123123 // reset our ignoreKeypress variable if it's set to true
124124 if( context.$iframe.data( 'ignoreKeypress' ) ) context.$iframe.data( 'ignoreKeypress', false );
125125 var $evtElem = event.jQueryNode;
Index: trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.js
@@ -654,7 +654,7 @@
655655 // We need the traverser because there can be other weird stuff in between
656656
657657 // Check for preceding text
658 - var t = new context.fn.rawTraverser( this.firstChild, 0, this, $pre.get( 0 ), true ).prev();
 658+ var t = new context.fn.rawTraverser( this.firstChild, this, $pre.get( 0 ), true ).prev();
659659 while ( t && t.node.nodeName != '#text' && t.node.nodeName != 'BR' && t.node.nodeName != 'P' ) {
660660 t = t.prev();
661661 }
@@ -663,7 +663,7 @@
664664 }
665665
666666 // Check for following text
667 - t = new context.fn.rawTraverser( this.lastChild, 0, this, $pre.get( 0 ), true ).next();
 667+ t = new context.fn.rawTraverser( this.lastChild, this, $pre.get( 0 ), true ).next();
668668 while ( t && t.node.nodeName != '#text' && t.node.nodeName != 'BR' && t.node.nodeName != 'P' ) {
669669 t = t.next();
670670 }
@@ -769,19 +769,16 @@
770770 /**
771771 * Object used by traverser(). Don't use this unless you know what you're doing
772772 */
773 - 'rawTraverser': function( node, depth, inP, ancestor, skipNoinclude ) {
 773+ 'rawTraverser': function( node, inP, ancestor, skipNoinclude ) {
774774 this.node = node;
775 - this.depth = depth;
776775 this.inP = inP;
777776 this.ancestor = ancestor;
778777 this.skipNoinclude = skipNoinclude;
779778 this.next = function() {
780779 var p = this.node;
781 - var nextDepth = this.depth;
782780 var nextInP = this.inP;
783781 while ( p && !p.nextSibling ) {
784782 p = p.parentNode;
785 - nextDepth--;
786783 if ( p == this.ancestor ) {
787784 // We're back at the ancestor, stop here
788785 p = null;
@@ -805,23 +802,20 @@
806803 }
807804 if ( p && p.firstChild ) {
808805 p = p.firstChild;
809 - nextDepth++;
810806 if ( p.nodeName == "P" ) {
811807 nextInP = p;
812808 }
813809 }
814810 } while ( p && p.firstChild );
815811 // Instead of calling the rawTraverser constructor, inline it. This avoids function call overhead
816 - return p ? { 'node': p, 'depth': nextDepth, 'inP': nextInP, 'ancestor': this.ancestor,
 812+ return p ? { 'node': p, 'inP': nextInP, 'ancestor': this.ancestor,
817813 'skipNoinclude': this.skipNoinclude, 'next': this.next, 'prev': this.prev } : null;
818814 };
819815 this.prev = function() {
820816 var p = this.node;
821 - var prevDepth = this.depth;
822817 var prevInP = this.inP;
823818 while ( p && !p.previousSibling ) {
824819 p = p.parentNode;
825 - prevDepth--;
826820 if ( p == this.ancestor ) {
827821 // We're back at the ancestor, stop here
828822 p = null;
@@ -845,14 +839,13 @@
846840 }
847841 if ( p && p.lastChild ) {
848842 p = p.lastChild;
849 - prevDepth++;
850843 if ( p.nodeName == "P" ) {
851844 prevInP = p;
852845 }
853846 }
854847 } while ( p && p.lastChild );
855848 // Instead of calling the rawTraverser constructor, inline it. This avoids function call overhead
856 - return p ? { 'node': p, 'depth': prevDepth, 'inP': prevInP, 'ancestor': this.ancestor,
 849+ return p ? { 'node': p, 'inP': prevInP, 'ancestor': this.ancestor,
857850 'skipNoinclude': this.skipNoinclude, 'next': this.next, 'prev': this.prev } : null;
858851 };
859852 },
@@ -860,18 +853,14 @@
861854 * Get an object used to traverse the leaf nodes in the iframe DOM. This traversal skips leaf nodes
862855 * inside an element with the wikiEditor-noinclude class. This basically wraps rawTraverser
863856 *
864 - * Usage:
865 - * var t = context.fn.traverser( context.$content );
866 - * // t.node is the first textnode, t.depth is its depth
867 - * t.goNext();
868 - * // t.node is the second textnode, t.depth is its depth
869 - * // Trying to advance past the end will set t.node to null
 857+ * @param start Node to start at
 858+ * @return Traverser object, use .next() or .prev() to get a traverser object referring to the
 859+ * previous/next node
870860 */
871861 'traverser': function( start ) {
872862 // Find the leftmost leaf node in the tree
873863 var startNode = start.jquery ? start.get( 0 ) : start;
874864 var node = startNode;
875 - var depth = 0;
876865 var inP = node.nodeName == "P" ? node : null;
877866 do {
878867 // Filter nodes with the wikiEditor-noinclude class
@@ -882,13 +871,12 @@
883872 }
884873 if ( node && node.firstChild ) {
885874 node = node.firstChild;
886 - depth++;
887875 if ( node.nodeName == "P" ) {
888876 inP = node;
889877 }
890878 }
891879 } while ( node && node.firstChild );
892 - return new context.fn.rawTraverser( node, depth, inP, startNode, true );
 880+ return new context.fn.rawTraverser( node, inP, startNode, true );
893881 },
894882 'getOffset': function( offset ) {
895883 if ( !context.offsets ) {
@@ -914,9 +902,7 @@
915903 'node': base.node,
916904 'offset': base.offset + offset - lowerBound,
917905 'length': base.length,
918 - 'depth': base.depth,
919 - 'lastTextNode': base.lastTextNode,
920 - 'lastTextNodeDepth': base.lastTextNodeDepth
 906+ 'lastTextNode': base.lastTextNode
921907 };
922908 },
923909 'purgeOffsets': function() {
@@ -925,7 +911,7 @@
926912 'refreshOffsets': function() {
927913 context.offsets = [ ];
928914 var t = context.fn.traverser( context.$content );
929 - var pos = 0, lastTextNode = null, lastTextNodeDepth = null;
 915+ var pos = 0, lastTextNode = null;
930916 while ( t ) {
931917 if ( t.node.nodeName != '#text' && t.node.nodeName != 'BR' ) {
932918 t = t.next();
@@ -938,9 +924,7 @@
939925 'node': t.node,
940926 'offset': 0,
941927 'length': nextPos - pos + ( leavingP ? 1 : 0 ),
942 - 'depth': t.depth,
943 - 'lastTextNode': lastTextNode,
944 - 'lastTextNodeDepth': lastTextNodeDepth
 928+ 'lastTextNode': lastTextNode
945929 };
946930 if ( leavingP ) {
947931 // <p>Foo</p> looks like "Foo\n", make it quack like it too
@@ -949,15 +933,12 @@
950934 'node': t.node,
951935 'offset': nextPos - pos,
952936 'length': nextPos - pos + 1,
953 - 'depth': t.depth,
954 - 'lastTextNode': lastTextNode,
955 - 'lastTextNodeDepth': lastTextNodeDepth
 937+ 'lastTextNode': lastTextNode
956938 };
957939 }
958940 pos = nextPos + ( leavingP ? 1 : 0 );
959941 if ( t.node.nodeName == '#text' ) {
960942 lastTextNode = t.node;
961 - lastTextNodeDepth = t.depth;
962943 }
963944 t = nextT;
964945 }
Index: trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.highlight.js
@@ -186,7 +186,6 @@
187187 continue;
188188 }
189189 var startNode = s.node;
190 - var startDepth = s.depth;
191190
192191 // Don't wrap leading BRs, produces undesirable results
193192 // FIXME: It's also possible that the offset is a bit high because getOffset() has incremented
@@ -196,7 +195,6 @@
197196 start++;
198197 s = context.fn.getOffset( start );
199198 startNode = s.node;
200 - startDepth = s.depth;
201199 }
202200
203201 // The next marker starts somewhere in this textNode or at this BR
@@ -218,7 +216,6 @@
219217 // with lastTextNode == oldStartNode, but that doesn't really matter
220218 var subtracted = s.offset;
221219 var oldLength = s.length;
222 - var oldDepth = s.depth;
223220
224221 var j, o;
225222 // Update offset objects referring to oldStartNode
@@ -237,7 +234,6 @@
238235 o.offset -= subtracted;
239236 o.length -= subtracted;
240237 o.lastTextNode = oldStartNode;
241 - o.lastTextNodeDepth = oldDepth;
242238 }
243239 }
244240 }
@@ -251,7 +247,6 @@
252248 continue;
253249 }
254250 var endNode = e.node;
255 - var endDepth = e.depth;
256251 if ( e.offset + 1 < e.length - 1 && endNode.nodeName == '#text' ) {
257252 // Split off the suffix. This puts the suffix in a new node and leaves the rest in endNode
258253 var newEndNode = endNode;
@@ -260,7 +255,7 @@
261256 // Update offset objects
262257 var subtracted = e.offset + 1;
263258 var oldLength = e.length;
264 - var oldDepth = e.depth;
 259+
265260
266261 var j, o;
267262 // Update offset objects referring to oldEndNode
@@ -278,7 +273,6 @@
279274 o.offset -= subtracted;
280275 o.length -= subtracted;
281276 o.lastTextNode = oldEndNode;
282 - o.lastTextNodeDepth = oldDepth;
283277 }
284278 }
285279 }
@@ -286,14 +280,13 @@
287281 // Don't wrap trailing BRs, doing that causes weird issues
288282 if ( endNode.nodeName == 'BR' ) {
289283 endNode = e.lastTextNode;
290 - endDepth = e.lastTextNodeDepth;
291284 }
292285
293286 // If startNode and endNode have different parents, we need to pull endNode and all textnodes in between
294287 // into startNode's parent and replace </p><p> with <br>
295288 if ( startNode.parentNode != endNode.parentNode ) {
296289 var startP = $( startNode ).closest( 'p' ).get( 0 );
297 - var t = new context.fn.rawTraverser( startNode, 0, startP, context.$content.get( 0 ), false );
 290+ var t = new context.fn.rawTraverser( startNode, startP, context.$content.get( 0 ), false );
298291 var afterStart = startNode.nextSibling;
299292 var lastP = startP;
300293 var nextT = t.next();
@@ -341,7 +334,6 @@
342335 // Moving nodes around like this invalidates offset objects
343336 // TODO: Update offset objects ourselves for performance. Requires rewriting this code block to be
344337 // offset-based rather than traverser-based
345 - context.fn.purgeOffsets();
346338 }
347339
348340 // Now wrap everything between startNode and endNode (may be equal).
@@ -412,11 +404,9 @@
413405 // Assume anchor == 'wrap'
414406 $(this).replaceWith( this.childNodes );
415407 }
 408+ context.fn.purgeOffsets();
416409 });
417410
418 - // Purge offsets after we're done
419 - // TODO: Ideally this is not needed
420 - context.fn.purgeOffsets();
421411 }
422412 }
423413
Index: trunk/extensions/UsabilityInitiative/js/plugins.combined.js
@@ -7197,7 +7197,7 @@
71987198 // We need the traverser because there can be other weird stuff in between
71997199
72007200 // Check for preceding text
7201 - var t = new context.fn.rawTraverser( this.firstChild, 0, this, $pre.get( 0 ), true ).prev();
 7201+ var t = new context.fn.rawTraverser( this.firstChild, this, $pre.get( 0 ), true ).prev();
72027202 while ( t && t.node.nodeName != '#text' && t.node.nodeName != 'BR' && t.node.nodeName != 'P' ) {
72037203 t = t.prev();
72047204 }
@@ -7206,7 +7206,7 @@
72077207 }
72087208
72097209 // Check for following text
7210 - t = new context.fn.rawTraverser( this.lastChild, 0, this, $pre.get( 0 ), true ).next();
 7210+ t = new context.fn.rawTraverser( this.lastChild, this, $pre.get( 0 ), true ).next();
72117211 while ( t && t.node.nodeName != '#text' && t.node.nodeName != 'BR' && t.node.nodeName != 'P' ) {
72127212 t = t.next();
72137213 }
@@ -7312,19 +7312,16 @@
73137313 /**
73147314 * Object used by traverser(). Don't use this unless you know what you're doing
73157315 */
7316 - 'rawTraverser': function( node, depth, inP, ancestor, skipNoinclude ) {
 7316+ 'rawTraverser': function( node, inP, ancestor, skipNoinclude ) {
73177317 this.node = node;
7318 - this.depth = depth;
73197318 this.inP = inP;
73207319 this.ancestor = ancestor;
73217320 this.skipNoinclude = skipNoinclude;
73227321 this.next = function() {
73237322 var p = this.node;
7324 - var nextDepth = this.depth;
73257323 var nextInP = this.inP;
73267324 while ( p && !p.nextSibling ) {
73277325 p = p.parentNode;
7328 - nextDepth--;
73297326 if ( p == this.ancestor ) {
73307327 // We're back at the ancestor, stop here
73317328 p = null;
@@ -7348,23 +7345,20 @@
73497346 }
73507347 if ( p && p.firstChild ) {
73517348 p = p.firstChild;
7352 - nextDepth++;
73537349 if ( p.nodeName == "P" ) {
73547350 nextInP = p;
73557351 }
73567352 }
73577353 } while ( p && p.firstChild );
73587354 // Instead of calling the rawTraverser constructor, inline it. This avoids function call overhead
7359 - return p ? { 'node': p, 'depth': nextDepth, 'inP': nextInP, 'ancestor': this.ancestor,
 7355+ return p ? { 'node': p, 'inP': nextInP, 'ancestor': this.ancestor,
73607356 'skipNoinclude': this.skipNoinclude, 'next': this.next, 'prev': this.prev } : null;
73617357 };
73627358 this.prev = function() {
73637359 var p = this.node;
7364 - var prevDepth = this.depth;
73657360 var prevInP = this.inP;
73667361 while ( p && !p.previousSibling ) {
73677362 p = p.parentNode;
7368 - prevDepth--;
73697363 if ( p == this.ancestor ) {
73707364 // We're back at the ancestor, stop here
73717365 p = null;
@@ -7388,14 +7382,13 @@
73897383 }
73907384 if ( p && p.lastChild ) {
73917385 p = p.lastChild;
7392 - prevDepth++;
73937386 if ( p.nodeName == "P" ) {
73947387 prevInP = p;
73957388 }
73967389 }
73977390 } while ( p && p.lastChild );
73987391 // Instead of calling the rawTraverser constructor, inline it. This avoids function call overhead
7399 - return p ? { 'node': p, 'depth': prevDepth, 'inP': prevInP, 'ancestor': this.ancestor,
 7392+ return p ? { 'node': p, 'inP': prevInP, 'ancestor': this.ancestor,
74007393 'skipNoinclude': this.skipNoinclude, 'next': this.next, 'prev': this.prev } : null;
74017394 };
74027395 },
@@ -7403,18 +7396,14 @@
74047397 * Get an object used to traverse the leaf nodes in the iframe DOM. This traversal skips leaf nodes
74057398 * inside an element with the wikiEditor-noinclude class. This basically wraps rawTraverser
74067399 *
7407 - * Usage:
7408 - * var t = context.fn.traverser( context.$content );
7409 - * // t.node is the first textnode, t.depth is its depth
7410 - * t.goNext();
7411 - * // t.node is the second textnode, t.depth is its depth
7412 - * // Trying to advance past the end will set t.node to null
 7400+ * @param start Node to start at
 7401+ * @return Traverser object, use .next() or .prev() to get a traverser object referring to the
 7402+ * previous/next node
74137403 */
74147404 'traverser': function( start ) {
74157405 // Find the leftmost leaf node in the tree
74167406 var startNode = start.jquery ? start.get( 0 ) : start;
74177407 var node = startNode;
7418 - var depth = 0;
74197408 var inP = node.nodeName == "P" ? node : null;
74207409 do {
74217410 // Filter nodes with the wikiEditor-noinclude class
@@ -7425,13 +7414,12 @@
74267415 }
74277416 if ( node && node.firstChild ) {
74287417 node = node.firstChild;
7429 - depth++;
74307418 if ( node.nodeName == "P" ) {
74317419 inP = node;
74327420 }
74337421 }
74347422 } while ( node && node.firstChild );
7435 - return new context.fn.rawTraverser( node, depth, inP, startNode, true );
 7423+ return new context.fn.rawTraverser( node, inP, startNode, true );
74367424 },
74377425 'getOffset': function( offset ) {
74387426 if ( !context.offsets ) {
@@ -7457,9 +7445,7 @@
74587446 'node': base.node,
74597447 'offset': base.offset + offset - lowerBound,
74607448 'length': base.length,
7461 - 'depth': base.depth,
7462 - 'lastTextNode': base.lastTextNode,
7463 - 'lastTextNodeDepth': base.lastTextNodeDepth
 7449+ 'lastTextNode': base.lastTextNode
74647450 };
74657451 },
74667452 'purgeOffsets': function() {
@@ -7468,7 +7454,7 @@
74697455 'refreshOffsets': function() {
74707456 context.offsets = [ ];
74717457 var t = context.fn.traverser( context.$content );
7472 - var pos = 0, lastTextNode = null, lastTextNodeDepth = null;
 7458+ var pos = 0, lastTextNode = null;
74737459 while ( t ) {
74747460 if ( t.node.nodeName != '#text' && t.node.nodeName != 'BR' ) {
74757461 t = t.next();
@@ -7481,9 +7467,7 @@
74827468 'node': t.node,
74837469 'offset': 0,
74847470 'length': nextPos - pos + ( leavingP ? 1 : 0 ),
7485 - 'depth': t.depth,
7486 - 'lastTextNode': lastTextNode,
7487 - 'lastTextNodeDepth': lastTextNodeDepth
 7471+ 'lastTextNode': lastTextNode
74887472 };
74897473 if ( leavingP ) {
74907474 // <p>Foo</p> looks like "Foo\n", make it quack like it too
@@ -7492,15 +7476,12 @@
74937477 'node': t.node,
74947478 'offset': nextPos - pos,
74957479 'length': nextPos - pos + 1,
7496 - 'depth': t.depth,
7497 - 'lastTextNode': lastTextNode,
7498 - 'lastTextNodeDepth': lastTextNodeDepth
 7480+ 'lastTextNode': lastTextNode
74997481 };
75007482 }
75017483 pos = nextPos + ( leavingP ? 1 : 0 );
75027484 if ( t.node.nodeName == '#text' ) {
75037485 lastTextNode = t.node;
7504 - lastTextNodeDepth = t.depth;
75057486 }
75067487 t = nextT;
75077488 }
@@ -8727,7 +8708,6 @@
87288709 continue;
87298710 }
87308711 var startNode = s.node;
8731 - var startDepth = s.depth;
87328712
87338713 // Don't wrap leading BRs, produces undesirable results
87348714 // FIXME: It's also possible that the offset is a bit high because getOffset() has incremented
@@ -8737,7 +8717,6 @@
87388718 start++;
87398719 s = context.fn.getOffset( start );
87408720 startNode = s.node;
8741 - startDepth = s.depth;
87428721 }
87438722
87448723 // The next marker starts somewhere in this textNode or at this BR
@@ -8759,7 +8738,6 @@
87608739 // with lastTextNode == oldStartNode, but that doesn't really matter
87618740 var subtracted = s.offset;
87628741 var oldLength = s.length;
8763 - var oldDepth = s.depth;
87648742
87658743 var j, o;
87668744 // Update offset objects referring to oldStartNode
@@ -8778,7 +8756,6 @@
87798757 o.offset -= subtracted;
87808758 o.length -= subtracted;
87818759 o.lastTextNode = oldStartNode;
8782 - o.lastTextNodeDepth = oldDepth;
87838760 }
87848761 }
87858762 }
@@ -8792,7 +8769,6 @@
87938770 continue;
87948771 }
87958772 var endNode = e.node;
8796 - var endDepth = e.depth;
87978773 if ( e.offset + 1 < e.length - 1 && endNode.nodeName == '#text' ) {
87988774 // Split off the suffix. This puts the suffix in a new node and leaves the rest in endNode
87998775 var newEndNode = endNode;
@@ -8801,7 +8777,7 @@
88028778 // Update offset objects
88038779 var subtracted = e.offset + 1;
88048780 var oldLength = e.length;
8805 - var oldDepth = e.depth;
 8781+
88068782
88078783 var j, o;
88088784 // Update offset objects referring to oldEndNode
@@ -8819,7 +8795,6 @@
88208796 o.offset -= subtracted;
88218797 o.length -= subtracted;
88228798 o.lastTextNode = oldEndNode;
8823 - o.lastTextNodeDepth = oldDepth;
88248799 }
88258800 }
88268801 }
@@ -8827,14 +8802,13 @@
88288803 // Don't wrap trailing BRs, doing that causes weird issues
88298804 if ( endNode.nodeName == 'BR' ) {
88308805 endNode = e.lastTextNode;
8831 - endDepth = e.lastTextNodeDepth;
88328806 }
88338807
88348808 // If startNode and endNode have different parents, we need to pull endNode and all textnodes in between
88358809 // into startNode's parent and replace </p><p> with <br>
88368810 if ( startNode.parentNode != endNode.parentNode ) {
88378811 var startP = $( startNode ).closest( 'p' ).get( 0 );
8838 - var t = new context.fn.rawTraverser( startNode, 0, startP, context.$content.get( 0 ), false );
 8812+ var t = new context.fn.rawTraverser( startNode, startP, context.$content.get( 0 ), false );
88398813 var afterStart = startNode.nextSibling;
88408814 var lastP = startP;
88418815 var nextT = t.next();
@@ -8882,7 +8856,6 @@
88838857 // Moving nodes around like this invalidates offset objects
88848858 // TODO: Update offset objects ourselves for performance. Requires rewriting this code block to be
88858859 // offset-based rather than traverser-based
8886 - context.fn.purgeOffsets();
88878860 }
88888861
88898862 // Now wrap everything between startNode and endNode (may be equal).
@@ -8953,11 +8926,9 @@
89548927 // Assume anchor == 'wrap'
89558928 $(this).replaceWith( this.childNodes );
89568929 }
 8930+ context.fn.purgeOffsets();
89578931 });
89588932
8959 - // Purge offsets after we're done
8960 - // TODO: Ideally this is not needed
8961 - context.fn.purgeOffsets();
89628933 }
89638934 }
89648935
@@ -9380,7 +9351,7 @@
93819352 }
93829353 }, //mark
93839354
9384 - keydown: function( context, event ){
 9355+ keydown: function( context, event ) {
93859356 // reset our ignoreKeypress variable if it's set to true
93869357 if( context.$iframe.data( 'ignoreKeypress' ) ) context.$iframe.data( 'ignoreKeypress', false );
93879358 var $evtElem = event.jQueryNode;
Index: trunk/extensions/UsabilityInitiative/js/plugins.combined.min.js
@@ -479,9 +479,9 @@
480480 if(!context.$tabs.children().size()){addTab({'name':'wikitext','titleMsg':'wikieditor-wikitext-tab'});}
481481 addTab(options);return $('<div></div>').addClass('wikiEditor-ui-view wikiEditor-ui-view-'+options.name).hide().appendTo(context.$ui);},'highlightLine':function($element,mode){if(!$element.is('p')){$element=$element.closest('p');}
482482 $element.css('backgroundColor','#AACCFF');setTimeout(function(){$element.animate({'backgroundColor':'white'},'slow');},100);setTimeout(function(){$element.css('backgroundColor','white');},1000);},'htmlToText':function(html){if(html in context.htmlToTextMap){return context.htmlToTextMap[html];}
483 -var origHTML=html;html=html.replace(/\r?\n/g,"").replace(/&nbsp;/g," ").replace(/\<br[^\>]*\>\<\/p\>/gi,'</p>').replace(/\<\/p\>\s*\<p[^\>]*\>/gi,"\n").replace(/\<br[^\>]*\>/gi,"\n").replace(/\<\/p\>(\n*)\<p[^\>]*\>/gi,"$1\n").replace(/\<p[^\>]*\><p[^\>]*\>/gi,'<p>').replace(/\<\/p\><\/p\>/gi,'</p>');var leading=html.match(/^\s*/)[0];var trailing=html.match(/\s*$/)[0];html=html.substr(leading.length,html.length-leading.length-trailing.length);var $pre=$('<pre>'+html+'</pre>');$pre.find('.wikiEditor-noinclude').each(function(){$(this).remove();});$pre.find('.wikiEditor-tab').each(function(){$(this).text("\t");});$pre.find('br').each(function(){$(this).replaceWith("\n");});$pre.find('p').each(function(){var text=$(this).text();var t=new context.fn.rawTraverser(this.firstChild,0,this,$pre.get(0),true).prev();while(t&&t.node.nodeName!='#text'&&t.node.nodeName!='BR'&&t.node.nodeName!='P'){t=t.prev();}
 483+var origHTML=html;html=html.replace(/\r?\n/g,"").replace(/&nbsp;/g," ").replace(/\<br[^\>]*\>\<\/p\>/gi,'</p>').replace(/\<\/p\>\s*\<p[^\>]*\>/gi,"\n").replace(/\<br[^\>]*\>/gi,"\n").replace(/\<\/p\>(\n*)\<p[^\>]*\>/gi,"$1\n").replace(/\<p[^\>]*\><p[^\>]*\>/gi,'<p>').replace(/\<\/p\><\/p\>/gi,'</p>');var leading=html.match(/^\s*/)[0];var trailing=html.match(/\s*$/)[0];html=html.substr(leading.length,html.length-leading.length-trailing.length);var $pre=$('<pre>'+html+'</pre>');$pre.find('.wikiEditor-noinclude').each(function(){$(this).remove();});$pre.find('.wikiEditor-tab').each(function(){$(this).text("\t");});$pre.find('br').each(function(){$(this).replaceWith("\n");});$pre.find('p').each(function(){var text=$(this).text();var t=new context.fn.rawTraverser(this.firstChild,this,$pre.get(0),true).prev();while(t&&t.node.nodeName!='#text'&&t.node.nodeName!='BR'&&t.node.nodeName!='P'){t=t.prev();}
484484 if(t){text="\n"+text;}
485 -t=new context.fn.rawTraverser(this.lastChild,0,this,$pre.get(0),true).next();while(t&&t.node.nodeName!='#text'&&t.node.nodeName!='BR'&&t.node.nodeName!='P'){t=t.next();}
 485+t=new context.fn.rawTraverser(this.lastChild,this,$pre.get(0),true).next();while(t&&t.node.nodeName!='#text'&&t.node.nodeName!='BR'&&t.node.nodeName!='P'){t=t.next();}
486486 if(t&&!t.inP&&t.node.nodeName=='#text'&&t.node.nodeValue.charAt(0)!='\n'&&t.node.nodeValue.charAt(0)!='\r'){text+="\n";}
487487 $(this).text(text);});var retval;if($.browser.msie){retval=$('<pre>'+$pre.html()+'</pre>').text().replace(/\r/g,'\n');}else{retval=$pre.text();}
488488 return context.htmlToTextMap[origHTML]=leading+retval+trailing;},'beforeSelection':function(classname,strict){if(typeof classname=='undefined'){classname='';}
@@ -495,23 +495,23 @@
496496 var classStr=' '+classname+' ';while(e){if(!strict&&(!classname||(' '+e.className+' ').indexOf(classStr)!=-1)){return $(e);}
497497 var next=e.previousSibling;while(next&&next.lastChild){next=next.lastChild;}
498498 e=next||e.parentNode;strict=false;}
499 -return $([]);},'rawTraverser':function(node,depth,inP,ancestor,skipNoinclude){this.node=node;this.depth=depth;this.inP=inP;this.ancestor=ancestor;this.skipNoinclude=skipNoinclude;this.next=function(){var p=this.node;var nextDepth=this.depth;var nextInP=this.inP;while(p&&!p.nextSibling){p=p.parentNode;nextDepth--;if(p==this.ancestor){p=null;}
 499+return $([]);},'rawTraverser':function(node,inP,ancestor,skipNoinclude){this.node=node;this.inP=inP;this.ancestor=ancestor;this.skipNoinclude=skipNoinclude;this.next=function(){var p=this.node;var nextInP=this.inP;while(p&&!p.nextSibling){p=p.parentNode;if(p==this.ancestor){p=null;}
500500 if(p&&p.nodeName=="P"){nextInP=null;}}
501501 p=p?p.nextSibling:null;if(p&&p.nodeName=="P"){nextInP=p;}
502502 do{if(this.skipNoinclude){while(p&&(' '+p.className+' ').indexOf(' wikiEditor-noinclude ')!=-1){p=p.nextSibling;}}
503 -if(p&&p.firstChild){p=p.firstChild;nextDepth++;if(p.nodeName=="P"){nextInP=p;}}}while(p&&p.firstChild);return p?{'node':p,'depth':nextDepth,'inP':nextInP,'ancestor':this.ancestor,'skipNoinclude':this.skipNoinclude,'next':this.next,'prev':this.prev}:null;};this.prev=function(){var p=this.node;var prevDepth=this.depth;var prevInP=this.inP;while(p&&!p.previousSibling){p=p.parentNode;prevDepth--;if(p==this.ancestor){p=null;}
 503+if(p&&p.firstChild){p=p.firstChild;if(p.nodeName=="P"){nextInP=p;}}}while(p&&p.firstChild);return p?{'node':p,'inP':nextInP,'ancestor':this.ancestor,'skipNoinclude':this.skipNoinclude,'next':this.next,'prev':this.prev}:null;};this.prev=function(){var p=this.node;var prevInP=this.inP;while(p&&!p.previousSibling){p=p.parentNode;if(p==this.ancestor){p=null;}
504504 if(p&&p.nodeName=="P"){prevInP=null;}}
505505 p=p?p.previousSibling:null;if(p&&p.nodeName=="P"){prevInP=p;}
506506 do{if(this.skipNoinclude){while(p&&(' '+p.className+' ').indexOf(' wikiEditor-noinclude ')!=-1){p=p.previousSibling;}}
507 -if(p&&p.lastChild){p=p.lastChild;prevDepth++;if(p.nodeName=="P"){prevInP=p;}}}while(p&&p.lastChild);return p?{'node':p,'depth':prevDepth,'inP':prevInP,'ancestor':this.ancestor,'skipNoinclude':this.skipNoinclude,'next':this.next,'prev':this.prev}:null;};},'traverser':function(start){var startNode=start.jquery?start.get(0):start;var node=startNode;var depth=0;var inP=node.nodeName=="P"?node:null;do{while(node&&(' '+node.className+' ').indexOf(' wikiEditor-noinclude ')!=-1){node=node.nextSibling;}
508 -if(node&&node.firstChild){node=node.firstChild;depth++;if(node.nodeName=="P"){inP=node;}}}while(node&&node.firstChild);return new context.fn.rawTraverser(node,depth,inP,startNode,true);},'getOffset':function(offset){if(!context.offsets){context.fn.refreshOffsets();}
 507+if(p&&p.lastChild){p=p.lastChild;if(p.nodeName=="P"){prevInP=p;}}}while(p&&p.lastChild);return p?{'node':p,'inP':prevInP,'ancestor':this.ancestor,'skipNoinclude':this.skipNoinclude,'next':this.next,'prev':this.prev}:null;};},'traverser':function(start){var startNode=start.jquery?start.get(0):start;var node=startNode;var inP=node.nodeName=="P"?node:null;do{while(node&&(' '+node.className+' ').indexOf(' wikiEditor-noinclude ')!=-1){node=node.nextSibling;}
 508+if(node&&node.firstChild){node=node.firstChild;if(node.nodeName=="P"){inP=node;}}}while(node&&node.firstChild);return new context.fn.rawTraverser(node,inP,startNode,true);},'getOffset':function(offset){if(!context.offsets){context.fn.refreshOffsets();}
509509 if(offset in context.offsets){return context.offsets[offset];}
510510 var lowerBound=-1;for(var o in context.offsets){if(o>offset){break;}
511511 lowerBound=o;}
512512 if(!(lowerBound in context.offsets)){return null;}
513 -var base=context.offsets[lowerBound];return context.offsets[offset]={'node':base.node,'offset':base.offset+offset-lowerBound,'length':base.length,'depth':base.depth,'lastTextNode':base.lastTextNode,'lastTextNodeDepth':base.lastTextNodeDepth};},'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;}
514 -var nextPos=t.node.nodeName=='#text'?pos+t.node.nodeValue.length:pos+1;var nextT=t.next();var leavingP=t.node.nodeName=='#text'&&t.inP&&nextT&&(!nextT.inP||nextT.inP!=t.inP);context.offsets[pos]={'node':t.node,'offset':0,'length':nextPos-pos+(leavingP?1:0),'depth':t.depth,'lastTextNode':lastTextNode,'lastTextNodeDepth':lastTextNodeDepth};if(leavingP){context.offsets[nextPos]={'node':t.node,'offset':nextPos-pos,'length':nextPos-pos+1,'depth':t.depth,'lastTextNode':lastTextNode,'lastTextNodeDepth':lastTextNodeDepth};}
515 -pos=nextPos+(leavingP?1:0);if(t.node.nodeName=='#text'){lastTextNode=t.node;lastTextNodeDepth=t.depth;}
 513+var base=context.offsets[lowerBound];return context.offsets[offset]={'node':base.node,'offset':base.offset+offset-lowerBound,'length':base.length,'lastTextNode':base.lastTextNode};},'purgeOffsets':function(){context.offsets=null;},'refreshOffsets':function(){context.offsets=[];var t=context.fn.traverser(context.$content);var pos=0,lastTextNode=null;while(t){if(t.node.nodeName!='#text'&&t.node.nodeName!='BR'){t=t.next();continue;}
 514+var nextPos=t.node.nodeName=='#text'?pos+t.node.nodeValue.length:pos+1;var nextT=t.next();var leavingP=t.node.nodeName=='#text'&&t.inP&&nextT&&(!nextT.inP||nextT.inP!=t.inP);context.offsets[pos]={'node':t.node,'offset':0,'length':nextPos-pos+(leavingP?1:0),'lastTextNode':lastTextNode};if(leavingP){context.offsets[nextPos]={'node':t.node,'offset':nextPos-pos,'length':nextPos-pos+1,'lastTextNode':lastTextNode};}
 515+pos=nextPos+(leavingP?1:0);if(t.node.nodeName=='#text'){lastTextNode=t.node;}
516516 t=nextT;}},'saveSelection':function(){if(!$.browser.msie){return;}
517517 context.$iframe[0].contentWindow.focus();context.savedSelection=context.$iframe[0].contentWindow.document.selection.createRange();},'restoreSelection':function(){if(!$.browser.msie||context.savedSelection===null){return;}
518518 context.$iframe[0].contentWindow.focus();context.savedSelection.select();context.savedSelection=null;},'updateHistory':function(htmlChange){var newHTML=context.$content.html();var newSel=context.fn.getCaretPosition();if(context.history.length==0||(htmlChange&&context.oldDelayedHistoryPosition==context.historyPosition)){context.fn.purgeOffsets();context.oldDelayedSel=newSel;if(context.historyPosition<-1){context.history.splice(context.history.length+context.historyPosition+1);context.historyPosition=-1;}
@@ -591,19 +591,18 @@
592592 if(context.modules.highlight.markersStr==markersStr){return;}
593593 context.modules.highlight.markersStr=markersStr;var oldStarts=[];if(!context.modules.highlight.markersOldStarts){context.modules.highlight.markersOldStarts=[];}
594594 var visited=[],v=0;for(var i=0;i<markers.length;i++){var start=markers[i].start;var s=context.fn.getOffset(start);if(!s){continue;}
595 -var startNode=s.node;var startDepth=s.depth;while(startNode.nodeName=='BR'||s.offset==startNode.nodeValue.length){start++;s=context.fn.getOffset(start);startNode=s.node;startDepth=s.depth;}
596 -if(s.offset>0&&s.node.nodeName=='#text'){var newStartNode=startNode.splitText(s.offset<s.node.nodeValue.length?s.offset:s.node.nodeValue.length-1);var oldStartNode=startNode;startNode=newStartNode;var subtracted=s.offset;var oldLength=s.length;var oldDepth=s.depth;var j,o;for(j=start-subtracted;j<start;j++){if(j in context.offsets){o=context.offsets[j];o.node=oldStartNode;o.length=subtracted;}}
597 -for(j=start;j<start-subtracted+oldLength;j++){if(j in context.offsets){o=context.offsets[j];o.node=newStartNode;o.offset-=subtracted;o.length-=subtracted;o.lastTextNode=oldStartNode;o.lastTextNodeDepth=oldDepth;}}}
 595+var startNode=s.node;while(startNode.nodeName=='BR'||s.offset==startNode.nodeValue.length){start++;s=context.fn.getOffset(start);startNode=s.node;}
 596+if(s.offset>0&&s.node.nodeName=='#text'){var newStartNode=startNode.splitText(s.offset<s.node.nodeValue.length?s.offset:s.node.nodeValue.length-1);var oldStartNode=startNode;startNode=newStartNode;var subtracted=s.offset;var oldLength=s.length;var j,o;for(j=start-subtracted;j<start;j++){if(j in context.offsets){o=context.offsets[j];o.node=oldStartNode;o.length=subtracted;}}
 597+for(j=start;j<start-subtracted+oldLength;j++){if(j in context.offsets){o=context.offsets[j];o.node=newStartNode;o.offset-=subtracted;o.length-=subtracted;o.lastTextNode=oldStartNode;}}}
598598 var end=markers[i].end;var e=context.fn.getOffset(end-1);if(!e){continue;}
599 -var endNode=e.node;var endDepth=e.depth;if(e.offset+1<e.length-1&&endNode.nodeName=='#text'){var newEndNode=endNode;var oldEndNode=endNode.splitText(e.offset+1);var subtracted=e.offset+1;var oldLength=e.length;var oldDepth=e.depth;var j,o;for(j=end-subtracted;j<end;j++){if(j in context.offsets){o=context.offsets[j];o.node=oldEndNode;o.length=subtracted;}}
600 -for(j=end;j<end-subtracted+oldLength;j++){if(j in context.offsets){o=context.offsets[j];o.node=newEndNode;o.offset-=subtracted;o.length-=subtracted;o.lastTextNode=oldEndNode;o.lastTextNodeDepth=oldDepth;}}}
601 -if(endNode.nodeName=='BR'){endNode=e.lastTextNode;endDepth=e.lastTextNodeDepth;}
602 -if(startNode.parentNode!=endNode.parentNode){var startP=$(startNode).closest('p').get(0);var t=new context.fn.rawTraverser(startNode,0,startP,context.$content.get(0),false);var afterStart=startNode.nextSibling;var lastP=startP;var nextT=t.next();while(nextT&&t.node!=endNode){t=nextT;nextT=t.next();if(t.node.parentNode!=startNode.parentNode){var oldParent=t.node.parentNode;if(afterStart){if(lastP!=t.inP){startNode.parentNode.insertBefore(startNode.ownerDocument.createElement('br'),afterStart);}
 599+var endNode=e.node;if(e.offset+1<e.length-1&&endNode.nodeName=='#text'){var newEndNode=endNode;var oldEndNode=endNode.splitText(e.offset+1);var subtracted=e.offset+1;var oldLength=e.length;var j,o;for(j=end-subtracted;j<end;j++){if(j in context.offsets){o=context.offsets[j];o.node=oldEndNode;o.length=subtracted;}}
 600+for(j=end;j<end-subtracted+oldLength;j++){if(j in context.offsets){o=context.offsets[j];o.node=newEndNode;o.offset-=subtracted;o.length-=subtracted;o.lastTextNode=oldEndNode;}}}
 601+if(endNode.nodeName=='BR'){endNode=e.lastTextNode;}
 602+if(startNode.parentNode!=endNode.parentNode){var startP=$(startNode).closest('p').get(0);var t=new context.fn.rawTraverser(startNode,startP,context.$content.get(0),false);var afterStart=startNode.nextSibling;var lastP=startP;var nextT=t.next();while(nextT&&t.node!=endNode){t=nextT;nextT=t.next();if(t.node.parentNode!=startNode.parentNode){var oldParent=t.node.parentNode;if(afterStart){if(lastP!=t.inP){startNode.parentNode.insertBefore(startNode.ownerDocument.createElement('br'),afterStart);}
603603 if(!(oldParent.childNodes.length==1&&oldParent.firstChild.nodeName=='BR')){while(oldParent.firstChild){startNode.parentNode.insertBefore(oldParent.firstChild,afterStart);}}}else{if(lastP!=t.inP){startNode.parentNode.appendChild(startNode.ownerDocument.createElement('br'));}
604604 if(!(oldParent.childNodes.length==1&&oldParent.firstChild.nodeName=='BR')){while(oldParent.firstChild){startNode.parentNode.appendChild(oldParent.firstChild);}}}
605605 oldParent.parentNode.removeChild(oldParent);}
606 -lastP=t.inP;}
607 -context.fn.purgeOffsets();}
 606+lastP=t.inP;}}
608607 var ca1=startNode,ca2=endNode;if(ca1&&ca2&&ca1.parentNode){var anchor=markers[i].getAnchor(ca1,ca2);if(!anchor){var commonAncestor=ca1.parentNode;if(markers[i].anchor=='wrap'){var newNode=ca1.ownerDocument.createElement('span');var nextNode=ca2.nextSibling;var n=ca1;while(n!=nextNode){var ns=n.nextSibling;newNode.appendChild(n);n=ns;}
609608 if(nextNode){commonAncestor.insertBefore(newNode,nextNode);}else{commonAncestor.appendChild(newNode);}
610609 anchor=newNode;}else if(markers[i].anchor=='tag'){anchor=commonAncestor;}
@@ -611,7 +610,8 @@
612611 visited[v++]=anchor;}}
613612 var j=0;context.$content.find('.wikiEditor-highlight').each(function(){if(visited[j]==this){j++;return true;}
614613 var marker=$(this).data('marker');if(marker&&typeof marker.beforeUnwrap=='function')
615 -marker.beforeUnwrap(this);if((marker&&marker.anchor=='tag')||$(this).is('p')){$(this).removeAttr('class');}else{$(this).replaceWith(this.childNodes);}});context.fn.purgeOffsets();}}};})(jQuery);(function($){$.wikiEditor.modules.preview={'browsers':{'ltr':{'msie':[['>=',7]],'firefox':[['>=',3]],'opera':[['>=',9.6]],'safari':[['>=',4]]},'rtl':{'msie':[['>=',8]],'firefox':[['>=',3]],'opera':[['>=',9.6]],'safari':[['>=',4]]}},fn:{create:function(context,config){if('initialized'in context.modules.preview){return;}
 614+marker.beforeUnwrap(this);if((marker&&marker.anchor=='tag')||$(this).is('p')){$(this).removeAttr('class');}else{$(this).replaceWith(this.childNodes);}
 615+context.fn.purgeOffsets();});}}};})(jQuery);(function($){$.wikiEditor.modules.preview={'browsers':{'ltr':{'msie':[['>=',7]],'firefox':[['>=',3]],'opera':[['>=',9.6]],'safari':[['>=',4]]},'rtl':{'msie':[['>=',8]],'firefox':[['>=',3]],'opera':[['>=',9.6]],'safari':[['>=',4]]}},fn:{create:function(context,config){if('initialized'in context.modules.preview){return;}
616616 context.modules.preview={'initialized':true,'previewText':null,'changesText':null};context.modules.preview.$preview=context.fn.addView({'name':'preview','titleMsg':'wikieditor-preview-tab','init':function(context){var wikitext=context.fn.getContents();if(context.modules.preview.previewText==wikitext){return;}
617617 context.modules.preview.$preview.find('.wikiEditor-preview-contents').empty();context.modules.preview.$preview.find('.wikiEditor-preview-loading').show();$.post(wgScriptPath+'/api.php',{'action':'parse','title':wgPageName,'text':wikitext,'prop':'text','pst':'','format':'json'},function(data){if(typeof data.parse=='undefined'||typeof data.parse.text=='undefined'||typeof data.parse.text['*']=='undefined'){return;}
618618 context.modules.preview.previewText=wikitext;context.modules.preview.$preview.find('.wikiEditor-preview-loading').hide();context.modules.preview.$preview.find('.wikiEditor-preview-contents').html(data.parse.text['*']).find('a:not([href^=#])').click(function(){return false;});},'json');}});context.$changesTab=context.fn.addView({'name':'changes','titleMsg':'wikieditor-preview-changes-tab','init':function(context){var wikitext=context.fn.getContents();if(context.modules.preview.changesText==wikitext){return;}

Status & tagging log