From 63601400e476c6cf43d985f3e7b9864681695ed4 Mon Sep 17 00:00:00 2001 From: Pierre Schmitz Date: Fri, 18 Jan 2013 16:46:04 +0100 Subject: Update to MediaWiki 1.20.2 this update includes: * adjusted Arch Linux skin * updated FluxBBAuthPlugin * patch for https://bugzilla.wikimedia.org/show_bug.cgi?id=44024 --- .../modules/jquery.wikiEditor.highlight.js | 638 +++++++++++---------- 1 file changed, 327 insertions(+), 311 deletions(-) (limited to 'extensions/WikiEditor/modules/jquery.wikiEditor.highlight.js') diff --git a/extensions/WikiEditor/modules/jquery.wikiEditor.highlight.js b/extensions/WikiEditor/modules/jquery.wikiEditor.highlight.js index 48140206..9d964fa7 100644 --- a/extensions/WikiEditor/modules/jquery.wikiEditor.highlight.js +++ b/extensions/WikiEditor/modules/jquery.wikiEditor.highlight.js @@ -1,357 +1,373 @@ /* Highlight module for wikiEditor */ -( function( $ ) { $.wikiEditor.modules.highlight = { +( function ( $ ) { + +$.wikiEditor.modules.highlight = { + + /** + * Core Requirements + */ + req: [ 'iframe' ], -/** - * Core Requirements - */ -'req': [ 'iframe' ], -/** - * Configuration - */ -'cfg': { - 'styleVersion': 3 -}, -/** - * Internally used event handlers - */ -'evt': { - 'delayedChange': function( context, event ) { - if ( event.data.scope == 'realchange' ) { - $.wikiEditor.modules.highlight.fn.scan( context ); - $.wikiEditor.modules.highlight.fn.mark( context, event.data.scope ); - } - }, - 'ready': function( context, event ) { - $.wikiEditor.modules.highlight.fn.scan( context ); - $.wikiEditor.modules.highlight.fn.mark( context, 'ready' ); - } -}, -/** - * Internally used functions - */ -'fn': { /** - * Creates a highlight module within a wikiEditor - * - * @param config Configuration object to create module from + * Configuration */ - 'create': function( context, config ) { - context.modules.highlight.markersStr = ''; + cfg: { + styleVersion: 3 }, + /** - * Scans text division for tokens - * - * @param division + * Internally used event handlers */ - 'scan': function( context, division ) { - // Remove all existing tokens - var tokenArray = context.modules.highlight.tokenArray = []; - // Scan text for new tokens - var text = context.fn.getContents(); - // Perform a scan for each module which provides any expressions to scan for - // FIXME: This traverses the entire string once for every regex. Investigate - // whether |-concatenating regexes then traversing once is faster. - for ( var module in context.modules ) { - if ( module in $.wikiEditor.modules && 'exp' in $.wikiEditor.modules[module] ) { - for ( var exp in $.wikiEditor.modules[module].exp ) { - // Prepare configuration - var regex = $.wikiEditor.modules[module].exp[exp].regex; - var label = $.wikiEditor.modules[module].exp[exp].label; - var markAfter = $.wikiEditor.modules[module].exp[exp].markAfter || false; - // Search for tokens - var offset = 0, left, right, match; - while ( ( match = text.substr( offset ).match( regex ) ) != null ) { - right = ( left = offset + match.index ) + match[0].length; - tokenArray[tokenArray.length] = { - 'offset': markAfter ? right : left, - 'label': label, - 'tokenStart': left, - 'match': match - }; - // Move to the right of this match - offset = right; - } - } + evt: { + delayedChange: function ( context, event ) { + if ( event.data.scope == 'realchange' ) { + $.wikiEditor.modules.highlight.fn.scan( context ); + $.wikiEditor.modules.highlight.fn.mark( context, event.data.scope ); } + }, + ready: function ( context, event ) { + $.wikiEditor.modules.highlight.fn.scan( context ); + $.wikiEditor.modules.highlight.fn.mark( context, 'ready' ); } - // Sort by start - tokenArray.sort( function( a, b ) { return a.tokenStart - b.tokenStart; } ); - // Let the world know, a scan just happened! - context.fn.trigger( 'scan' ); }, + /** - * Marks up text with HTML - * - * @param division - * @param tokens + * Internally used functions */ - // FIXME: What do division and tokens do? - // TODO: Document the scan() and mark() APIs somewhere - 'mark': function( context, division, tokens ) { - // Reset markers - var markers = []; + fn: { + /** + * Creates a highlight module within a wikiEditor + * + * @param config Configuration object to create module from + */ + create: function ( context, config ) { + context.modules.highlight.markersStr = ''; + }, + /** + * Scans text division for tokens + * + * @param division + */ + scan: function ( context, division ) { + var tokenArray, text, module, exp, + left, right, match; + /*jshint eqnull: true */ - // Recycle markers that will be skipped in this run - if ( context.modules.highlight.markers && division != '' ) { - for ( var i = 0; i < context.modules.highlight.markers.length; i++ ) { - if ( context.modules.highlight.markers[i].skipDivision == division ) { - markers.push( context.modules.highlight.markers[i] ); + // Remove all existing tokens + tokenArray = context.modules.highlight.tokenArray = []; + // Scan text for new tokens + text = context.fn.getContents(); + // Perform a scan for each module which provides any expressions to scan for + // FIXME: This traverses the entire string once for every regex. Investigate + // whether |-concatenating regexes then traversing once is faster. + for ( module in context.modules ) { + if ( module in $.wikiEditor.modules && 'exp' in $.wikiEditor.modules[module] ) { + for ( exp in $.wikiEditor.modules[module].exp ) { + // Prepare configuration + var regex = $.wikiEditor.modules[module].exp[exp].regex; + var label = $.wikiEditor.modules[module].exp[exp].label; + var markAfter = $.wikiEditor.modules[module].exp[exp].markAfter || false; + // Search for tokens + var offset = 0; + while ( ( match = text.substr( offset ).match( regex ) ) != null ) { + right = ( left = offset + match.index ) + match[0].length; + tokenArray[tokenArray.length] = { + offset: markAfter ? right : left, + label: label, + tokenStart: left, + match: match + }; + // Move to the right of this match + offset = right; + } + } } } - } - context.modules.highlight.markers = markers; + // Sort by start + tokenArray.sort( function ( a, b ) { + return a.tokenStart - b.tokenStart; + } ); + // Let the world know, a scan just happened! + context.fn.trigger( 'scan' ); + }, - // Get all markers - context.fn.trigger( 'mark' ); - markers.sort( function( a, b ) { return a.start - b.start || a.end - b.end; } ); + /** + * Marks up text with HTML + * + * @param division + * @param tokens + */ + // FIXME: What do division and tokens do? + // TODO: Document the scan() and mark() APIs somewhere + mark: function ( context, division, tokens ) { + var i, subtracted, oldLength, j, o; - // Serialize the markers array to a string and compare it with the one stored in the previous run - if they're - // equal, there's no markers to change - var markersStr = ''; - for ( var i = 0; i < markers.length; i++ ) { - markersStr += markers[i].start + ',' + markers[i].end + ',' + markers[i].type + ','; - } - if ( context.modules.highlight.markersStr == markersStr ) { - // No change, bail out - return; - } - context.modules.highlight.markersStr = markersStr; + // Reset markers + var markers = []; - // Traverse the iframe DOM, inserting markers where they're needed - store visited markers here so we know which - // markers should be removed - var visited = [], v = 0; - for ( var i = 0; i < markers.length; i++ ) { - if ( typeof markers[i].skipDivision !== 'undefined' && ( division == markers[i].skipDivision ) ) { - continue; + // Recycle markers that will be skipped in this run + if ( context.modules.highlight.markers && division !== '' ) { + for ( i = 0; i < context.modules.highlight.markers.length; i++ ) { + if ( context.modules.highlight.markers[i].skipDivision == division ) { + markers.push( context.modules.highlight.markers[i] ); + } + } } + context.modules.highlight.markers = markers; - // We want to isolate each marker, so we may need to split textNodes if a marker starts or ends halfway one. - var start = markers[i].start; - var s = context.fn.getOffset( start ); - if ( !s ) { - // This shouldn't happen - continue; - } - var startNode = s.node; + // Get all markers + context.fn.trigger( 'mark' ); + markers.sort( function ( a, b ) { + return a.start - b.start || a.end - b.end; + } ); - // Don't wrap leading BRs, produces undesirable results - // FIXME: It's also possible that the offset is a bit high because getOffset() has incremented .length to - // fake the newline caused by startNode being in a P. In this case, prevent the textnode splitting below - // from making startNode an empty textnode, IE barfs on that - while ( startNode.nodeName == 'BR' || s.offset == startNode.nodeValue.length ) { - start++; - s = context.fn.getOffset( start ); - startNode = s.node; + // Serialize the markers array to a string and compare it with the one stored in the previous run - if they're + // equal, there's no markers to change + var markersStr = ''; + for ( i = 0; i < markers.length; i++ ) { + markersStr += markers[i].start + ',' + markers[i].end + ',' + markers[i].type + ','; + } + if ( context.modules.highlight.markersStr == markersStr ) { + // No change, bail out + return; } + context.modules.highlight.markersStr = markersStr; - // The next marker starts somewhere in this textNode or at this BR - if ( s.offset > 0 && s.node.nodeName == '#text' ) { - // Split off the prefix - this leaves the prefix in the current node and puts the rest in a new node - // which is our start node - var newStartNode = startNode.splitText( s.offset < s.node.nodeValue.length ? - s.offset : s.node.nodeValue.length - 1 - ); - var oldStartNode = startNode; - startNode = newStartNode; - // Update offset objects. We don't need purgeOffsets(), simply manipulating the existing offset objects - // will suffice - // FIXME: This manipulates context.offsets directly, which is ugly, but the performance improvement vs. - // purgeOffsets() is worth it - this code doesn't set lastTextNode to newStartNode for offset objects - // with lastTextNode == oldStartNode, but that doesn't really matter - var subtracted = s.offset; - var oldLength = s.length; + // Traverse the iframe DOM, inserting markers where they're needed - store visited markers here so we know which + // markers should be removed + var visited = [], v = 0; + for ( i = 0; i < markers.length; i++ ) { + if ( typeof markers[i].skipDivision !== 'undefined' && ( division == markers[i].skipDivision ) ) { + continue; + } - var j, o; - // Update offset objects referring to oldStartNode - for ( j = start - subtracted; j < start; j++ ) { - if ( j in context.offsets ) { - o = context.offsets[j]; - o.node = oldStartNode; - o.length = subtracted; - } + // We want to isolate each marker, so we may need to split textNodes if a marker starts or ends halfway one. + var start = markers[i].start; + var s = context.fn.getOffset( start ); + if ( !s ) { + // This shouldn't happen + continue; } - // Update offset objects referring to newStartNode - 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; - } + var startNode = s.node; + + // Don't wrap leading BRs, produces undesirable results + // FIXME: It's also possible that the offset is a bit high because getOffset() has incremented .length to + // fake the newline caused by startNode being in a P. In this case, prevent the textnode splitting below + // from making startNode an empty textnode, IE barfs on that + while ( startNode.nodeName === 'BR' || s.offset === startNode.nodeValue.length ) { + start++; + s = context.fn.getOffset( start ); + startNode = s.node; } - } - var end = markers[i].end; - // To avoid ending up at the first char of the next node, we grab the offset for end - 1 and add one to the - // offset - var e = context.fn.getOffset( end - 1 ); - if ( !e ) { - // This shouldn't happen - continue; - } - var endNode = e.node; - if ( e.offset + 1 < e.length - 1 && endNode.nodeName == '#text' ) { - // Split off the suffix. This puts the suffix in a new node and leaves the rest in endNode - var oldEndNode = endNode; - var newEndNode = endNode.splitText( e.offset + 1 ); - // Update offset objects - var subtracted = e.offset + 1; - var oldLength = e.length; - var j, o; - // Update offset objects referring to oldEndNode - for ( j = end - subtracted; j < end; j++ ) { - if ( j in context.offsets ) { - o = context.offsets[j]; - o.node = oldEndNode; - o.length = subtracted; + + // The next marker starts somewhere in this textNode or at this BR + if ( s.offset > 0 && s.node.nodeName == '#text' ) { + // Split off the prefix - this leaves the prefix in the current node and puts the rest in a new node + // which is our start node + var newStartNode = startNode.splitText( s.offset < s.node.nodeValue.length ? + s.offset : s.node.nodeValue.length - 1 + ); + var oldStartNode = startNode; + startNode = newStartNode; + // Update offset objects. We don't need purgeOffsets(), simply manipulating the existing offset objects + // will suffice + // FIXME: This manipulates context.offsets directly, which is ugly, but the performance improvement vs. + // purgeOffsets() is worth it - this code doesn't set lastTextNode to newStartNode for offset objects + // with lastTextNode == oldStartNode, but that doesn't really matter + subtracted = s.offset; + oldLength = s.length; + + // Update offset objects referring to oldStartNode + for ( j = start - subtracted; j < start; j++ ) { + if ( j in context.offsets ) { + o = context.offsets[j]; + o.node = oldStartNode; + o.length = subtracted; + } + } + // Update offset objects referring to newStartNode + 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; + } } } - // We have to insert this one, as it might not exist: we didn't call getOffset( end ) - context.offsets[end] = { - 'node': newEndNode, - 'offset': 0, - 'length': oldLength - subtracted, - 'lastTextNode': oldEndNode - }; - // Update offset objects referring to newEndNode - for ( j = end + 1; 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; + var end = markers[i].end; + // To avoid ending up at the first char of the next node, we grab the offset for end - 1 and add one to the + // offset + var e = context.fn.getOffset( end - 1 ); + if ( !e ) { + // This shouldn't happen + continue; + } + var endNode = e.node; + if ( e.offset + 1 < e.length - 1 && endNode.nodeName == '#text' ) { + // Split off the suffix. This puts the suffix in a new node and leaves the rest in endNode + var oldEndNode = endNode; + var newEndNode = endNode.splitText( e.offset + 1 ); + // Update offset objects + subtracted = e.offset + 1; + oldLength = e.length; + + // Update offset objects referring to oldEndNode + for ( j = end - subtracted; j < end; j++ ) { + if ( j in context.offsets ) { + o = context.offsets[j]; + o.node = oldEndNode; + o.length = subtracted; + } + } + // We have to insert this one, as it might not exist: we didn't call getOffset( end ) + context.offsets[end] = { + 'node': newEndNode, + 'offset': 0, + 'length': oldLength - subtracted, + 'lastTextNode': oldEndNode + }; + // Update offset objects referring to newEndNode + for ( j = end + 1; 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; + } } } - } - // Don't wrap trailing BRs, doing that causes weird issues - if ( endNode.nodeName == 'BR' ) { - endNode = e.lastTextNode; - } - // If startNode and endNode have different parents, we need to pull endNode and all textnodes in between - // into startNode's parent and replace

