~smagoun/whoopsie/whoopsie-lp1017637

« back to all changes in this revision

Viewing changes to backend/stats/static/js/yui/build/highlight-base/highlight-base.js

  • Committer: Evan Dandrea
  • Date: 2012-05-09 05:53:45 UTC
  • Revision ID: evan.dandrea@canonical.com-20120509055345-z2j41tmcbf4as5uf
The backend now lives in lp:daisy and the website (errors.ubuntu.com) now lives in lp:errors.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
YUI 3.5.0 (build 5089)
3
 
Copyright 2012 Yahoo! Inc. All rights reserved.
4
 
Licensed under the BSD License.
5
 
http://yuilibrary.com/license/
6
 
*/
7
 
YUI.add('highlight-base', function(Y) {
8
 
 
9
 
/**
10
 
Provides methods for highlighting strings within other strings by wrapping
11
 
them in HTML.
12
 
 
13
 
@module highlight
14
 
@submodule highlight-base
15
 
@main
16
 
@since 3.3.0
17
 
**/
18
 
 
19
 
/**
20
 
Provides methods for highlighting strings within other strings by wrapping
21
 
them in HTML.
22
 
 
23
 
The highlight methods first escape any special HTML characters in the input
24
 
strings and then highlight the appropriate substrings by wrapping them in a
25
 
`<b class="yui3-highlight"></b>` element. The `<b>` element is used rather than
26
 
`<strong>` in accordance with HTML5's definition of `<b>` as being purely
27
 
presentational, which is exactly what highlighting is.
28
 
 
29
 
@class Highlight
30
 
@static
31
 
**/
32
 
 
33
 
var YArray    = Y.Array,
34
 
    Escape    = Y.Escape,
35
 
    WordBreak = Y.Text.WordBreak,
36
 
 
37
 
    isArray = Y.Lang.isArray,
38
 
 
39
 
    EMPTY_OBJECT = {},
40
 
 
41
 
    // Regex string that captures zero or one unclosed HTML entities. Used in
42
 
    // the static regex template properties below. The entity matching is
43
 
    // intentionally loose here, since there's a world of complexity involved in
44
 
    // doing strict matching for this use case.
45
 
    UNCLOSED_ENTITY = '(&[^;\\s]*)?',
46
 
 
47
 
Highlight = {
48
 
    // -- Protected Static Properties ------------------------------------------
49
 
 
50
 
    /**
51
 
    Regular expression template for highlighting a match that occurs anywhere
52
 
    in a string. The placeholder `%needles` will be replaced with a list of
53
 
    needles to match, joined by `|` characters.
54
 
 
55
 
    This regex should have two capturing subpatterns:
56
 
 
57
 
      1. Zero or one unclosed HTML entity (e.g. "&amp" without a ";" at the
58
 
         end).
59
 
      2. The `%needles` placeholder.
60
 
 
61
 
    The first subpattern match is used to emulate a negative lookbehind
62
 
    assertion in order to prevent highlighting inside HTML entities.
63
 
 
64
 
    @property _REGEX
65
 
    @type String
66
 
    @protected
67
 
    @static
68
 
    @final
69
 
    **/
70
 
    _REGEX: UNCLOSED_ENTITY + '(%needles)',
71
 
 
72
 
    /**
73
 
    Regex replacer function or string for normal matches.
74
 
 
75
 
    @property _REPLACER
76
 
    @type Function|String
77
 
    @protected
78
 
    @static
79
 
    @final
80
 
    **/
81
 
    _REPLACER: function (match, p1, p2) {
82
 
         // Mimicking a negative lookbehind assertion to prevent matches inside
83
 
         // HTML entities. Hat tip to Steven Levithan for the technique:
84
 
         // http://blog.stevenlevithan.com/archives/mimic-lookbehind-javascript
85
 
         return p1 && !(/\s/).test(p2) ? match :
86
 
                    Highlight._TEMPLATE.replace(/\{s\}/g, p2);
87
 
     },
88
 
 
89
 
    /**
90
 
    Regular expression template for highlighting start-of-string matches
91
 
    (i.e., only matches that occur at the beginning of a string). The
92
 
    placeholder `%needles` will be replaced with a list of needles to match,
93
 
    joined by `|` characters.
94
 
 
95
 
    See `_REGEX` for a description of the capturing subpatterns this regex
96
 
    string should contain.
97
 
 
98
 
    @property _START_REGEX
99
 
    @type String
100
 
    @protected
101
 
    @static
102
 
    @final
103
 
     */
104
 
    _START_REGEX: '^' + UNCLOSED_ENTITY + '(%needles)',
105
 
 
106
 
    /**
107
 
    Highlight template which will be used as a replacement for matched
108
 
    substrings. The placeholder `{s}` will be replaced with the matched
109
 
    substring.
110
 
 
111
 
    @property _TEMPLATE
112
 
    @type String
113
 
    @default '<b class="yui3-highlight">{s}</b>'
114
 
    @protected
115
 
    @static
116
 
    @final
117
 
    **/
118
 
    _TEMPLATE: '<b class="' + Y.ClassNameManager.getClassName('highlight') + '">{s}</b>',
119
 
 
120
 
    // -- Public Static Methods ------------------------------------------------
121
 
 
122
 
    /**
123
 
    Highlights all occurrences in the _haystack_ string of the items in the
124
 
    _needles_ array, regardless of where they occur. The returned string will
125
 
    have all HTML characters escaped except for the highlighting markup.
126
 
 
127
 
    @method all
128
 
    @param {String} haystack String to apply highlighting to.
129
 
    @param {String|String[]} needles String or array of strings that should be
130
 
        highlighted.
131
 
    @param {Object} [options] Options object.
132
 
    @param {Boolean} [options.caseSensitive=false] If `true`, matching will
133
 
        be case-sensitive.
134
 
    @param {Boolean} [options.startsWith=false] If `true`, matches must be
135
 
        anchored to the beginning of the string.
136
 
    @return {String} Escaped and highlighted copy of _haystack_.
137
 
    @static
138
 
    **/
139
 
    all: function (haystack, needles, options) {
140
 
        var validNeedles = [],
141
 
            esc, i, len, needle, regex, replacer;
142
 
 
143
 
        if (!options) {
144
 
            options = EMPTY_OBJECT;
145
 
        }
146
 
 
147
 
        // TODO: document options.replacer
148
 
        esc      = options.escapeHTML !== false;
149
 
        regex    = options.startsWith ? Highlight._START_REGEX : Highlight._REGEX;
150
 
        replacer = options.replacer || Highlight._REPLACER;
151
 
        needles  = isArray(needles) ? needles : [needles];
152
 
 
153
 
        // Escape HTML characters and special regular expression characters in
154
 
        // the needles so they can be used in a regex and matched against the
155
 
        // escaped haystack.
156
 
        for (i = 0, len = needles.length; i < len; ++i) {
157
 
            needle = needles[i];
158
 
 
159
 
            if (needle) {
160
 
                validNeedles.push(Escape.regex(esc ? Escape.html(needle) : needle));
161
 
            }
162
 
        }
163
 
 
164
 
        // Escape HTML characters in the haystack to prevent HTML injection.
165
 
        if (esc) {
166
 
            haystack = Escape.html(haystack);
167
 
        }
168
 
 
169
 
        // No point continuing if there are no needles.
170
 
        if (!validNeedles.length) {
171
 
            return haystack;
172
 
        }
173
 
 
174
 
        return haystack.replace(
175
 
            new RegExp(
176
 
                regex.replace('%needles', validNeedles.join('|')),
177
 
                options.caseSensitive ? 'g' : 'gi'
178
 
            ),
179
 
            replacer
180
 
        );
181
 
    },
182
 
 
183
 
    /**
184
 
    Same as `all()`, but case-sensitive by default.
185
 
 
186
 
    @method allCase
187
 
    @param {String} haystack String to apply highlighting to.
188
 
    @param {String|String[]} needles String or array of strings that should be
189
 
      highlighted.
190
 
    @param {Object} [options] Options object. See `all()` for details.
191
 
    @return {String} Escaped and highlighted copy of _haystack_.
192
 
    @static
193
 
    **/
194
 
    allCase: function (haystack, needles, options) {
195
 
        return Highlight.all(haystack, needles,
196
 
                Y.merge(options || EMPTY_OBJECT, {caseSensitive: true}));
197
 
    },
198
 
 
199
 
    /**
200
 
    Highlights _needles_ that occur at the start of _haystack_. The returned
201
 
    string will have all HTML characters escaped except for the highlighting
202
 
    markup.
203
 
 
204
 
    @method start
205
 
    @param {String} haystack String to apply highlighting to.
206
 
    @param {String|String[]} needles String or array of strings that should be
207
 
      highlighted.
208
 
    @param {Object} [options] Options object.
209
 
    @param {Boolean} [options.caseSensitive=false] If `true`, matching will
210
 
        be case-sensitive.
211
 
    @return {String} Escaped and highlighted copy of _haystack_.
212
 
    @static
213
 
    **/
214
 
    start: function (haystack, needles, options) {
215
 
        return Highlight.all(haystack, needles,
216
 
                Y.merge(options || EMPTY_OBJECT, {startsWith: true}));
217
 
    },
218
 
 
219
 
    /**
220
 
    Same as `start()`, but case-sensitive by default.
221
 
 
222
 
    @method startCase
223
 
    @param {String} haystack String to apply highlighting to.
224
 
    @param {String|String[]} needles String or array of strings that should be
225
 
      highlighted.
226
 
    @return {String} Escaped and highlighted copy of _haystack_.
227
 
    @static
228
 
    **/
229
 
    startCase: function (haystack, needles) {
230
 
        // No options passthru for now, since it would be redundant. If start()
231
 
        // ever supports more options than caseSensitive, then we'll start
232
 
        // passing the options through.
233
 
        return Highlight.start(haystack, needles, {caseSensitive: true});
234
 
    },
235
 
 
236
 
    /**
237
 
    Highlights complete words in the _haystack_ string that are also in the
238
 
    _needles_ array. The returned string will have all HTML characters escaped
239
 
    except for the highlighting markup.
240
 
 
241
 
    @method words
242
 
    @param {String} haystack String to apply highlighting to.
243
 
    @param {String|String[]} needles String or array of strings containing words
244
 
      that should be highlighted. If a string is passed, it will be split
245
 
      into words; if an array is passed, it is assumed to have already been
246
 
      split.
247
 
    @param {Object} [options] Options object.
248
 
    @param {Boolean} [options.caseSensitive=false] If `true`, matching will
249
 
        be case-sensitive.
250
 
    @return {String} Escaped and highlighted copy of _haystack_.
251
 
    @static
252
 
    **/
253
 
    words: function (haystack, needles, options) {
254
 
        var caseSensitive,
255
 
            mapper,
256
 
            template = Highlight._TEMPLATE,
257
 
            words;
258
 
 
259
 
        if (!options) {
260
 
            options = EMPTY_OBJECT;
261
 
        }
262
 
 
263
 
        caseSensitive = !!options.caseSensitive;
264
 
 
265
 
        // Convert needles to a hash for faster lookups.
266
 
        needles = YArray.hash(
267
 
            isArray(needles) ? needles : WordBreak.getUniqueWords(needles, {
268
 
                ignoreCase: !caseSensitive
269
 
            })
270
 
        );
271
 
 
272
 
        // The default word mapping function can be overridden with a custom
273
 
        // one. This is used to implement accent-folded highlighting in the
274
 
        // highlight-accentfold module.
275
 
        mapper = options.mapper || function (word, needles) {
276
 
            if (needles.hasOwnProperty(caseSensitive ? word : word.toLowerCase())) {
277
 
                return template.replace(/\{s\}/g, Escape.html(word));
278
 
            }
279
 
 
280
 
            return Escape.html(word);
281
 
        };
282
 
 
283
 
        // Split the haystack into an array of words, including punctuation and
284
 
        // whitespace so we can rebuild the string later.
285
 
        words = WordBreak.getWords(haystack, {
286
 
            includePunctuation: true,
287
 
            includeWhitespace : true
288
 
        });
289
 
 
290
 
        return YArray.map(words, function (word) {
291
 
            return mapper(word, needles);
292
 
        }).join('');
293
 
    },
294
 
 
295
 
    /**
296
 
    Same as `words()`, but case-sensitive by default.
297
 
 
298
 
    @method wordsCase
299
 
    @param {String} haystack String to apply highlighting to.
300
 
    @param {String|String[]} needles String or array of strings containing words
301
 
      that should be highlighted. If a string is passed, it will be split
302
 
      into words; if an array is passed, it is assumed to have already been
303
 
      split.
304
 
    @return {String} Escaped and highlighted copy of _haystack_.
305
 
    @static
306
 
    **/
307
 
    wordsCase: function (haystack, needles) {
308
 
        // No options passthru for now, since it would be redundant. If words()
309
 
        // ever supports more options than caseSensitive, then we'll start
310
 
        // passing the options through.
311
 
        return Highlight.words(haystack, needles, {caseSensitive: true});
312
 
    }
313
 
};
314
 
 
315
 
Y.Highlight = Highlight;
316
 
 
317
 
 
318
 
}, '3.5.0' ,{requires:['array-extras', 'classnamemanager', 'escape', 'text-wordbreak']});