Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

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