with
- 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 has a different parent, merge t.node.parentNode with startNode.parentNode - if ( t.node.parentNode != startNode.parentNode ) { - var oldParent = t.node.parentNode; - if ( afterStart ) { - if ( lastP != t.inP ) { - // We're entering a new

, insert a
- startNode.parentNode.insertBefore( - startNode.ownerDocument.createElement( 'br' ), - afterStart - ); - } - // A

with just a
in it is an empty line, so let's not bother with unwrapping it - if ( !( oldParent.childNodes.length == 1 && oldParent.firstChild.nodeName == 'BR' ) ) { - // Move all children of oldParent into startNode's parent - while ( oldParent.firstChild ) { - startNode.parentNode.insertBefore( oldParent.firstChild, afterStart ); + // Don't wrap trailing BRs, doing that causes weird issues + if ( endNode.nodeName == 'BR' ) { + endNode = e.lastTextNode; + } + // If startNode and endNode have different parents, we need to pull endNode and all textnodes in between + // into startNode's parent and replace

with
+ 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 has a different parent, merge t.node.parentNode with startNode.parentNode + if ( t.node.parentNode !== startNode.parentNode ) { + var oldParent = t.node.parentNode; + if ( afterStart ) { + if ( lastP !== t.inP ) { + // We're entering a new

, insert a
+ startNode.parentNode.insertBefore( + startNode.ownerDocument.createElement( 'br' ), + afterStart + ); } - } - } else { - if ( lastP != t.inP ) { - // We're entering a new

, insert a
- startNode.parentNode.appendChild( - startNode.ownerDocument.createElement( 'br' ) - ); - } - // A

with just a
in it is an empty line, so let's not bother with unwrapping it - if ( !( oldParent.childNodes.length == 1 && oldParent.firstChild.nodeName == 'BR' ) ) { - // Move all children of oldParent into startNode's parent - while ( oldParent.firstChild ) { - startNode.parentNode.appendChild( oldParent.firstChild ); + // A

with just a
in it is an empty line, so let's not bother with unwrapping it + if ( !( oldParent.childNodes.length == 1 && oldParent.firstChild.nodeName == 'BR' ) ) { + // Move all children of oldParent into startNode's parent + while ( oldParent.firstChild ) { + startNode.parentNode.insertBefore( oldParent.firstChild, afterStart ); + } + } + } else { + if ( lastP !== t.inP ) { + // We're entering a new

, insert a
+ startNode.parentNode.appendChild( + startNode.ownerDocument.createElement( 'br' ) + ); + } + // A

with just a
in it is an empty line, so let's not bother with unwrapping it + if ( !( oldParent.childNodes.length == 1 && oldParent.firstChild.nodeName == 'BR' ) ) { + // Move all children of oldParent into startNode's parent + while ( oldParent.firstChild ) { + startNode.parentNode.appendChild( oldParent.firstChild ); + } } } + // Remove oldParent, which is now empty + oldParent.parentNode.removeChild( oldParent ); } - // Remove oldParent, which is now empty - oldParent.parentNode.removeChild( oldParent ); + lastP = t.inP; } - lastP = t.inP; + // Moving nodes around like this invalidates offset objects + // TODO: Update offset objects ourselves for performance. Requires rewriting this code block to be + // offset-based rather than traverser-based } - // Moving nodes around like this invalidates offset objects - // TODO: Update offset objects ourselves for performance. Requires rewriting this code block to be - // offset-based rather than traverser-based - } - // Now wrap everything between startNode and endNode (may be equal). - 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') { - // We have to store things like .parentNode and .nextSibling because appendChild() changes these - var newNode = ca1.ownerDocument.createElement( 'span' ); - var nextNode = ca2.nextSibling; - // Append all nodes between ca1 and ca2 (inclusive) to newNode - var n = ca1; - while ( n != nextNode ) { - var ns = n.nextSibling; - newNode.appendChild( n ); - n = ns; - } - // Insert newNode in the right place - if ( nextNode ) { - commonAncestor.insertBefore( newNode, nextNode ); - } else { - commonAncestor.appendChild( newNode ); + // Now wrap everything between startNode and endNode (may be equal). + 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') { + // We have to store things like .parentNode and .nextSibling because appendChild() changes these + var newNode = ca1.ownerDocument.createElement( 'span' ); + var nextNode = ca2.nextSibling; + // Append all nodes between ca1 and ca2 (inclusive) to newNode + var n = ca1; + while ( n !== nextNode ) { + var ns = n.nextSibling; + newNode.appendChild( n ); + n = ns; + } + // Insert newNode in the right place + if ( nextNode ) { + commonAncestor.insertBefore( newNode, nextNode ); + } else { + commonAncestor.appendChild( newNode ); + } + anchor = newNode; + } else if ( markers[i].anchor == 'tag' ) { + anchor = commonAncestor; } - anchor = newNode; - } else if ( markers[i].anchor == 'tag' ) { - anchor = commonAncestor; - } - $( anchor ).data( 'marker', markers[i] ).addClass( 'wikiEditor-highlight' ); - // Allow the module adding this marker to manipulate it - markers[i].afterWrap( anchor, markers[i] ); + $( anchor ).data( 'marker', markers[i] ).addClass( 'wikiEditor-highlight' ); + // Allow the module adding this marker to manipulate it + markers[i].afterWrap( anchor, markers[i] ); - } else { - // Update the marker object - $( anchor ).data( 'marker', markers[i] ); - if ( typeof markers[i].onSkip == 'function' ) { - markers[i].onSkip( anchor ); + } else { + // Update the marker object + $( anchor ).data( 'marker', markers[i] ); + if ( typeof markers[i].onSkip == 'function' ) { + markers[i].onSkip( anchor ); + } } + visited[v++] = anchor; } - visited[v++] = anchor; - } - } - // Remove markers that were previously inserted but weren't passed to this function - visited[] contains the - // visited elements in order and find() and each() preserve order - var j = 0; - context.$content.find( '.wikiEditor-highlight' ).each( function() { - if ( visited[j] == this ) { - // This marker is legit, leave it in - j++; - return true; } - // Remove this marker - var marker = $(this).data( 'marker' ); - if ( marker && typeof marker.skipDivision != 'undefined' && ( division == marker.skipDivision ) ) { - // Don't remove these either - return true; - } - if ( marker && typeof marker.beforeUnwrap == 'function' ) - marker.beforeUnwrap( this ); - if ( ( marker && marker.anchor == 'tag' ) || $(this).is( 'p' ) ) { - // Remove all classes - $(this).removeAttr( 'class' ); - } else { - // Assume anchor == 'wrap' - $(this).replaceWith( this.childNodes ); - } - context.fn.purgeOffsets(); - }); + // Remove markers that were previously inserted but weren't passed to this function - visited[] contains the + // visited elements in order and find() and each() preserve order + j = 0; + context.$content.find( '.wikiEditor-highlight' ).each( function () { + if ( visited[j] == this ) { + // This marker is legit, leave it in + j++; + return true; + } + // Remove this marker + var marker = $(this).data( 'marker' ); + if ( marker && typeof marker.skipDivision !== 'undefined' && ( division === marker.skipDivision ) ) { + // Don't remove these either + return true; + } + if ( marker && typeof marker.beforeUnwrap === 'function' ) + marker.beforeUnwrap( this ); + if ( ( marker && marker.anchor === 'tag' ) || $(this).is( 'p' ) ) { + // Remove all classes + $(this).removeAttr( 'class' ); + } else { + // Assume anchor == 'wrap' + $(this).replaceWith( this.childNodes ); + } + context.fn.purgeOffsets(); + }); + } } -} +}; -}; })( jQuery ); +}( jQuery ) ); -- cgit v1.2.3-54-g00ecf