NOBUG: Fixed file access permissions
[moodle.git] / lib / yuilib / 3.13.0 / highlight-base / highlight-base-debug.js
blob041f40558120fda74d91aecaa6860a27f517ccf2
1 /*
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/
6 */
8 YUI.add('highlight-base', function (Y, NAME) {
10 /**
11 Provides methods for highlighting strings within other strings by wrapping
12 them in HTML.
14 @module highlight
15 @submodule highlight-base
16 @main
17 @since 3.3.0
18 **/
20 /**
21 Provides methods for highlighting strings within other strings by wrapping
22 them in HTML.
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.
30 @class Highlight
31 @static
32 **/
34 var YArray    = Y.Array,
35     Escape    = Y.Escape,
36     WordBreak = Y.Text.WordBreak,
38     isArray = Y.Lang.isArray,
40     EMPTY_OBJECT = {},
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]*)?',
48 Highlight = {
49     // -- Protected Static Properties ------------------------------------------
51     /**
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. "&amp" without a ";" at the
59          end).
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.
65     @property _REGEX
66     @type String
67     @protected
68     @static
69     @final
70     **/
71     _REGEX: UNCLOSED_ENTITY + '(%needles)',
73     /**
74     Regex replacer function or string for normal matches.
76     @property _REPLACER
77     @type Function|String
78     @protected
79     @static
80     @final
81     **/
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);
88      },
90     /**
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
100     @type String
101     @protected
102     @static
103     @final
104      */
105     _START_REGEX: '^' + UNCLOSED_ENTITY + '(%needles)',
107     /**
108     Highlight template which will be used as a replacement for matched
109     substrings. The placeholder `{s}` will be replaced with the matched
110     substring.
112     @property _TEMPLATE
113     @type String
114     @default '<b class="yui3-highlight">{s}</b>'
115     @protected
116     @static
117     @final
118     **/
119     _TEMPLATE: '<b class="' + Y.ClassNameManager.getClassName('highlight') + '">{s}</b>',
121     // -- Public Static Methods ------------------------------------------------
123     /**
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.
128     @method all
129     @param {String} haystack String to apply highlighting to.
130     @param {String|String[]} needles String or array of strings that should be
131         highlighted.
132     @param {Object} [options] Options object.
133     @param {Boolean} [options.caseSensitive=false] If `true`, matching will
134         be case-sensitive.
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_.
138     @static
139     **/
140     all: function (haystack, needles, options) {
141         var validNeedles = [],
142             esc, i, len, needle, regex, replacer;
144         if (!options) {
145             options = EMPTY_OBJECT;
146         }
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
156         // escaped haystack.
157         for (i = 0, len = needles.length; i < len; ++i) {
158             needle = needles[i];
160             if (needle) {
161                 validNeedles.push(Escape.regex(esc ? Escape.html(needle) : needle));
162             }
163         }
165         // Escape HTML characters in the haystack to prevent HTML injection.
166         if (esc) {
167             haystack = Escape.html(haystack);
168         }
170         // No point continuing if there are no needles.
171         if (!validNeedles.length) {
172             return haystack;
173         }
175         return haystack.replace(
176             new RegExp(
177                 regex.replace('%needles', validNeedles.join('|')),
178                 options.caseSensitive ? 'g' : 'gi'
179             ),
180             replacer
181         );
182     },
184     /**
185     Same as `all()`, but case-sensitive by default.
187     @method allCase
188     @param {String} haystack String to apply highlighting to.
189     @param {String|String[]} needles String or array of strings that should be
190       highlighted.
191     @param {Object} [options] Options object. See `all()` for details.
192     @return {String} Escaped and highlighted copy of _haystack_.
193     @static
194     **/
195     allCase: function (haystack, needles, options) {
196         return Highlight.all(haystack, needles,
197                 Y.merge(options || EMPTY_OBJECT, {caseSensitive: true}));
198     },
200     /**
201     Highlights _needles_ that occur at the start of _haystack_. The returned
202     string will have all HTML characters escaped except for the highlighting
203     markup.
205     @method start
206     @param {String} haystack String to apply highlighting to.
207     @param {String|String[]} needles String or array of strings that should be
208       highlighted.
209     @param {Object} [options] Options object.
210     @param {Boolean} [options.caseSensitive=false] If `true`, matching will
211         be case-sensitive.
212     @return {String} Escaped and highlighted copy of _haystack_.
213     @static
214     **/
215     start: function (haystack, needles, options) {
216         return Highlight.all(haystack, needles,
217                 Y.merge(options || EMPTY_OBJECT, {startsWith: true}));
218     },
220     /**
221     Same as `start()`, but case-sensitive by default.
223     @method startCase
224     @param {String} haystack String to apply highlighting to.
225     @param {String|String[]} needles String or array of strings that should be
226       highlighted.
227     @return {String} Escaped and highlighted copy of _haystack_.
228     @static
229     **/
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});
235     },
237     /**
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.
242     @method words
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
247       split.
248     @param {Object} [options] Options object.
249     @param {Boolean} [options.caseSensitive=false] If `true`, matching will
250         be case-sensitive.
251     @return {String} Escaped and highlighted copy of _haystack_.
252     @static
253     **/
254     words: function (haystack, needles, options) {
255         var caseSensitive,
256             mapper,
257             template = Highlight._TEMPLATE,
258             words;
260         if (!options) {
261             options = EMPTY_OBJECT;
262         }
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
270             })
271         );
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));
279             }
281             return Escape.html(word);
282         };
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
289         });
291         return YArray.map(words, function (word) {
292             return mapper(word, needles);
293         }).join('');
294     },
296     /**
297     Same as `words()`, but case-sensitive by default.
299     @method wordsCase
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
304       split.
305     @return {String} Escaped and highlighted copy of _haystack_.
306     @static
307     **/
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});
313     }
316 Y.Highlight = Highlight;
319 }, '3.13.0', {"requires": ["array-extras", "classnamemanager", "escape", "text-wordbreak"]});