mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/WikiEditor
synced 2024-11-12 09:57:16 +00:00
Merge "WikiEditor: Remove unmaintained highlight plugin"
This commit is contained in:
commit
e3668e18aa
|
@ -127,13 +127,6 @@ $wgResourceModules += array(
|
|||
'wikieditor-toolbar-tool-file-cancel',
|
||||
),
|
||||
),
|
||||
'jquery.wikiEditor.highlight' => $wikiEditorTpl + array(
|
||||
'scripts' => 'jquery.wikiEditor.highlight.js',
|
||||
'dependencies' => array(
|
||||
'jquery.wikiEditor',
|
||||
'jquery.wikiEditor.iframe',
|
||||
),
|
||||
),
|
||||
'jquery.wikiEditor.preview' => $wikiEditorTpl + array(
|
||||
'scripts' => 'jquery.wikiEditor.preview.js',
|
||||
'styles' => 'jquery.wikiEditor.preview.css',
|
||||
|
@ -392,13 +385,6 @@ $wgResourceModules += array(
|
|||
'jquery.wikiEditor.dialogs.config',
|
||||
),
|
||||
),
|
||||
'ext.wikiEditor.highlight' => $wikiEditorTpl + array(
|
||||
'scripts' => 'ext.wikiEditor.highlight.js',
|
||||
'dependencies' => array(
|
||||
'ext.wikiEditor',
|
||||
'jquery.wikiEditor.highlight',
|
||||
),
|
||||
),
|
||||
'ext.wikiEditor.preview' => $wikiEditorTpl + array(
|
||||
'scripts' => 'ext.wikiEditor.preview.js',
|
||||
'dependencies' => array(
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
/*
|
||||
* JavaScript for WikiEditor Highlighting
|
||||
*/
|
||||
jQuery( document ).ready( function ( $ ) {
|
||||
// Add highlight module
|
||||
$( '#wpTextbox1' ).wikiEditor( 'addModule', 'highlight' );
|
||||
} );
|
|
@ -1,388 +0,0 @@
|
|||
/* Highlight module for wikiEditor */
|
||||
|
||||
( function ( $ ) {
|
||||
|
||||
$.wikiEditor.modules.highlight = {
|
||||
|
||||
/**
|
||||
* Core Requirements
|
||||
*/
|
||||
req: [ 'iframe' ],
|
||||
|
||||
/**
|
||||
* Configuration
|
||||
*/
|
||||
cfg: {
|
||||
styleVersion: 3
|
||||
},
|
||||
|
||||
/**
|
||||
* Internally used event handlers
|
||||
*/
|
||||
evt: {
|
||||
/**
|
||||
* @param context
|
||||
* @param event
|
||||
*/
|
||||
delayedChange: function ( context, event ) {
|
||||
if ( event.data.scope === 'realchange' ) {
|
||||
$.wikiEditor.modules.highlight.fn.scan( context );
|
||||
$.wikiEditor.modules.highlight.fn.mark( context, event.data.scope );
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @param context
|
||||
* @param event
|
||||
*/
|
||||
ready: function ( context ) {
|
||||
$.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 context
|
||||
* @param config Configuration object to create module from
|
||||
*/
|
||||
create: function ( context ) {
|
||||
context.modules.highlight.markersStr = '';
|
||||
},
|
||||
/**
|
||||
* Scans text division for tokens
|
||||
*
|
||||
* @param context
|
||||
* @param division
|
||||
*/
|
||||
scan: function ( context ) {
|
||||
var tokenArray, text, module, exp,
|
||||
left, right, match,
|
||||
regex, label, markAfter, offset;
|
||||
/*jshint eqnull: true */
|
||||
|
||||
// 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
|
||||
regex = $.wikiEditor.modules[module].exp[exp].regex;
|
||||
label = $.wikiEditor.modules[module].exp[exp].label;
|
||||
markAfter = $.wikiEditor.modules[module].exp[exp].markAfter || false;
|
||||
// Search for tokens
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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 context
|
||||
* @param division
|
||||
* @param tokens
|
||||
*/
|
||||
// FIXME: What do division and tokens do?
|
||||
// TODO: Document the scan() and mark() APIs somewhere
|
||||
mark: function ( context, division ) {
|
||||
/*jshint eqeqeq:false, onevar:false */
|
||||
var i, subtracted, oldLength, j, o,
|
||||
markers;
|
||||
|
||||
// Reset markers
|
||||
markers = [];
|
||||
|
||||
// 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;
|
||||
|
||||
// Get all markers
|
||||
context.fn.trigger( 'mark' );
|
||||
markers.sort( function ( a, b ) {
|
||||
return a.start - b.start || a.end - b.end;
|
||||
} );
|
||||
|
||||
// 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;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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 </p><p> with <br>
|
||||
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 <p>, insert a <br>
|
||||
startNode.parentNode.insertBefore(
|
||||
startNode.ownerDocument.createElement( 'br' ),
|
||||
afterStart
|
||||
);
|
||||
}
|
||||
// A <p> with just a <br> 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 <p>, insert a <br>
|
||||
startNode.parentNode.appendChild(
|
||||
startNode.ownerDocument.createElement( 'br' )
|
||||
);
|
||||
}
|
||||
// A <p> with just a <br> 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 );
|
||||
}
|
||||
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
|
||||
}
|
||||
// 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 ).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 );
|
||||
}
|
||||
}
|
||||
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
|
||||
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 ) );
|
||||
|
|
@ -11,7 +11,6 @@ class WikiEditorSeleniumConfig {
|
|||
'wgDefaultSkin' => 'vector',
|
||||
'wgWikiEditorFeatures' => array(
|
||||
'toolbar' => array( 'global' => true, 'user' => true ),
|
||||
'highlight' => array( 'global' => false, 'user' => false ),
|
||||
'dialogs' => array( 'global' => true, 'user' => true )
|
||||
),
|
||||
'wgVectorFeatures' => array(
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
* $wgDefaultSkin = 'vector';
|
||||
* $wgVectorFeatures['editwarning'] = array( 'global' => false, 'user' => false );
|
||||
* $wgWikiEditorFeatures['toolbar'] = array( 'global' => true, 'user' => true );
|
||||
* $wgWikiEditorFeatures['highlight'] = array( 'global' => false, 'user' => false );
|
||||
* $wgWikiEditorFeatures['dialogs'] = array( 'global' => true, 'user' => true );
|
||||
*
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue