r61649 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r61648‎ | r61649 | r61650 >
Date:23:29, 28 January 2010
Author:catrope
Status:deferred
Tags:
Comment:
UsabilityInitiative: Some fixes for <p> handling
* Append newlines to <p>s followed by textnodes in getContents() so "Foo<p>Bar</p>Baz" returns "Foo\nBar\nBaz" instead of "Foo\nBarBaz"
** Break out Traverser into context.fn.rawTraverser() to make this possible
** Still need to handle a freakish case where an anchor at the very start of the document followed by a <p> keeps getting added and removed. This needs a prev() function in Traverser, will do this tomorrow
* Repurpose inP to hold the actual <p> rather than a boolean. Use this to fix a bug where refreshOffsets() wouldn't (and couldn't) detect leaving a <p> and immediately entering another one in the same step
* Purge offsets when splitting text nodes: cached offset objects will hold invalid text nodes after splitting
* Prevent splitting off empty text nodes in cases where high offsets due to newline faking would cause this: IE really doesn't like this and creates an empty text node with no parents or siblings
* Don't try to split things that aren't text nodes
* Remove check for ca2.nextSibling that broke stuff
* Don't try to put <div>s inside <p>s, that's illegal and Firefox solves it in a weird way. Wrap the <p> too in this case
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)

Diff [purge]

Index: trunk/extensions/UsabilityInitiative/UsabilityInitiative.hooks.php
@@ -72,8 +72,8 @@
7373 array( 'src' => 'js/plugins/jquery.namespaceSelect.js', 'version' => 1 ),
7474 array( 'src' => 'js/plugins/jquery.suggestions.js', 'version' => 7 ),
7575 array( 'src' => 'js/plugins/jquery.textSelection.js', 'version' => 26 ),
76 - array( 'src' => 'js/plugins/jquery.wikiEditor.js', 'version' => 82 ),
77 - array( 'src' => 'js/plugins/jquery.wikiEditor.highlight.js', 'version' => 25 ),
 76+ array( 'src' => 'js/plugins/jquery.wikiEditor.js', 'version' => 83 ),
 77+ array( 'src' => 'js/plugins/jquery.wikiEditor.highlight.js', 'version' => 26 ),
