|
1 /* |
|
2 YUI 3.10.3 (build 2fb5187) |
|
3 Copyright 2013 Yahoo! Inc. All rights reserved. |
|
4 Licensed under the BSD License. |
|
5 http://yuilibrary.com/license/ |
|
6 */ |
|
7 |
|
8 YUI.add('highlight-accentfold', function (Y, NAME) { |
|
9 |
|
10 /** |
|
11 Adds accent-folding highlighters to `Y.Highlight`. |
|
12 |
|
13 @module highlight |
|
14 @submodule highlight-accentfold |
|
15 **/ |
|
16 |
|
17 /** |
|
18 @class Highlight |
|
19 @static |
|
20 **/ |
|
21 |
|
22 var AccentFold = Y.Text.AccentFold, |
|
23 Escape = Y.Escape, |
|
24 |
|
25 EMPTY_OBJECT = {}, |
|
26 |
|
27 Highlight = Y.mix(Y.Highlight, { |
|
28 // -- Public Static Methods ------------------------------------------------ |
|
29 |
|
30 /** |
|
31 Accent-folding version of `all()`. |
|
32 |
|
33 @method allFold |
|
34 @param {String} haystack String to apply highlighting to. |
|
35 @param {String|String[]} needles String or array of strings that should be |
|
36 highlighted. |
|
37 @param {Object} [options] Options object. |
|
38 @param {Boolean} [options.startsWith=false] If `true`, matches must be |
|
39 anchored to the beginning of the string. |
|
40 @return {String} Escaped and highlighted copy of _haystack_. |
|
41 @static |
|
42 **/ |
|
43 allFold: function (haystack, needles, options) { |
|
44 var template = Highlight._TEMPLATE, |
|
45 results = [], |
|
46 startPos = 0, |
|
47 chunk, i, len, match, result; |
|
48 |
|
49 options = Y.merge({ |
|
50 // This tells Highlight.all() not to escape HTML, in order to ensure |
|
51 // usable match offsets. The output of all() is discarded, and we |
|
52 // perform our own escaping before returning the highlighted string. |
|
53 escapeHTML: false, |
|
54 |
|
55 // While the highlight regex operates on the accent-folded strings, |
|
56 // this replacer will highlight the matched positions in the |
|
57 // original string. |
|
58 // |
|
59 // Note: this implementation doesn't handle multi-character folds, |
|
60 // like "æ" -> "ae". Doing so correctly would be prohibitively |
|
61 // expensive both in terms of code size and runtime performance, so |
|
62 // I've chosen to take the pragmatic route and just not do it at |
|
63 // all. This is one of many reasons why accent folding is best done |
|
64 // on the server. |
|
65 replacer: function (match, p1, foldedNeedle, pos) { |
|
66 var len; |
|
67 |
|
68 // Ignore matches inside HTML entities. |
|
69 if (p1 && !(/\s/).test(foldedNeedle)) { |
|
70 return match; |
|
71 } |
|
72 |
|
73 len = foldedNeedle.length; |
|
74 |
|
75 results.push([ |
|
76 haystack.substring(startPos, pos), // substring between previous match and this match |
|
77 haystack.substr(pos, len) // match to be highlighted |
|
78 ]); |
|
79 |
|
80 startPos = pos + len; |
|
81 } |
|
82 }, options || EMPTY_OBJECT); |
|
83 |
|
84 // Run the highlighter on the folded strings. We don't care about the |
|
85 // output; our replacer function will build the canonical highlighted |
|
86 // string, with original accented characters. |
|
87 Highlight.all(AccentFold.fold(haystack), AccentFold.fold(needles), options); |
|
88 |
|
89 // Tack on the remainder of the haystack that wasn't highlighted, if |
|
90 // any. |
|
91 if (startPos < haystack.length) { |
|
92 results.push([haystack.substr(startPos)]); |
|
93 } |
|
94 |
|
95 // Highlight and escape the string. |
|
96 for (i = 0, len = results.length; i < len; ++i) { |
|
97 chunk = Escape.html(results[i][0]); |
|
98 |
|
99 if ((match = results[i][1])) { |
|
100 chunk += template.replace(/\{s\}/g, Escape.html(match)); |
|
101 } |
|
102 |
|
103 results[i] = chunk; |
|
104 } |
|
105 |
|
106 return results.join(''); |
|
107 }, |
|
108 |
|
109 /** |
|
110 Accent-folding version of `start()`. |
|
111 |
|
112 @method startFold |
|
113 @param {String} haystack String to apply highlighting to. |
|
114 @param {String|String[]} needles String or array of strings that should be |
|
115 highlighted. |
|
116 @return {String} Escaped and highlighted copy of _haystack_. |
|
117 @static |
|
118 **/ |
|
119 startFold: function (haystack, needles) { |
|
120 return Highlight.allFold(haystack, needles, {startsWith: true}); |
|
121 }, |
|
122 |
|
123 /** |
|
124 Accent-folding version of `words()`. |
|
125 |
|
126 @method wordsFold |
|
127 @param {String} haystack String to apply highlighting to. |
|
128 @param {String|String[]} needles String or array of strings containing words |
|
129 that should be highlighted. If a string is passed, it will be split |
|
130 into words; if an array is passed, it is assumed to have already been |
|
131 split. |
|
132 @return {String} Escaped and highlighted copy of _haystack_. |
|
133 @static |
|
134 **/ |
|
135 wordsFold: function (haystack, needles) { |
|
136 var template = Highlight._TEMPLATE; |
|
137 |
|
138 return Highlight.words(haystack, AccentFold.fold(needles), { |
|
139 mapper: function (word, needles) { |
|
140 if (needles.hasOwnProperty(AccentFold.fold(word))) { |
|
141 return template.replace(/\{s\}/g, Escape.html(word)); |
|
142 } |
|
143 |
|
144 return Escape.html(word); |
|
145 } |
|
146 }); |
|
147 } |
|
148 }); |
|
149 |
|
150 |
|
151 }, '3.10.3', {"requires": ["highlight-base", "text-accentfold"]}); |