2 YUI 3.13.0 (build 508226d)
3 Copyright 2013 Yahoo! Inc. All rights reserved.
4 Licensed under the BSD License.
5 http://yuilibrary.com/license/
8 YUI.add('highlight-base', function (Y, NAME) {
11 Provides methods for highlighting strings within other strings by wrapping
15 @submodule highlight-base
21 Provides methods for highlighting strings within other strings by wrapping
24 The highlight methods first escape any special HTML characters in the input
25 strings and then highlight the appropriate substrings by wrapping them in a
26 `<b class="yui3-highlight"></b>` element. The `<b>` element is used rather than
27 `<strong>` in accordance with HTML5's definition of `<b>` as being purely
28 presentational, which is exactly what highlighting is.
36 WordBreak = Y.Text.WordBreak,
38 isArray = Y.Lang.isArray,
42 // Regex string that captures zero or one unclosed HTML entities. Used in
43 // the static regex template properties below. The entity matching is
44 // intentionally loose here, since there's a world of complexity involved in
45 // doing strict matching for this use case.
46 UNCLOSED_ENTITY = '(&[^;\\s]*)?',
49 // -- Protected Static Properties ------------------------------------------
52 Regular expression template for highlighting a match that occurs anywhere
53 in a string. The placeholder `%needles` will be replaced with a list of
54 needles to match, joined by `|` characters.
56 This regex should have two capturing subpatterns:
58 1. Zero or one unclosed HTML entity (e.g. "&" without a ";" at the
60 2. The `%needles` placeholder.
62 The first subpattern match is used to emulate a negative lookbehind
63 assertion in order to prevent highlighting inside HTML entities.
71 _REGEX: UNCLOSED_ENTITY + '(%needles)',
74 Regex replacer function or string for normal matches.
82 _REPLACER: function (match, p1, p2) {
83 // Mimicking a negative lookbehind assertion to prevent matches inside
84 // HTML entities. Hat tip to Steven Levithan for the technique:
85 // http://blog.stevenlevithan.com/archives/mimic-lookbehind-javascript
86 return p1 && !(/\s/).test(p2) ? match :
87 Highlight._TEMPLATE.replace(/\{s\}/g, p2);
91 Regular expression template for highlighting start-of-string matches
92 (i.e., only matches that occur at the beginning of a string). The
93 placeholder `%needles` will be replaced with a list of needles to match,
94 joined by `|` characters.
96 See `_REGEX` for a description of the capturing subpatterns this regex
97 string should contain.
99 @property _START_REGEX
105 _START_REGEX: '^' + UNCLOSED_ENTITY + '(%needles)',
108 Highlight template which will be used as a replacement for matched
109 substrings. The placeholder `{s}` will be replaced with the matched
114 @default '<b class="yui3-highlight">{s}</b>'
119 _TEMPLATE: '<b class="' + Y.ClassNameManager.getClassName('highlight') + '">{s}</b>',
121 // -- Public Static Methods ------------------------------------------------
124 Highlights all occurrences in the _haystack_ string of the items in the
125 _needles_ array, regardless of where they occur. The returned string will
126 have all HTML characters escaped except for the highlighting markup.
129 @param {String} haystack String to apply highlighting to.
130 @param {String|String[]} needles String or array of strings that should be
132 @param {Object} [options] Options object.
133 @param {Boolean} [options.caseSensitive=false] If `true`, matching will
135 @param {Boolean} [options.startsWith=false] If `true`, matches must be
136 anchored to the beginning of the string.
137 @return {String} Escaped and highlighted copy of _haystack_.
140 all: function (haystack, needles, options) {
141 var validNeedles = [],
142 esc, i, len, needle, regex, replacer;
145 options = EMPTY_OBJECT;
148 // TODO: document options.replacer
149 esc = options.escapeHTML !== false;
150 regex = options.startsWith ? Highlight._START_REGEX : Highlight._REGEX;
151 replacer = options.replacer || Highlight._REPLACER;
152 needles = isArray(needles) ? needles : [needles];
154 // Escape HTML characters and special regular expression characters in
155 // the needles so they can be used in a regex and matched against the
157 for (i = 0, len = needles.length; i < len; ++i) {
161 validNeedles.push(Escape.regex(esc ? Escape.html(needle) : needle));
165 // Escape HTML characters in the haystack to prevent HTML injection.
167 haystack = Escape.html(haystack);
170 // No point continuing if there are no needles.
171 if (!validNeedles.length) {
175 return haystack.replace(
177 regex.replace('%needles', validNeedles.join('|')),
178 options.caseSensitive ? 'g' : 'gi'
185 Same as `all()`, but case-sensitive by default.
188 @param {String} haystack String to apply highlighting to.
189 @param {String|String[]} needles String or array of strings that should be
191 @param {Object} [options] Options object. See `all()` for details.
192 @return {String} Escaped and highlighted copy of _haystack_.
195 allCase: function (haystack, needles, options) {
196 return Highlight.all(haystack, needles,
197 Y.merge(options || EMPTY_OBJECT, {caseSensitive: true}));
201 Highlights _needles_ that occur at the start of _haystack_. The returned
202 string will have all HTML characters escaped except for the highlighting
206 @param {String} haystack String to apply highlighting to.
207 @param {String|String[]} needles String or array of strings that should be
209 @param {Object} [options] Options object.
210 @param {Boolean} [options.caseSensitive=false] If `true`, matching will
212 @return {String} Escaped and highlighted copy of _haystack_.
215 start: function (haystack, needles, options) {
216 return Highlight.all(haystack, needles,
217 Y.merge(options || EMPTY_OBJECT, {startsWith: true}));
221 Same as `start()`, but case-sensitive by default.
224 @param {String} haystack String to apply highlighting to.
225 @param {String|String[]} needles String or array of strings that should be
227 @return {String} Escaped and highlighted copy of _haystack_.
230 startCase: function (haystack, needles) {
231 // No options passthru for now, since it would be redundant. If start()
232 // ever supports more options than caseSensitive, then we'll start
233 // passing the options through.
234 return Highlight.start(haystack, needles, {caseSensitive: true});
238 Highlights complete words in the _haystack_ string that are also in the
239 _needles_ array. The returned string will have all HTML characters escaped
240 except for the highlighting markup.
243 @param {String} haystack String to apply highlighting to.
244 @param {String|String[]} needles String or array of strings containing words
245 that should be highlighted. If a string is passed, it will be split
246 into words; if an array is passed, it is assumed to have already been
248 @param {Object} [options] Options object.
249 @param {Boolean} [options.caseSensitive=false] If `true`, matching will
251 @return {String} Escaped and highlighted copy of _haystack_.
254 words: function (haystack, needles, options) {
257 template = Highlight._TEMPLATE,
261 options = EMPTY_OBJECT;
264 caseSensitive = !!options.caseSensitive;
266 // Convert needles to a hash for faster lookups.
267 needles = YArray.hash(
268 isArray(needles) ? needles : WordBreak.getUniqueWords(needles, {
269 ignoreCase: !caseSensitive
273 // The default word mapping function can be overridden with a custom
274 // one. This is used to implement accent-folded highlighting in the
275 // highlight-accentfold module.
276 mapper = options.mapper || function (word, needles) {
277 if (needles.hasOwnProperty(caseSensitive ? word : word.toLowerCase())) {
278 return template.replace(/\{s\}/g, Escape.html(word));
281 return Escape.html(word);
284 // Split the haystack into an array of words, including punctuation and
285 // whitespace so we can rebuild the string later.
286 words = WordBreak.getWords(haystack, {
287 includePunctuation: true,
288 includeWhitespace : true
291 return YArray.map(words, function (word) {
292 return mapper(word, needles);
297 Same as `words()`, but case-sensitive by default.
300 @param {String} haystack String to apply highlighting to.
301 @param {String|String[]} needles String or array of strings containing words
302 that should be highlighted. If a string is passed, it will be split
303 into words; if an array is passed, it is assumed to have already been
305 @return {String} Escaped and highlighted copy of _haystack_.
308 wordsCase: function (haystack, needles) {
309 // No options passthru for now, since it would be redundant. If words()
310 // ever supports more options than caseSensitive, then we'll start
311 // passing the options through.
312 return Highlight.words(haystack, needles, {caseSensitive: true});
316 Y.Highlight = Highlight;
319 }, '3.13.0', {"requires": ["array-extras", "classnamemanager", "escape", "text-wordbreak"]});