7878 array( 'src' => 'js/plugins/jquery.wikiEditor.toolbar.js', 'version' => 45 ),
7979 array( 'src' => 'js/plugins/jquery.wikiEditor.dialogs.js', 'version' => 11 ),
8080 array( 'src' => 'js/plugins/jquery.wikiEditor.toc.js', 'version' => 75 ),
@@ -82,10 +82,10 @@
8383 array( 'src' => 'js/plugins/jquery.wikiEditor.publish.js', 'version' => 2 ),
8484 ),
8585 'combined' => array(
86 - array( 'src' => 'js/plugins.combined.js', 'version' => 195 ),
 86+ array( 'src' => 'js/plugins.combined.js', 'version' => 196 ),
8787 ),
8888 'minified' => array(
89 - array( 'src' => 'js/plugins.combined.min.js', 'version' => 195 ),
 89+ array( 'src' => 'js/plugins.combined.min.js', 'version' => 196 ),
9090 ),
9191 ),
9292 );
Index: trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.js
@@ -376,7 +376,19 @@
377377 // .find( '* + p' ) isn't good enough because textnodes aren't considered
378378 $pre.find( 'p' ).each( function() {
379379 if ( this.previousSibling || this.parentNode != $pre.get( 0 ) ) {
380 - $( this ).text( "\n" + $( this ).text() );
 380+ var text = "\n" + $( this ).text();
 381+ // If this <p> is preceded by some text, add a \n at the beginning, and if
 382+ // it's followed by a textnode, add a \n at the end
 383+ // We need the traverser because there can be other weird stuff in between
 384+ // TODO: We need a reverse traverser, write this
 385+ var t = new context.fn.rawTraverser( this.lastChild, -10, this ).next();
 386+ while ( t && t.node.nodeName != '#text' && t.node.nodeName != 'BR' && t.node.nodeName != 'P' ) {
 387+ t = t.next();
 388+ }
 389+ if ( t && !t.inP && t.node.nodeName != 'P' ) {
 390+ text += "\n";
 391+ }
 392+ $( this ).text( text );
381393 }
382394 } );
383395 return $pre.text();
@@ -742,8 +754,52 @@
743755 return retval || $( [] );
744756 },
745757 /**
 758+ * Object used by traverser(). Don't use this unless you know what you're doing
 759+ */
 760+ 'rawTraverser': function( node, depth, inP ) {
 761+ this.node = node;
 762+ this.depth = depth;
 763+ this.inP = inP;
 764+ this.next = function() {
 765+ var p = this.node;
 766+ var nextDepth = this.depth;
 767+ var nextInP = this.inP;
 768+ while ( p && !p.nextSibling ) {
 769+ p = p.parentNode;
 770+ nextDepth--;
 771+ if ( nextDepth == 0 ) {
 772+ // We're back at the start node
 773+ p = null;
 774+ }
 775+ if ( p && p.nodeName == "P" ) {
 776+ nextInP = null;
 777+ }
 778+ }
 779+ p = p ? p.nextSibling : null;
 780+ if ( p && p.nodeName == "P" ) {
 781+ nextInP = p;
 782+ }
 783+ do {
 784+ // Filter nodes with the wikiEditor-noinclude class
 785+ // Don't use $( p ).hasClass( 'wikiEditor-noinclude' ) because
 786+ // $() is slow in a tight loop
 787+ while ( p && ( ' ' + p.className + ' ' ).indexOf( ' wikiEditor-noinclude ' ) != -1 ) {
 788+ p = p.nextSibling;
 789+ }
 790+ if ( p && p.firstChild ) {
 791+ p = p.firstChild;
 792+ nextDepth++;
 793+ if ( p.nodeName == "P" ) {
 794+ nextInP = p;
 795+ }
 796+ }
 797+ } while ( p && p.firstChild );
 798+ return p ? new context.fn.rawTraverser( p, nextDepth, nextInP ) : null;
 799+ };
 800+ },
 801+ /**
746802 * Get an object used to traverse the leaf nodes in the iframe DOM. This traversal skips leaf nodes
747 - * inside an element with the wikiEditor-noinclude class.
 803+ * inside an element with the wikiEditor-noinclude class. This basically wraps rawTraverser
748804 *
749805 * Usage:
750806 * var t = context.fn.traverser( context.$content );
@@ -753,48 +809,10 @@
754810 * // Trying to advance past the end will set t.node to null
755811 */
756812 'traverser': function( start ) {
757 - function Traverser( node, depth, inP ) {
758 - this.node = node;
759 - this.depth = depth;
760 - this.inP = inP;
761 - this.next = function() {
762 - var p = this.node;
763 - var nextDepth = this.depth;
764 - var nextInP = this.inP;
765 - while ( p && !p.nextSibling ) {
766 - if ( p.nodeName == "P" ) {
767 - nextInP = false;
768 - }
769 - p = p.parentNode;
770 - nextDepth--;
771 - if ( nextDepth == 0 ) {
772 - // We're back at the start node
773 - p = null;
774 - }
775 - }
776 - p = p ? p.nextSibling : null;
777 - do {
778 - // Filter nodes with the wikiEditor-noinclude class
779 - // Don't use $( p ).hasClass( 'wikiEditor-noinclude' ) because
780 - // $() is slow in a tight loop
781 - while ( p && ( ' ' + p.className + ' ' ).indexOf( ' wikiEditor-noinclude ' ) != -1 ) {
782 - p = p.nextSibling;
783 - }
784 - if ( p && p.firstChild ) {
785 - p = p.firstChild;
786 - nextDepth++;
787 - if ( p.nodeName == "P" ) {
788 - nextInP = true;
789 - }
790 - }
791 - } while ( p && p.firstChild );
792 - return p ? new Traverser( p, nextDepth, nextInP ) : null;
793 - };
794 - }
795813 // Find the leftmost leaf node in the tree
796814 var node = start.jquery ? start.get( 0 ) : start;
797815 var depth = 0;
798 - var inP = node.nodeName == "P";
 816+ var inP = node.nodeName == "P" ? node : null;
799817 do {
800818 // Filter nodes with the wikiEditor-noinclude class
801819 // Don't use $( p ).hasClass( 'wikiEditor-noinclude' ) because
@@ -806,11 +824,11 @@
807825 node = node.firstChild;
808826 depth++;
809827 if ( node.nodeName == "P" ) {
810 - inP = true;
 828+ inP = node;
811829 }
812830 }
813831 } while ( node && node.firstChild );
814 - return new Traverser( node, depth, inP );
 832+ return new context.fn.rawTraverser( node, depth, inP );
815833 },
816834 'getOffset': function( offset ) {
817835 if ( !context.offsets ) {
@@ -849,13 +867,13 @@
850868 var t = context.fn.traverser( context.$content );
851869 var pos = 0, lastTextNode = null, lastTextNodeDepth = null;
852870 while ( t ) {
853 - if ( t.node.nodeName != '#text' && t.node.nodeName != 'BR' ) {
 871+ if ( t.node.nodeName != '#text' && t.node.nodeName != 'BR' && t.node.nodeName != 'P' ) {
854872 t = t.next();
855873 continue;
856874 }
857875 var nextPos = t.node.nodeName == '#text' ? pos + t.node.nodeValue.length : pos + 1;
858876 var nextT = t.next();
859 - var leavingP = t.inP && nextT && !nextT.inP;
 877+ var leavingP = t.node.nodeName != 'P' && t.inP && nextT && ( !nextT.inP || nextT.inP != t.inP );
860878 context.offsets[pos] = {
861879 'node': t.node,
862880 'offset': 0,
Index: trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.highlight.js
@@ -163,23 +163,27 @@
164164 }
165165 var startNode = s.node;
166166 var startDepth = s.depth;
167 - // The next marker starts somewhere in this textNode or at this BR
168 - if ( s.offset > 0 ) {
169 - // t.node must be a textnode at this point because
170 - // only textnodes can have offset > 0
171 -
172 - // Split off the prefix
173 - // This leaves the prefix in the current node and puts
174 - // the rest in a new node which is our start node
175 - startNode = startNode.splitText( s.offset );
176 - }
 167+
177168 // Don't wrap leading BRs, produces undesirable results
178 - while ( startNode.nodeName == 'BR' ) {
 169+ // FIXME: It's also possible that the offset is a bit high because getOffset() has incremented
 170+ // .length to fake the newline caused by startNode being in a P. In this case, prevent
 171+ // the textnode splitting below from making startNode an empty textnode, IE barfs on that
 172+ while ( startNode.nodeName == 'BR' || s.offset == startNode.nodeValue.length ) {
179173 start++;
180174 s = context.fn.getOffset( start );
181175 startNode = s.node;
182176 startDepth = s.depth;
183177 }
 178+
 179+ // The next marker starts somewhere in this textNode or at this BR
 180+ if ( s.offset > 0 && s.node.nodeName == '#text' ) {
 181+ // Split off the prefix
 182+ // This leaves the prefix in the current node and puts
 183+ // the rest in a new node which is our start node
 184+ startNode = startNode.splitText( s.offset );
 185+ // This also invalidates cached offset objects
 186+ context.fn.purgeOffsets(); // TODO: Optimize better, get end offset object earlier
 187+ }
184188
185189 var end = markers[i].end;
186190 var e = context.fn.getOffset( end );
@@ -189,14 +193,13 @@
190194 }
191195 var endNode = e.node;
192196 var endDepth = e.depth;
193 - if ( e.offset < e.length - 1 ) {
194 - // t.node must be a textnode at this point because
195 - // .length is 1 for BRs and offset can't be < 0
196 -
 197+ if ( e.offset < e.length - 1 && e.node.nodeName == '#text' ) {
197198 // Split off the suffix - This puts the suffix in a new node and leaves the rest in the current
198199 // node.
199200 // endNode.nodeValue.length - ( newPos - markers[i].end )
200201 endNode.splitText( e.offset + 1 );
 202+ // This also invalidates cached offset objects
 203+ context.fn.purgeOffsets(); // TODO: Optimize better, get end offset object earlier
201204 }
202205
203206 // Don't wrap trailing BRs, doing that causes weird issues
@@ -236,13 +239,19 @@
237240 ca1 = ca1.parentNode.firstChild == ca1 ? ca1.parentNode : null;
238241 ca2 = ca2.parentNode.lastChild == ca2 ? ca2.parentNode : null;
239242 }
240 - if ( ca1 && ca2 && ca1.parentNode && ca2.nextSibling ) {
 243+ if ( ca1 && ca2 && ca1.parentNode ) {
241244 var anchor = markers[i].getAnchor( ca1, ca2 );
242245 if ( !anchor ) {
243246 // We have to store things like .parentNode and .nextSibling because appendChild() changes these
244247 // properties
245248 var newNode = ca1.ownerDocument.createElement( 'div' );
246249 var commonAncestor = ca1.parentNode;
 250+ // Special case: can't put block elements in a <p>
 251+ if ( commonAncestor.nodeName == 'P' && commonAncestor.parentNode ) {
 252+ commonAncestor = commonAncestor.parentNode;
 253+ ca1 = ca1.parentNode;
 254+ ca2 = ca2.parentNode;
 255+ }
247256 var nextNode = ca2.nextSibling;
248257 if ( markers[i].anchor == 'wrap' ) {
249258 // Append all nodes between ca1 and ca2 (inclusive) to newNode
Index: trunk/extensions/UsabilityInitiative/js/plugins.combined.js
@@ -6800,7 +6800,19 @@
68016801 // .find( '* + p' ) isn't good enough because textnodes aren't considered
68026802 $pre.find( 'p' ).each( function() {
68036803 if ( this.previousSibling || this.parentNode != $pre.get( 0 ) ) {
6804 - $( this ).text( "\n" + $( this ).text() );
 6804+ var text = "\n" + $( this ).text();
 6805+ // If this <p> is preceded by some text, add a \n at the beginning, and if
 6806+ // it's followed by a textnode, add a \n at the end
 6807+ // We need the traverser because there can be other weird stuff in between
 6808+ // TODO: We need a reverse traverser, write this
 6809+ var t = new context.fn.rawTraverser( this.lastChild, -10, this ).next();
 6810+ while ( t && t.node.nodeName != '#text' && t.node.nodeName != 'BR' && t.node.nodeName != 'P' ) {
 6811+ t = t.next();
 6812+ }
 6813+ if ( t && !t.inP && t.node.nodeName != 'P' ) {
 6814+ text += "\n";
 6815+ }
 6816+ $( this ).text( text );
68056817 }
68066818 } );
68076819 return $pre.text();
@@ -7166,8 +7178,52 @@
71677179 return retval || $( [] );
71687180 },
71697181 /**
 7182+ * Object used by traverser(). Don't use this unless you know what you're doing
 7183+ */
 7184+ 'rawTraverser': function( node, depth, inP ) {
 7185+ this.node = node;
 7186+ this.depth = depth;
 7187+ this.inP = inP;
 7188+ this.next = function() {
 7189+ var p = this.node;
 7190+ var nextDepth = this.depth;
 7191+ var nextInP = this.inP;
 7192+ while ( p && !p.nextSibling ) {
 7193+ p = p.parentNode;
 7194+ nextDepth--;
 7195+ if ( nextDepth == 0 ) {
 7196+ // We're back at the start node
 7197+ p = null;
 7198+ }
 7199+ if ( p && p.nodeName == "P" ) {
 7200+ nextInP = null;
 7201+ }
 7202+ }
 7203+ p = p ? p.nextSibling : null;
 7204+ if ( p && p.nodeName == "P" ) {
 7205+ nextInP = p;
 7206+ }
 7207+ do {
 7208+ // Filter nodes with the wikiEditor-noinclude class
 7209+ // Don't use $( p ).hasClass( 'wikiEditor-noinclude' ) because
 7210+ // $() is slow in a tight loop
 7211+ while ( p && ( ' ' + p.className + ' ' ).indexOf( ' wikiEditor-noinclude ' ) != -1 ) {
 7212+ p = p.nextSibling;
 7213+ }
 7214+ if ( p && p.firstChild ) {
 7215+ p = p.firstChild;
 7216+ nextDepth++;
 7217+ if ( p.nodeName == "P" ) {
 7218+ nextInP = p;
 7219+ }
 7220+ }
 7221+ } while ( p && p.firstChild );
 7222+ return p ? new context.fn.rawTraverser( p, nextDepth, nextInP ) : null;
 7223+ };
 7224+ },
 7225+ /**
71707226 * Get an object used to traverse the leaf nodes in the iframe DOM. This traversal skips leaf nodes
7171 - * inside an element with the wikiEditor-noinclude class.
 7227+ * inside an element with the wikiEditor-noinclude class. This basically wraps rawTraverser
71727228 *
71737229 * Usage:
71747230 * var t = context.fn.traverser( context.$content );
@@ -7177,48 +7233,10 @@
71787234 * // Trying to advance past the end will set t.node to null
71797235 */
71807236 'traverser': function( start ) {
7181 - function Traverser( node, depth, inP ) {
7182 - this.node = node;
7183 - this.depth = depth;
7184 - this.inP = inP;
7185 - this.next = function() {
7186 - var p = this.node;
7187 - var nextDepth = this.depth;
7188 - var nextInP = this.inP;
7189 - while ( p && !p.nextSibling ) {
7190 - if ( p.nodeName == "P" ) {
7191 - nextInP = false;
7192 - }
7193 - p = p.parentNode;
7194 - nextDepth--;
7195 - if ( nextDepth == 0 ) {
7196 - // We're back at the start node
7197 - p = null;
7198 - }
7199 - }
7200 - p = p ? p.nextSibling : null;
7201 - do {
7202 - // Filter nodes with the wikiEditor-noinclude class
7203 - // Don't use $( p ).hasClass( 'wikiEditor-noinclude' ) because
7204 - // $() is slow in a tight loop
7205 - while ( p && ( ' ' + p.className + ' ' ).indexOf( ' wikiEditor-noinclude ' ) != -1 ) {
7206 - p = p.nextSibling;
7207 - }
7208 - if ( p && p.firstChild ) {
7209 - p = p.firstChild;
7210 - nextDepth++;
7211 - if ( p.nodeName == "P" ) {
7212 - nextInP = true;
7213 - }
7214 - }
7215 - } while ( p && p.firstChild );
7216 - return p ? new Traverser( p, nextDepth, nextInP ) : null;
7217 - };
7218 - }
72197237 // Find the leftmost leaf node in the tree
72207238 var node = start.jquery ? start.get( 0 ) : start;
72217239 var depth = 0;
7222 - var inP = node.nodeName == "P";
 7240+ var inP = node.nodeName == "P" ? node : null;
72237241 do {
72247242 // Filter nodes with the wikiEditor-noinclude class
72257243 // Don't use $( p ).hasClass( 'wikiEditor-noinclude' ) because
@@ -7230,11 +7248,11 @@
72317249 node = node.firstChild;
72327250 depth++;
72337251 if ( node.nodeName == "P" ) {
7234 - inP = true;
 7252+ inP = node;
72357253 }
72367254 }
72377255 } while ( node && node.firstChild );
7238 - return new Traverser( node, depth, inP );
 7256+ return new context.fn.rawTraverser( node, depth, inP );
72397257 },
72407258 'getOffset': function( offset ) {
72417259 if ( !context.offsets ) {
@@ -7273,13 +7291,13 @@
72747292 var t = context.fn.traverser( context.$content );
72757293 var pos = 0, lastTextNode = null, lastTextNodeDepth = null;
72767294 while ( t ) {
7277 - if ( t.node.nodeName != '#text' && t.node.nodeName != 'BR' ) {
 7295+ if ( t.node.nodeName != '#text' && t.node.nodeName != 'BR' && t.node.nodeName != 'P' ) {
72787296 t = t.next();
72797297 continue;
72807298 }
72817299 var nextPos = t.node.nodeName == '#text' ? pos + t.node.nodeValue.length : pos + 1;
72827300 var nextT = t.next();
7283 - var leavingP = t.inP && nextT && !nextT.inP;
 7301+ var leavingP = t.node.nodeName != 'P' && t.inP && nextT && ( !nextT.inP || nextT.inP != t.inP );
72847302 context.offsets[pos] = {
72857303 'node': t.node,
72867304 'offset': 0,
@@ -7784,23 +7802,27 @@
77857803 }
77867804 var startNode = s.node;
77877805 var startDepth = s.depth;
7788 - // The next marker starts somewhere in this textNode or at this BR
7789 - if ( s.offset > 0 ) {
7790 - // t.node must be a textnode at this point because
7791 - // only textnodes can have offset > 0
7792 -
7793 - // Split off the prefix
7794 - // This leaves the prefix in the current node and puts
7795 - // the rest in a new node which is our start node
7796 - startNode = startNode.splitText( s.offset );
7797 - }
 7806+
77987807 // Don't wrap leading BRs, produces undesirable results
7799 - while ( startNode.nodeName == 'BR' ) {
 7808+ // FIXME: It's also possible that the offset is a bit high because getOffset() has incremented
 7809+ // .length to fake the newline caused by startNode being in a P. In this case, prevent
 7810+ // the textnode splitting below from making startNode an empty textnode, IE barfs on that
 7811+ while ( startNode.nodeName == 'BR' || s.offset == startNode.nodeValue.length ) {
78007812 start++;
78017813 s = context.fn.getOffset( start );
78027814 startNode = s.node;
78037815 startDepth = s.depth;
78047816 }
 7817+
 7818+ // The next marker starts somewhere in this textNode or at this BR
 7819+ if ( s.offset > 0 && s.node.nodeName == '#text' ) {
 7820+ // Split off the prefix
 7821+ // This leaves the prefix in the current node and puts
 7822+ // the rest in a new node which is our start node
 7823+ startNode = startNode.splitText( s.offset );
 7824+ // This also invalidates cached offset objects
 7825+ context.fn.purgeOffsets(); // TODO: Optimize better, get end offset object earlier
 7826+ }
78057827
78067828 var end = markers[i].end;
78077829 var e = context.fn.getOffset( end );
@@ -7810,14 +7832,13 @@
78117833 }
78127834 var endNode = e.node;
78137835 var endDepth = e.depth;
7814 - if ( e.offset < e.length - 1 ) {
7815 - // t.node must be a textnode at this point because
7816 - // .length is 1 for BRs and offset can't be < 0
7817 -
 7836+ if ( e.offset < e.length - 1 && e.node.nodeName == '#text' ) {
78187837 // Split off the suffix - This puts the suffix in a new node and leaves the rest in the current
78197838 // node.
78207839 // endNode.nodeValue.length - ( newPos - markers[i].end )
78217840 endNode.splitText( e.offset + 1 );
 7841+ // This also invalidates cached offset objects
 7842+ context.fn.purgeOffsets(); // TODO: Optimize better, get end offset object earlier
78227843 }
78237844
78247845 // Don't wrap trailing BRs, doing that causes weird issues
@@ -7857,13 +7878,19 @@
78587879 ca1 = ca1.parentNode.firstChild == ca1 ? ca1.parentNode : null;
78597880 ca2 = ca2.parentNode.lastChild == ca2 ? ca2.parentNode : null;
78607881 }
7861 - if ( ca1 && ca2 && ca1.parentNode && ca2.nextSibling ) {
 7882+ if ( ca1 && ca2 && ca1.parentNode ) {
78627883 var anchor = markers[i].getAnchor( ca1, ca2 );
78637884 if ( !anchor ) {
78647885 // We have to store things like .parentNode and .nextSibling because appendChild() changes these
78657886 // properties
78667887 var newNode = ca1.ownerDocument.createElement( 'div' );
78677888 var commonAncestor = ca1.parentNode;
 7889+ // Special case: can't put block elements in a <p>
 7890+ if ( commonAncestor.nodeName == 'P' && commonAncestor.parentNode ) {
 7891+ commonAncestor = commonAncestor.parentNode;
 7892+ ca1 = ca1.parentNode;
 7893+ ca2 = ca2.parentNode;
 7894+ }
78687895 var nextNode = ca2.nextSibling;
78697896 if ( markers[i].anchor == 'wrap' ) {
78707897 // Append all nodes between ca1 and ca2 (inclusive) to newNode
Index: trunk/extensions/UsabilityInitiative/js/plugins.combined.min.js
@@ -450,7 +450,9 @@
451451 if(!context.$tabs.children().size()){addTab({'name':'wikitext','titleMsg':'wikieditor-wikitext-tab'});}
452452 addTab(options);return $('<div></div>').addClass('wikiEditor-ui-view wikiEditor-ui-view-'+options.name).hide().appendTo(context.$ui);},'htmlToText':function(html){var $pre=$('<pre>'+
453453 html.replace(/\r?\n/g,"").replace(/&nbsp;/g," ")
454 -+'</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(){if(this.previousSibling||this.parentNode!=$pre.get(0)){$(this).text("\n"+$(this).text());}});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();}
 454++'</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(){if(this.previousSibling||this.parentNode!=$pre.get(0)){var text="\n"+$(this).text();var t=new context.fn.rawTraverser(this.lastChild,-10,this).next();while(t&&t.node.nodeName!='#text'&&t.node.nodeName!='BR'&&t.node.nodeName!='P'){t=t.next();}
 455+if(t&&!t.inP&&t.node.nodeName!='P'){text+="\n";}
 456+$(this).text(text);}});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();}
455457 if(typeof retval.text!='undefined'){retval=context.fn.htmlToText(retval.htmlText);}else if(retval.toString){retval=retval.toString();}
456458 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.replace){selText=options.peri;}else if(selText.charAt(selText.length-1)==' '){selText=selText.substring(0,selText.length-1);post+=' ';}
457459 if(options.splitlines){selTextArr=selText.split(/\n/);}
@@ -484,18 +486,18 @@
485487 var next=e.previousSibling;while(next&&next.lastChild){next=next.lastChild;}
486488 e=next||e.parentNode;strict=false;}
487489 if(selector!='*')
488 -occurrences.removeClass('wikiEditor-beforeSelection-tagged');return retval||$([]);},'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;}
489 -p=p.parentNode;nextDepth--;if(nextDepth==0){p=null;}}
490 -p=p?p.nextSibling:null;do{while(p&&(' '+p.className+' ').indexOf(' wikiEditor-noinclude ')!=-1){p=p.nextSibling;}
491 -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;};}
492 -var node=start.jquery?start.get(0):start;var depth=0;var inP=node.nodeName=="P";do{while(node&&(' '+node.className+' ').indexOf(' wikiEditor-noinclude ')!=-1){node=node.nextSibling;}
493 -if(node&&node.firstChild){node=node.firstChild;depth++;if(node.nodeName=="P"){inP=true;}}}while(node&&node.firstChild);return new Traverser(node,depth,inP);},'getOffset':function(offset){if(!context.offsets){context.fn.refreshOffsets();}
 490+occurrences.removeClass('wikiEditor-beforeSelection-tagged');return retval||$([]);},'rawTraverser':function(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){p=p.parentNode;nextDepth--;if(nextDepth==0){p=null;}
 491+if(p&&p.nodeName=="P"){nextInP=null;}}
 492+p=p?p.nextSibling:null;if(p&&p.nodeName=="P"){nextInP=p;}
 493+do{while(p&&(' '+p.className+' ').indexOf(' wikiEditor-noinclude ')!=-1){p=p.nextSibling;}
 494+if(p&&p.firstChild){p=p.firstChild;nextDepth++;if(p.nodeName=="P"){nextInP=p;}}}while(p&&p.firstChild);return p?new context.fn.rawTraverser(p,nextDepth,nextInP):null;};},'traverser':function(start){var node=start.jquery?start.get(0):start;var depth=0;var inP=node.nodeName=="P"?node:null;do{while(node&&(' '+node.className+' ').indexOf(' wikiEditor-noinclude ')!=-1){node=node.nextSibling;}
 495+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);},'getOffset':function(offset){if(!context.offsets){context.fn.refreshOffsets();}
494496 if(offset in context.offsets){return context.offsets[offset];}
495497 var lowerBound=-1;for(var o in context.offsets){if(o>offset){break;}
496498 lowerBound=o;}
497499 if(!(lowerBound in context.offsets)){return null;}
498 -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;}
499 -var nextPos=t.node.nodeName=='#text'?pos+t.node.nodeValue.length:pos+1;var nextT=t.next();var leavingP=t.inP&&nextT&&!nextT.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};}
 500+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.node.nodeName!='P'){t=t.next();continue;}
 501+var nextPos=t.node.nodeName=='#text'?pos+t.node.nodeValue.length:pos+1;var nextT=t.next();var leavingP=t.node.nodeName!='P'&&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};}
