wiki.techinc.nl/resources/jquery/jquery.highlightText.js
Timo Tijhof 089c58d232 jshint: resources/jquery/*
* .jshintrc: Updated to include more strict options that match
  our code conventions.
  Also separated into 3 groups:
  - stricter (curly, eqeqeq etc.)
  - laxer (smarttabs, laxbreak)
  - envrionment (browser)

* .jshintignore: Updated to include more third-party/upstream files
   that should not be linted.

* Most of it is just routine cleanup, a few notable points:

 - jquery.autoEllipsis: Removed unused variable $protectedText.

 - jquery.arrowSteps.js: Remove <!-- --> and language="javascript"
   that hasn't been needed for almost a decade.

 - jquery.byteLimit: Use dashToCamel key for .data(), this already
   happens internally in jQuery data(), since data storage should use
   keys that are usable as identifiers. The dashed versions are to
   populate these from data-attribute-names, which then becomes
   data.attributeNames. jQuery data() takes both forms as
   convenience.

 - jquery.client.js: To avoid a rewrite of it, allowing unexpected
   assignments (boss) and eval (evil) in the functions that use that.
   Left as it is for now, could use a rewrite later.

 - jquery.color.js: Tolerate unexpected assignment for now (boss).
   Left as it is for now, should perhaps be refactored later.
   Also re-ordered per jshint/jslint to put definition before
   invocation. This option can be disabled, but then it doesn't
   warn for invoking undefined functions (or typos) at all.

 - jquery.expandableField.js: Remove empty switch/case.

 - jquery.localize.js: Alias mw global.

 - jquery.suggestions.js: Use e.which; jQuery.Event normalizes
   e.keyCode etc.

 - jquery.tablesorter.js: Alias mw global.

 - jquery.textSelection.js: Fix leakage of variable in global scope
   of var "i" and "j".

 - mediawiki.util.test.js: Fixed implied global `pCustom`.

* Review with -w for your own sanity.

Change-Id: Ia972f79539a96a38357ec4e92b0b6e38cc301681
2012-07-15 11:13:20 -04:00

67 lines
2.7 KiB
JavaScript

/**
* Plugin that highlights matched word partials in a given element.
* TODO: Add a function for restoring the previous text.
* TODO: Accept mappings for converting shortcuts like WP: to Wikipedia:.
*/
( function ( $ ) {
$.highlightText = {
// Split our pattern string at spaces and run our highlight function on the results
splitAndHighlight: function ( node, pat ) {
var patArray = pat.split( ' ' );
for ( var i = 0; i < patArray.length; i++ ) {
if ( patArray[i].length === 0 ) {
continue;
}
$.highlightText.innerHighlight( node, patArray[i] );
}
return node;
},
// scans a node looking for the pattern and wraps a span around each match
innerHighlight: function ( node, pat ) {
// if this is a text node
if ( node.nodeType === 3 ) {
// TODO - need to be smarter about the character matching here.
// non latin characters can make regex think a new word has begun: do not use \b
// http://stackoverflow.com/questions/3787072/regex-wordwrap-with-utf8-characters-in-js
// look for an occurrence of our pattern and store the starting position
var match = node.data.match( new RegExp( "(^|\\s)" + $.escapeRE( pat ), "i" ) );
if ( match ) {
var pos = match.index + match[1].length; // include length of any matched spaces
// create the span wrapper for the matched text
var spannode = document.createElement( 'span' );
spannode.className = 'highlight';
// shave off the characters preceding the matched text
var middlebit = node.splitText( pos );
// shave off any unmatched text off the end
middlebit.splitText( pat.length );
// clone for appending to our span
var middleclone = middlebit.cloneNode( true );
// append the matched text node to the span
spannode.appendChild( middleclone );
// replace the matched node, with our span-wrapped clone of the matched node
middlebit.parentNode.replaceChild( spannode, middlebit );
}
// if this is an element with childnodes, and not a script, style or an element we created
} else if ( node.nodeType === 1 && node.childNodes && !/(script|style)/i.test( node.tagName )
&& !( node.tagName.toLowerCase() === 'span' && node.className.match( /\bhighlight/ ) ) ) {
for ( var i = 0; i < node.childNodes.length; ++i ) {
// call the highlight function for each child node
$.highlightText.innerHighlight( node.childNodes[i], pat );
}
}
}
};
$.fn.highlightText = function ( matchString ) {
return $( this ).each( function () {
var $el = $( this );
$el.data( 'highlightText', { originalText: $el.text() } );
$.highlightText.splitAndHighlight( this, matchString );
} );
};
}( jQuery ) );