500502 pos=nextPos+(leavingP?1:0);if(t.node.nodeName=='#text'){lastTextNode=t.node;lastTextNodeDepth=t.depth;}
501503 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;}}
502504 context.$content=$(context.$iframe[0].contentWindow.document.body);var html=context.$textarea.val().replace(/&nbsp;/g,'&amp;nbsp;').replace(/\<br\>/g,'&lt;br&gt;').replace(/\<span class="wikiEditor-tab"\>\<\/span\>/g,'&lt;span class=&quot;wikiEditor-tab&quot;&gt;&lt;/span&gt;');if($.browser.msie){if($.browser.versionNumber<=7){html=html.replace(/ /g,"&nbsp;");}else{html=html.replace(/(^|\n) /g,"$1&nbsp;");}
@@ -513,15 +515,16 @@
514516 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;}
515517 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);}}}}
516518 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;});for(var i=0;i<markers.length;i++){var start=markers[i].start;var s=context.fn.getOffset(start);if(!s){continue;}
517 -var startNode=s.node;var startDepth=s.depth;if(s.offset>0){startNode=startNode.splitText(s.offset);}
518 -while(startNode.nodeName=='BR'){start++;s=context.fn.getOffset(start);startNode=s.node;startDepth=s.depth;}
 519+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;}
 520+if(s.offset>0&&s.node.nodeName=='#text'){startNode=startNode.splitText(s.offset);context.fn.purgeOffsets();}
519521 var end=markers[i].end;var e=context.fn.getOffset(end);if(!e){continue;}
520 -var endNode=e.node;var endDepth=e.depth;if(e.offset<e.length-1){endNode.splitText(e.offset+1);}
 522+var endNode=e.node;var endDepth=e.depth;if(e.offset<e.length-1&&e.node.nodeName=='#text'){endNode.splitText(e.offset+1);context.fn.purgeOffsets();}
521523 if(endNode.nodeName=='BR'){endNode=e.lastTextNode;endDepth=e.lastTextNodeDepth;}
522524 var ca1=startNode,ca2=endNode;if(startDepth>endDepth){for(var j=0;j<startDepth-endDepth&&ca1;j++){ca1=ca1.parentNode.firstChild==ca1?ca1.parentNode:null;}}
523525 else if(startDepth<endDepth){for(var j=0;j<endDepth-startDepth&&ca2;j++){ca2=ca2.parentNode.lastChild==ca2?ca2.parentNode:null;}}
524526 while(ca1&&ca2&&ca1.parentNode&&ca2.parentNode&&ca1.parentNode!=ca2.parentNode&&ca1.parentNode.firstChild&&ca2.parentNode.lastChild){ca1=ca1.parentNode.firstChild==ca1?ca1.parentNode:null;ca2=ca2.parentNode.lastChild==ca2?ca2.parentNode:null;}
525 -if(ca1&&ca2&&ca1.parentNode&&ca2.nextSibling){var anchor=markers[i].getAnchor(ca1,ca2);if(!anchor){var newNode=ca1.ownerDocument.createElement('div');var commonAncestor=ca1.parentNode;var nextNode=ca2.nextSibling;if(markers[i].anchor=='wrap'){var n=ca1;while(n!=nextNode){var ns=n.nextSibling;newNode.appendChild(n);n=ns;}
 527+if(ca1&&ca2&&ca1.parentNode){var anchor=markers[i].getAnchor(ca1,ca2);if(!anchor){var newNode=ca1.ownerDocument.createElement('div');var commonAncestor=ca1.parentNode;if(commonAncestor.nodeName=='P'&&commonAncestor.parentNode){commonAncestor=commonAncestor.parentNode;ca1=ca1.parentNode;ca2=ca2.parentNode;}
 528+var nextNode=ca2.nextSibling;if(markers[i].anchor=='wrap'){var n=ca1;while(n!=nextNode){var ns=n.nextSibling;newNode.appendChild(n);n=ns;}
526529 if(nextNode){commonAncestor.insertBefore(newNode,nextNode);}else{commonAncestor.appendChild(newNode);}}else if(markers[i].anchor=='before'){commonAncestor.insertBefore(newNode,ca1);}else if(markers[i].anchor=='after'){if(nextNode){commonAncestor.insertBefore(newNode,nextNode);}else{commonAncestor.appendChild(newNode);}}
527530 $(newNode).data('marker',markers[i]).addClass('wikiEditor-highlight wikiEditor-highlight-tmp');markers[i].afterWrap(newNode,markers[i]);}else{$(anchor).addClass('wikiEditor-highlight-tmp').data('marker',markers[i]);markers[i].onSkip(anchor);}}}
528531 context.$content.find('div.wikiEditor-highlight:not(.wikiEditor-highlight-tmp)').each(function(){if($(this).data('marker')&&typeof $(this).data('marker').unwrap=='function')

Status & tagging log