closure 1.3.1 → 1.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data/README.md +142 -9
  2. data/bin/closure-script +19 -0
  3. data/closure-compiler/README +18 -4
  4. data/closure-compiler/compiler.jar +0 -0
  5. data/closure-templates/SoyToJsSrcCompiler.jar +0 -0
  6. data/closure-templates/soydata.js +163 -0
  7. data/closure-templates/soyutils.js +1191 -159
  8. data/closure-templates/soyutils_usegoog.js +1107 -60
  9. data/docs/closure/Closure.html +58 -52
  10. data/docs/closure/Closure/BeanShell.html +6 -3
  11. data/docs/closure/Closure/Compiler.html +18 -15
  12. data/docs/closure/Closure/Compiler/Compilation.html +9 -3
  13. data/docs/closure/Closure/Compiler/Error.html +3 -3
  14. data/docs/closure/Closure/FileResponse.html +13 -7
  15. data/docs/closure/Closure/Goog.html +49 -85
  16. data/docs/closure/Closure/Middleware.html +5 -3
  17. data/docs/closure/Closure/Script.html +14 -5
  18. data/docs/closure/Closure/Script/NotFound.html +3 -3
  19. data/docs/closure/Closure/Script/RenderStackOverflow.html +3 -3
  20. data/docs/closure/Closure/Server.html +6 -3
  21. data/docs/closure/Closure/ShowExceptions.html +5 -3
  22. data/docs/closure/Closure/Sources.html +145 -37
  23. data/docs/closure/Closure/Templates.html +11 -10
  24. data/docs/closure/Closure/Templates/Error.html +3 -3
  25. data/docs/closure/_index.html +4 -4
  26. data/docs/closure/css/full_list.css +2 -0
  27. data/docs/closure/css/style.css +2 -0
  28. data/docs/closure/file.LICENSE.html +3 -3
  29. data/docs/closure/file.README.html +151 -10
  30. data/docs/closure/frames.html +1 -1
  31. data/docs/closure/index.html +151 -10
  32. data/docs/closure/js/full_list.js +23 -6
  33. data/docs/closure/method_list.html +91 -83
  34. data/docs/closure/top-level-namespace.html +3 -3
  35. data/lib/closure.rb +3 -16
  36. data/lib/closure/compiler.rb +135 -53
  37. data/lib/closure/goog.rb +5 -29
  38. data/lib/closure/sources.rb +22 -9
  39. data/lib/closure/version.rb +1 -1
  40. data/scripts/config.ru +0 -1
  41. data/scripts/hello/compiler_build.js +5 -5
  42. data/scripts/hello/compiler_build.map +518 -522
  43. data/scripts/hello/compiler_debug.js +7 -13
  44. data/scripts/hello/legume.js +2 -2
  45. data/scripts/index.erb +0 -3
  46. data/scripts/modules/compiler_build.js +3 -3
  47. data/scripts/modules/compiler_build.map +11569 -11476
  48. data/scripts/modules/compiler_build_api.js +1 -1
  49. data/scripts/modules/compiler_build_app.js +71 -70
  50. data/scripts/modules/compiler_build_settings.js +2 -2
  51. data/scripts/modules/compiler_debug.js +3 -3
  52. data/scripts/modules/compiler_debug_api.js +2 -2
  53. data/scripts/modules/compiler_debug_app.js +926 -1382
  54. data/scripts/modules/compiler_debug_settings.js +21 -24
  55. metadata +8 -18
  56. data/externs/chrome_extensions.externs +0 -968
  57. data/externs/jquery-1.3.2.externs +0 -718
  58. data/externs/jquery-1.4.3.externs +0 -1289
  59. data/externs/jquery-1.4.4.externs +0 -1302
  60. data/externs/jquery-1.5.externs +0 -1697
  61. data/externs/jquery-ui.externs +0 -10
  62. data/externs/jquery.externs +0 -4
  63. data/scripts/jquery/compiler.js.erb +0 -7
  64. data/scripts/jquery/compiler_out.js +0 -1
  65. data/scripts/jquery/index.erb +0 -25
  66. data/scripts/jquery/jquery_1.4.4.js +0 -167
  67. data/scripts/jquery/jquery_test.js +0 -8
@@ -14,26 +14,40 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
- // Utility functions and classes for Soy.
18
- //
19
- // The top portion of this file contains utilities for Soy users:
20
- // + soy.StringBuilder: Compatible with the 'stringbuilder' code style.
21
- // + soy.renderElement: Render template and set as innerHTML of an element.
22
- // + soy.renderAsFragment: Render template and return as HTML fragment.
23
- //
24
- // The bottom portion of this file contains utilities that should only be called
25
- // by Soy-generated JS code. Please do not use these functions directly from
26
- // your hand-writen code. Their names all start with '$$'.
17
+ /**
18
+ * @fileoverview
19
+ * Utility functions and classes for Soy.
20
+ *
21
+ * <p>
22
+ * The top portion of this file contains utilities for Soy users:<ul>
23
+ * <li> soy.StringBuilder: Compatible with the 'stringbuilder' code style.
24
+ * <li> soy.renderElement: Render template and set as innerHTML of an element.
25
+ * <li> soy.renderAsFragment: Render template and return as HTML fragment.
26
+ * </ul>
27
+ *
28
+ * <p>
29
+ * The bottom portion of this file contains utilities that should only be called
30
+ * by Soy-generated JS code. Please do not use these functions directly from
31
+ * your hand-writen code. Their names all start with '$$'.
32
+ *
33
+ * @author Mike Samuel
34
+ * @author Kai Huang
35
+ * @author Aharon Lenin
36
+ */
27
37
 
28
38
  goog.provide('soy');
29
39
  goog.provide('soy.StringBuilder');
40
+ goog.provide('soy.esc');
30
41
 
31
- goog.require('goog.dom');
42
+ goog.require('goog.asserts');
43
+ goog.require('goog.dom.DomHelper');
32
44
  goog.require('goog.format');
33
45
  goog.require('goog.i18n.BidiFormatter');
34
46
  goog.require('goog.i18n.bidi');
47
+ goog.require('goog.soy');
35
48
  goog.require('goog.string');
36
49
  goog.require('goog.string.StringBuffer');
50
+ goog.require('soydata');
37
51
 
38
52
 
39
53
  // -----------------------------------------------------------------------------
@@ -62,27 +76,62 @@ soy.StringBuilder = goog.string.StringBuffer;
62
76
  * instead of directly setting innerHTML in your hand-written code, so that it
63
77
  * will be easier to audit the code for cross-site scripting vulnerabilities.
64
78
  *
79
+ * NOTE: New code should consider using goog.soy.renderElement instead.
80
+ *
65
81
  * @param {Element} element The element whose content we are rendering.
66
82
  * @param {Function} template The Soy template defining the element's content.
67
83
  * @param {Object=} opt_templateData The data for the template.
84
+ * @param {Object=} opt_injectedData The injected data for the template.
68
85
  */
69
- soy.renderElement = function(element, template, opt_templateData) {
70
- element.innerHTML = template(opt_templateData);
71
- };
86
+ soy.renderElement = goog.soy.renderElement;
72
87
 
73
88
 
74
89
  /**
75
90
  * Helper function to render a Soy template into a single node or a document
76
91
  * fragment. If the rendered HTML string represents a single node, then that
77
- * node is returned. Otherwise a document fragment is returned containing the
92
+ * node is returned (note that this is *not* a fragment, despite them name of
93
+ * the method). Otherwise a document fragment is returned containing the
78
94
  * rendered nodes.
79
95
  *
96
+ * NOTE: New code should consider using goog.soy.renderAsFragment
97
+ * instead (note that the arguments are different).
98
+ *
99
+ * @param {Function} template The Soy template defining the element's content.
100
+ * @param {Object=} opt_templateData The data for the template.
101
+ * @param {Document=} opt_document The document used to create DOM nodes. If not
102
+ * specified, global document object is used.
103
+ * @param {Object=} opt_injectedData The injected data for the template.
104
+ * @return {!Node} The resulting node or document fragment.
105
+ */
106
+ soy.renderAsFragment = function(
107
+ template, opt_templateData, opt_document, opt_injectedData) {
108
+ return goog.soy.renderAsFragment(
109
+ template, opt_templateData, opt_injectedData,
110
+ new goog.dom.DomHelper(opt_document));
111
+ };
112
+
113
+
114
+ /**
115
+ * Helper function to render a Soy template into a single node. If the rendered
116
+ * HTML string represents a single node, then that node is returned. Otherwise,
117
+ * a DIV element is returned containing the rendered nodes.
118
+ *
119
+ * NOTE: New code should consider using goog.soy.renderAsElement
120
+ * instead (note that the arguments are different).
121
+ *
80
122
  * @param {Function} template The Soy template defining the element's content.
81
123
  * @param {Object=} opt_templateData The data for the template.
82
- * @return {Node} The resulting node or document fragment.
124
+ * @param {Document=} opt_document The document used to create DOM nodes. If not
125
+ * specified, global document object is used.
126
+ * @param {Object=} opt_injectedData The injected data for the template.
127
+ * @return {!Element} Rendered template contents, wrapped in a parent DIV
128
+ * element if necessary.
83
129
  */
84
- soy.renderAsFragment = function(template, opt_templateData) {
85
- return goog.dom.htmlToDocumentFragment(template(opt_templateData));
130
+ soy.renderAsElement = function(
131
+ template, opt_templateData, opt_document, opt_injectedData) {
132
+ return goog.soy.renderAsElement(
133
+ template, opt_templateData, opt_injectedData,
134
+ new goog.dom.DomHelper(opt_document));
86
135
  };
87
136
 
88
137
 
@@ -107,9 +156,9 @@ soy.$$augmentData = function(origData, additionalParams) {
107
156
 
108
157
  // Create a new object whose '__proto__' field is set to origData.
109
158
  /** @constructor */
110
- function tempCtor() {};
111
- tempCtor.prototype = origData;
112
- var newData = new tempCtor();
159
+ function TempCtor() {}
160
+ TempCtor.prototype = origData;
161
+ var newData = new TempCtor();
113
162
 
114
163
  // Add the additional params to the new object.
115
164
  for (var key in additionalParams) {
@@ -121,45 +170,462 @@ soy.$$augmentData = function(origData, additionalParams) {
121
170
 
122
171
 
123
172
  /**
124
- * Escapes HTML special characters in a string. Escapes double quote '"' in
173
+ * Gets the keys in a map as an array. There are no guarantees on the order.
174
+ * @param {Object} map The map to get the keys of.
175
+ * @return {Array.<string>} The array of keys in the given map.
176
+ */
177
+ soy.$$getMapKeys = function(map) {
178
+ var mapKeys = [];
179
+ for (var key in map) {
180
+ mapKeys.push(key);
181
+ }
182
+ return mapKeys;
183
+ };
184
+
185
+
186
+ /**
187
+ * Gets a consistent unique id for the given delegate template name. Two calls
188
+ * to this function will return the same id if and only if the input names are
189
+ * the same.
190
+ *
191
+ * <p> Important: This function must always be called with a string constant.
192
+ *
193
+ * <p> If Closure Compiler is not being used, then this is just this identity
194
+ * function. If Closure Compiler is being used, then each call to this function
195
+ * will be replaced with a short string constant, which will be consistent per
196
+ * input name.
197
+ *
198
+ * @param {string} delTemplateName The delegate template name for which to get a
199
+ * consistent unique id.
200
+ * @return {string} A unique id that is consistent per input name.
201
+ *
202
+ * @consistentIdGenerator
203
+ */
204
+ soy.$$getDelegateId = function(delTemplateName) {
205
+ return delTemplateName;
206
+ };
207
+
208
+
209
+ /**
210
+ * Map from registered delegate template id/name to the priority of the
211
+ * implementation.
212
+ * @type {Object}
213
+ * @private
214
+ */
215
+ soy.$$DELEGATE_REGISTRY_PRIORITIES_ = {};
216
+
217
+ /**
218
+ * Map from registered delegate template id/name to the implementation function.
219
+ * @type {Object}
220
+ * @private
221
+ */
222
+ soy.$$DELEGATE_REGISTRY_FUNCTIONS_ = {};
223
+
224
+
225
+ /**
226
+ * Registers a delegate implementation. If the same delegate template id/name
227
+ * has been registered previously, then priority values are compared and only
228
+ * the higher priority implementation is stored (if priorities are equal, an
229
+ * error is thrown).
230
+ *
231
+ * @param {string} delTemplateId The delegate template id/name to register.
232
+ * @param {number} delPriority The implementation's priority value.
233
+ * @param {Function} delFn The implementation function.
234
+ */
235
+ soy.$$registerDelegateFn = function(delTemplateId, delPriority, delFn) {
236
+ var mapKey = 'key_' + delTemplateId;
237
+ var currPriority = soy.$$DELEGATE_REGISTRY_PRIORITIES_[mapKey];
238
+ if (currPriority === undefined || delPriority > currPriority) {
239
+ // Registering new or higher-priority function: replace registry entry.
240
+ soy.$$DELEGATE_REGISTRY_PRIORITIES_[mapKey] = delPriority;
241
+ soy.$$DELEGATE_REGISTRY_FUNCTIONS_[mapKey] = delFn;
242
+ } else if (delPriority == currPriority) {
243
+ // Registering same-priority function: error.
244
+ throw Error(
245
+ 'Encountered two active delegates with same priority (id/name "' +
246
+ delTemplateId + '").');
247
+ } else {
248
+ // Registering lower-priority function: do nothing.
249
+ }
250
+ };
251
+
252
+
253
+ /**
254
+ * Retrieves the (highest-priority) implementation that has been registered for
255
+ * a given delegate template id/name. If no implementation has been registered
256
+ * for the id/name, then returns an implementation that is equivalent to an
257
+ * empty template (i.e. rendered output would be empty string).
258
+ *
259
+ * @param {string} delTemplateId The delegate template id/name to get.
260
+ * @return {Function} The retrieved implementation function.
261
+ */
262
+ soy.$$getDelegateFn = function(delTemplateId) {
263
+ var delFn = soy.$$DELEGATE_REGISTRY_FUNCTIONS_['key_' + delTemplateId];
264
+ return delFn ? delFn : soy.$$EMPTY_TEMPLATE_FN_;
265
+ };
266
+
267
+
268
+ /**
269
+ * Private helper soy.$$getDelegateFn(). This is the empty template function
270
+ * that is returned whenever there's no delegate implementation found.
271
+ *
272
+ * @param {Object.<string, *>=} opt_data
273
+ * @param {soy.StringBuilder=} opt_sb
274
+ * @param {Object.<string, *>=} opt_ijData
275
+ * @return {string}
276
+ * @private
277
+ */
278
+ soy.$$EMPTY_TEMPLATE_FN_ = function(opt_data, opt_sb, opt_ijData) {
279
+ return '';
280
+ };
281
+
282
+
283
+ /**
284
+ * Used for temporary fix. See GenJsCodeVisitor.java.
285
+ * TODO: Remove when i18n plurals team provides a better # processing option.
286
+ * @param {string} str The string to escape.
287
+ * @return {string} The escaped string.
288
+ */
289
+ soy.$$tempHashEscape = function(str) {
290
+ return str.replace(soy.$$HASH_RE_, '__HashLit__');
291
+ };
292
+
293
+ /**
294
+ * Used by soy.$$tempHashEscape().
295
+ * @type {RegExp}
296
+ * @private
297
+ */
298
+ soy.$$HASH_RE_ = /#/g;
299
+
300
+
301
+ /**
302
+ * Used for temporary fix. See GenJsCodeVisitor.java.
303
+ * TODO: Remove when i18n plurals team provides a better # processing option.
304
+ * @param {string} str The string to unescape.
305
+ * @return {string} The unescaped string.
306
+ */
307
+ soy.$$tempHashUnescape = function(str) {
308
+ return str.replace(soy.$$HASH_ESCAPED_RE_, '#');
309
+ };
310
+
311
+ /**
312
+ * Used by soy.$$tempHashUnescape().
313
+ * @type {RegExp}
314
+ * @private
315
+ */
316
+ soy.$$HASH_ESCAPED_RE_ = /__HashLit__/g;
317
+
318
+
319
+ // -----------------------------------------------------------------------------
320
+ // Escape/filter/normalize.
321
+
322
+
323
+ /**
324
+ * Escapes HTML special characters in a string. Escapes double quote '"' in
125
325
  * addition to '&', '<', and '>' so that a string can be included in an HTML
126
326
  * tag attribute value within double quotes.
327
+ * Will emit known safe HTML as-is.
328
+ *
329
+ * @param {*} value The string-like value to be escaped. May not be a string,
330
+ * but the value will be coerced to a string.
331
+ * @return {string} An escaped version of value.
332
+ */
333
+ soy.$$escapeHtml = function(value) {
334
+ if (typeof value === 'object' && value &&
335
+ value.contentKind === soydata.SanitizedContentKind.HTML) {
336
+ return value.content;
337
+ }
338
+ return soy.esc.$$escapeHtmlHelper(value);
339
+ };
340
+
341
+
342
+ /**
343
+ * Escapes HTML special characters in a string so that it can be embedded in
344
+ * RCDATA.
345
+ * <p>
346
+ * Escapes HTML special characters so that the value will not prematurely end
347
+ * the body of a tag like {@code <textarea>} or {@code <title>}. RCDATA tags
348
+ * cannot contain other HTML entities, so it is not strictly necessary to escape
349
+ * HTML special characters except when part of that text looks like an HTML
350
+ * entity or like a close tag : {@code </textarea>}.
351
+ * <p>
352
+ * Will normalize known safe HTML to make sure that sanitized HTML (which could
353
+ * contain an innocuous {@code </textarea>} don't prematurely end an RCDATA
354
+ * element.
355
+ *
356
+ * @param {*} value The string-like value to be escaped. May not be a string,
357
+ * but the value will be coerced to a string.
358
+ * @return {string} An escaped version of value.
359
+ */
360
+ soy.$$escapeHtmlRcdata = function(value) {
361
+ if (typeof value === 'object' && value &&
362
+ value.contentKind === soydata.SanitizedContentKind.HTML) {
363
+ return soy.esc.$$normalizeHtmlHelper(value.content);
364
+ }
365
+ return soy.esc.$$escapeHtmlHelper(value);
366
+ };
367
+
368
+
369
+ /**
370
+ * Removes HTML tags from a string of known safe HTML so it can be used as an
371
+ * attribute value.
372
+ *
373
+ * @param {*} value The HTML to be escaped. May not be a string, but the
374
+ * value will be coerced to a string.
375
+ * @return {string} A representation of value without tags, HTML comments, or
376
+ * other content.
377
+ */
378
+ soy.$$stripHtmlTags = function(value) {
379
+ return String(value).replace(soy.esc.$$HTML_TAG_REGEX_, '');
380
+ };
381
+
382
+
383
+ /**
384
+ * Escapes HTML special characters in an HTML attribute value.
127
385
  *
128
- * @param {*} str The string to be escaped. Can be other types, but the value
386
+ * @param {*} value The HTML to be escaped. May not be a string, but the
387
+ * value will be coerced to a string.
388
+ * @return {string} An escaped version of value.
389
+ */
390
+ soy.$$escapeHtmlAttribute = function(value) {
391
+ if (typeof value === 'object' && value &&
392
+ value.contentKind === soydata.SanitizedContentKind.HTML) {
393
+ return soy.esc.$$normalizeHtmlHelper(soy.$$stripHtmlTags(value.content));
394
+ }
395
+ return soy.esc.$$escapeHtmlHelper(value);
396
+ };
397
+
398
+
399
+ /**
400
+ * Escapes HTML special characters in a string including space and other
401
+ * characters that can end an unquoted HTML attribute value.
402
+ *
403
+ * @param {*} value The HTML to be escaped. May not be a string, but the
404
+ * value will be coerced to a string.
405
+ * @return {string} An escaped version of value.
406
+ */
407
+ soy.$$escapeHtmlAttributeNospace = function(value) {
408
+ if (typeof value === 'object' && value &&
409
+ value.contentKind === soydata.SanitizedContentKind.HTML) {
410
+ return soy.esc.$$normalizeHtmlNospaceHelper(
411
+ soy.$$stripHtmlTags(value.content));
412
+ }
413
+ return soy.esc.$$escapeHtmlNospaceHelper(value);
414
+ };
415
+
416
+
417
+ /**
418
+ * Filters out strings that cannot be a substring of a valid HTML attribute.
419
+ *
420
+ * @param {*} value The value to escape. May not be a string, but the value
421
+ * will be coerced to a string.
422
+ * @return {string} A valid HTML attribute name part or name/value pair.
423
+ * {@code "zSoyz"} if the input is invalid.
424
+ */
425
+ soy.$$filterHtmlAttribute = function(value) {
426
+ if (typeof value === 'object' && value &&
427
+ value.contentKind === soydata.SanitizedContentKind.HTML_ATTRIBUTE) {
428
+ return value.content.replace(/=([^"']*)$/, '="$1"');
429
+ }
430
+ return soy.esc.$$filterHtmlAttributeHelper(value);
431
+ };
432
+
433
+
434
+ /**
435
+ * Filters out strings that cannot be a substring of a valid HTML element name.
436
+ *
437
+ * @param {*} value The value to escape. May not be a string, but the value
438
+ * will be coerced to a string.
439
+ * @return {string} A valid HTML element name part.
440
+ * {@code "zSoyz"} if the input is invalid.
441
+ */
442
+ soy.$$filterHtmlElementName = function(value) {
443
+ return soy.esc.$$filterHtmlElementNameHelper(value);
444
+ };
445
+
446
+
447
+ /**
448
+ * Escapes characters in the value to make it valid content for a JS string
449
+ * literal.
450
+ *
451
+ * @param {*} value The value to escape. May not be a string, but the value
129
452
  * will be coerced to a string.
130
- * @return {string} An escaped copy of the string.
131
- */
132
- soy.$$escapeHtml = function(str) {
133
- return goog.string.htmlEscape(String(str));
453
+ * @return {string} An escaped version of value.
454
+ * @deprecated
455
+ */
456
+ soy.$$escapeJs = function(value) {
457
+ return soy.$$escapeJsString(value);
134
458
  };
135
459
 
136
460
 
137
461
  /**
138
- * Escapes characters in the string to make it a valid content for a JS string literal.
462
+ * Escapes characters in the value to make it valid content for a JS string
463
+ * literal.
139
464
  *
140
- * @param {*} s The string to be escaped. Can be other types, but the value
465
+ * @param {*} value The value to escape. May not be a string, but the value
141
466
  * will be coerced to a string.
142
- * @return {string} An escaped copy of the string.
143
- */
144
- soy.$$escapeJs = function(s) {
145
- s = String(s);
146
- var sb = [];
147
- for (var i = 0; i < s.length; i++) {
148
- sb[i] = goog.string.escapeChar(s.charAt(i));
467
+ * @return {string} An escaped version of value.
468
+ */
469
+ soy.$$escapeJsString = function(value) {
470
+ if (typeof value === 'object' &&
471
+ value.contentKind === soydata.SanitizedContentKind.JS_STR_CHARS) {
472
+ return value.content;
473
+ }
474
+ return soy.esc.$$escapeJsStringHelper(value);
475
+ };
476
+
477
+
478
+ /**
479
+ * Encodes a value as a JavaScript literal.
480
+ *
481
+ * @param {*} value The value to escape. May not be a string, but the value
482
+ * will be coerced to a string.
483
+ * @return {string} A JavaScript code representation of the input.
484
+ */
485
+ soy.$$escapeJsValue = function(value) {
486
+ // We surround values with spaces so that they can't be interpolated into
487
+ // identifiers by accident.
488
+ // We could use parentheses but those might be interpreted as a function call.
489
+ if (value == null) { // Intentionally matches undefined.
490
+ // Java returns null from maps where there is no corresponding key while
491
+ // JS returns undefined.
492
+ // We always output null for compatibility with Java which does not have a
493
+ // distinct undefined value.
494
+ return ' null ';
495
+ }
496
+ switch (typeof value) {
497
+ case 'boolean': case 'number':
498
+ return ' ' + value + ' ';
499
+ default:
500
+ return "'" + soy.esc.$$escapeJsStringHelper(String(value)) + "'";
149
501
  }
150
- return sb.join('');
151
502
  };
152
503
 
153
504
 
154
505
  /**
155
- * Escapes a string so that it can be safely included in a URI
506
+ * Escapes characters in the string to make it valid content for a JS regular
507
+ * expression literal.
156
508
  *
157
- * @param {*} str The string to be escaped. Can be other types, but the value
509
+ * @param {*} value The value to escape. May not be a string, but the value
158
510
  * will be coerced to a string.
159
- * @return {string} An escaped copy of the string.
160
- */
161
- soy.$$escapeUri = function(str) {
162
- return goog.string.urlEncode(String(str));
511
+ * @return {string} An escaped version of value.
512
+ */
513
+ soy.$$escapeJsRegex = function(value) {
514
+ return soy.esc.$$escapeJsRegexHelper(value);
515
+ };
516
+
517
+
518
+ /**
519
+ * Matches all URI mark characters that conflict with HTML attribute delimiters
520
+ * or that cannot appear in a CSS uri.
521
+ * From <a href="http://www.w3.org/TR/CSS2/grammar.html">G.2: CSS grammar</a>
522
+ * <pre>
523
+ * url ([!#$%&*-~]|{nonascii}|{escape})*
524
+ * </pre>
525
+ *
526
+ * @type {RegExp}
527
+ * @private
528
+ */
529
+ soy.$$problematicUriMarks_ = /['()]/g;
530
+
531
+ /**
532
+ * @param {string} ch A single character in {@link soy.$$problematicUriMarks_}.
533
+ * @return {string}
534
+ * @private
535
+ */
536
+ soy.$$pctEncode_ = function(ch) {
537
+ return '%' + ch.charCodeAt(0).toString(16);
538
+ };
539
+
540
+ /**
541
+ * Escapes a string so that it can be safely included in a URI.
542
+ *
543
+ * @param {*} value The value to escape. May not be a string, but the value
544
+ * will be coerced to a string.
545
+ * @return {string} An escaped version of value.
546
+ */
547
+ soy.$$escapeUri = function(value) {
548
+ if (typeof value === 'object' &&
549
+ value.contentKind === soydata.SanitizedContentKind.URI) {
550
+ return soy.$$normalizeUri(value);
551
+ }
552
+ // Apostophes and parentheses are not matched by encodeURIComponent.
553
+ // They are technically special in URIs, but only appear in the obsolete mark
554
+ // production in Appendix D.2 of RFC 3986, so can be encoded without changing
555
+ // semantics.
556
+ var encoded = soy.esc.$$escapeUriHelper(value);
557
+ soy.$$problematicUriMarks_.lastIndex = 0;
558
+ if (soy.$$problematicUriMarks_.test(encoded)) {
559
+ return encoded.replace(soy.$$problematicUriMarks_, soy.$$pctEncode_);
560
+ }
561
+ return encoded;
562
+ };
563
+
564
+
565
+ /**
566
+ * Removes rough edges from a URI by escaping any raw HTML/JS string delimiters.
567
+ *
568
+ * @param {*} value The value to escape. May not be a string, but the value
569
+ * will be coerced to a string.
570
+ * @return {string} An escaped version of value.
571
+ */
572
+ soy.$$normalizeUri = function(value) {
573
+ return soy.esc.$$normalizeUriHelper(value);
574
+ };
575
+
576
+
577
+ /**
578
+ * Vets a URI's protocol and removes rough edges from a URI by escaping
579
+ * any raw HTML/JS string delimiters.
580
+ *
581
+ * @param {*} value The value to escape. May not be a string, but the value
582
+ * will be coerced to a string.
583
+ * @return {string} An escaped version of value.
584
+ */
585
+ soy.$$filterNormalizeUri = function(value) {
586
+ return soy.esc.$$filterNormalizeUriHelper(value);
587
+ };
588
+
589
+
590
+ /**
591
+ * Escapes a string so it can safely be included inside a quoted CSS string.
592
+ *
593
+ * @param {*} value The value to escape. May not be a string, but the value
594
+ * will be coerced to a string.
595
+ * @return {string} An escaped version of value.
596
+ */
597
+ soy.$$escapeCssString = function(value) {
598
+ return soy.esc.$$escapeCssStringHelper(value);
599
+ };
600
+
601
+
602
+ /**
603
+ * Encodes a value as a CSS identifier part, keyword, or quantity.
604
+ *
605
+ * @param {*} value The value to escape. May not be a string, but the value
606
+ * will be coerced to a string.
607
+ * @return {string} A safe CSS identifier part, keyword, or quanitity.
608
+ */
609
+ soy.$$filterCssValue = function(value) {
610
+ // Uses == to intentionally match null and undefined for Java compatibility.
611
+ if (value == null) {
612
+ return '';
613
+ }
614
+ return soy.esc.$$filterCssValueHelper(value);
615
+ };
616
+
617
+
618
+ // -----------------------------------------------------------------------------
619
+ // Basic directives/functions.
620
+
621
+
622
+ /**
623
+ * Converts \r\n, \r, and \n to <br>s
624
+ * @param {*} str The string in which to convert newlines.
625
+ * @return {string} A copy of {@code str} with converted newlines.
626
+ */
627
+ soy.$$changeNewlineToBr = function(str) {
628
+ return goog.string.newLineToBr(String(str), false);
163
629
  };
164
630
 
165
631
 
@@ -181,19 +647,80 @@ soy.$$insertWordBreaks = function(str, maxCharsBetweenWordBreaks) {
181
647
 
182
648
 
183
649
  /**
184
- * Converts \r\n, \r, and \n to <br>s
185
- * @param {*} str The string in which to convert newlines.
186
- * @return {string} A copy of {@code str} with converted newlines.
650
+ * Truncates a string to a given max length (if it's currently longer),
651
+ * optionally adding ellipsis at the end.
652
+ *
653
+ * @param {*} str The string to truncate. Can be other types, but the value will
654
+ * be coerced to a string.
655
+ * @param {number} maxLen The maximum length of the string after truncation
656
+ * (including ellipsis, if applicable).
657
+ * @param {boolean} doAddEllipsis Whether to add ellipsis if the string needs
658
+ * truncation.
659
+ * @return {string} The string after truncation.
187
660
  */
188
- soy.$$changeNewlineToBr = function(str) {
189
- return goog.string.newLineToBr(String(str), false);
661
+ soy.$$truncate = function(str, maxLen, doAddEllipsis) {
662
+
663
+ str = String(str);
664
+ if (str.length <= maxLen) {
665
+ return str; // no need to truncate
666
+ }
667
+
668
+ // If doAddEllipsis, either reduce maxLen to compensate, or else if maxLen is
669
+ // too small, just turn off doAddEllipsis.
670
+ if (doAddEllipsis) {
671
+ if (maxLen > 3) {
672
+ maxLen -= 3;
673
+ } else {
674
+ doAddEllipsis = false;
675
+ }
676
+ }
677
+
678
+ // Make sure truncating at maxLen doesn't cut up a unicode surrogate pair.
679
+ if (soy.$$isHighSurrogate_(str.charAt(maxLen - 1)) &&
680
+ soy.$$isLowSurrogate_(str.charAt(maxLen))) {
681
+ maxLen -= 1;
682
+ }
683
+
684
+ // Truncate.
685
+ str = str.substring(0, maxLen);
686
+
687
+ // Add ellipsis.
688
+ if (doAddEllipsis) {
689
+ str += '...';
690
+ }
691
+
692
+ return str;
693
+ };
694
+
695
+ /**
696
+ * Private helper for $$truncate() to check whether a char is a high surrogate.
697
+ * @param {string} ch The char to check.
698
+ * @return {boolean} Whether the given char is a unicode high surrogate.
699
+ * @private
700
+ */
701
+ soy.$$isHighSurrogate_ = function(ch) {
702
+ return 0xD800 <= ch && ch <= 0xDBFF;
190
703
  };
191
704
 
705
+ /**
706
+ * Private helper for $$truncate() to check whether a char is a low surrogate.
707
+ * @param {string} ch The char to check.
708
+ * @return {boolean} Whether the given char is a unicode low surrogate.
709
+ * @private
710
+ */
711
+ soy.$$isLowSurrogate_ = function(ch) {
712
+ return 0xDC00 <= ch && ch <= 0xDFFF;
713
+ };
714
+
715
+
716
+ // -----------------------------------------------------------------------------
717
+ // Bidi directives/functions.
718
+
192
719
 
193
720
  /**
194
721
  * Cache of bidi formatter by context directionality, so we don't keep on
195
722
  * creating new objects.
196
- * @type {Object}
723
+ * @type {!Object.<!goog.i18n.BidiFormatter>}
197
724
  * @private
198
725
  */
199
726
  soy.$$bidiFormatterCache_ = {};
@@ -206,13 +733,37 @@ soy.$$bidiFormatterCache_ = {};
206
733
  * @return {goog.i18n.BidiFormatter} A formatter for bidiGlobalDir.
207
734
  * @private
208
735
  */
209
- soy.$$bidiFormatterInstance_ = function(bidiGlobalDir) {
736
+ soy.$$getBidiFormatterInstance_ = function(bidiGlobalDir) {
210
737
  return soy.$$bidiFormatterCache_[bidiGlobalDir] ||
211
738
  (soy.$$bidiFormatterCache_[bidiGlobalDir] =
212
739
  new goog.i18n.BidiFormatter(bidiGlobalDir));
213
740
  };
214
741
 
215
742
 
743
+ /**
744
+ * Returns the leading horizontal edge, i.e. "left" or "right", depending on
745
+ * bidiGlobalDir.
746
+ * @param {number} bidiGlobalDir The global directionality context: 1 if ltr, -1
747
+ * if rtl, 0 if unknown.
748
+ * @return {string} "right" for RTL context and "left" otherwise.
749
+ */
750
+ soy.$$bidiStartEdge = function(bidiGlobalDir) {
751
+ return soy.$$getBidiFormatterInstance_(bidiGlobalDir).startEdge();
752
+ };
753
+
754
+
755
+ /**
756
+ * Returns the trailing horizontal edge, i.e. "right" or "left", depending on
757
+ * bidiGlobalDir.
758
+ * @param {number} bidiGlobalDir The global directionality context: 1 if ltr, -1
759
+ * if rtl, 0 if unknown.
760
+ * @return {string} "left" for RTL context and "right" otherwise.
761
+ */
762
+ soy.$$bidiEndEdge = function(bidiGlobalDir) {
763
+ return soy.$$getBidiFormatterInstance_(bidiGlobalDir).endEdge();
764
+ };
765
+
766
+
216
767
  /**
217
768
  * Estimate the overall directionality of text. If opt_isHtml, makes sure to
218
769
  * ignore the LTR nature of the mark-up and escapes in text, making the logic
@@ -241,12 +792,26 @@ soy.$$bidiTextDir = function(text, opt_isHtml) {
241
792
  * @param {string} text The text whose directionality is to be estimated.
242
793
  * @param {boolean=} opt_isHtml Whether text is HTML/HTML-escaped.
243
794
  * Default: false.
244
- * @return {string} "dir=rtl" for RTL text in non-RTL context; "dir=ltr" for LTR
245
- * text in non-LTR context; else, the empty string.
795
+ * @return {soydata.SanitizedHtmlAttribute} "dir=rtl" for RTL text in non-RTL
796
+ * context; "dir=ltr" for LTR text in non-LTR context;
797
+ * else, the empty string.
246
798
  */
247
799
  soy.$$bidiDirAttr = function(bidiGlobalDir, text, opt_isHtml) {
248
- var formatter = soy.$$bidiFormatterInstance_(bidiGlobalDir);
249
- return formatter.dirAttr(text, opt_isHtml);
800
+ return new soydata.SanitizedHtmlAttribute(
801
+ soy.$$getBidiFormatterInstance_(bidiGlobalDir).dirAttr(text, opt_isHtml));
802
+ };
803
+
804
+
805
+ /**
806
+ * Returns a Unicode BiDi mark matching bidiGlobalDir (LRM or RLM), or an empty
807
+ * string if bidiGlobalDir is 0 (unknown).
808
+ * @param {number} bidiGlobalDir The global directionality context: 1 if ltr, -1
809
+ * if rtl, 0 if unknown.
810
+ * @return {string} A Unicode bidi mark matching bidiGlobalDir, or the empty
811
+ * string when bidiGlobalDir is 0 (unknown).
812
+ */
813
+ soy.$$bidiMark = function(bidiGlobalDir) {
814
+ return soy.$$getBidiFormatterInstance_(bidiGlobalDir).mark();
250
815
  };
251
816
 
252
817
 
@@ -261,12 +826,12 @@ soy.$$bidiDirAttr = function(bidiGlobalDir, text, opt_isHtml) {
261
826
  * @param {string} text The text whose directionality is to be estimated.
262
827
  * @param {boolean=} opt_isHtml Whether text is HTML/HTML-escaped.
263
828
  * Default: false.
264
- * @return {string} A Unicode bidi mark matching bidiGlobalDir, or
265
- * the empty string when text's overall and exit directionalities both match
266
- * bidiGlobalDir.
829
+ * @return {string} A Unicode bidi mark matching bidiGlobalDir, or the empty
830
+ * string when text's overall and exit directionalities both match
831
+ * bidiGlobalDir, or bidiGlobalDir is 0 (unknown).
267
832
  */
268
833
  soy.$$bidiMarkAfter = function(bidiGlobalDir, text, opt_isHtml) {
269
- var formatter = soy.$$bidiFormatterInstance_(bidiGlobalDir);
834
+ var formatter = soy.$$getBidiFormatterInstance_(bidiGlobalDir);
270
835
  return formatter.markAfter(text, opt_isHtml);
271
836
  };
272
837
 
@@ -284,7 +849,7 @@ soy.$$bidiMarkAfter = function(bidiGlobalDir, text, opt_isHtml) {
284
849
  * @return {string} The wrapped string.
285
850
  */
286
851
  soy.$$bidiSpanWrap = function(bidiGlobalDir, str) {
287
- var formatter = soy.$$bidiFormatterInstance_(bidiGlobalDir);
852
+ var formatter = soy.$$getBidiFormatterInstance_(bidiGlobalDir);
288
853
  return formatter.spanWrap(str + '', true);
289
854
  };
290
855
 
@@ -303,6 +868,488 @@ soy.$$bidiSpanWrap = function(bidiGlobalDir, str) {
303
868
  * @return {string} The wrapped string.
304
869
  */
305
870
  soy.$$bidiUnicodeWrap = function(bidiGlobalDir, str) {
306
- var formatter = soy.$$bidiFormatterInstance_(bidiGlobalDir);
871
+ var formatter = soy.$$getBidiFormatterInstance_(bidiGlobalDir);
307
872
  return formatter.unicodeWrap(str + '', true);
308
873
  };
874
+
875
+
876
+ // -----------------------------------------------------------------------------
877
+ // Generated code.
878
+
879
+
880
+
881
+
882
+ // START GENERATED CODE FOR ESCAPERS.
883
+
884
+ /**
885
+ * @type {function (*) : string}
886
+ */
887
+ soy.esc.$$escapeUriHelper = function(v) {
888
+ return goog.string.urlEncode(String(v));
889
+ };
890
+
891
+ /**
892
+ * Maps charcters to the escaped versions for the named escape directives.
893
+ * @type {Object.<string, string>}
894
+ * @private
895
+ */
896
+ soy.esc.$$ESCAPE_MAP_FOR_ESCAPE_HTML__AND__NORMALIZE_HTML__AND__ESCAPE_HTML_NOSPACE__AND__NORMALIZE_HTML_NOSPACE_ = {
897
+ '\x00': '\x26#0;',
898
+ '\x22': '\x26quot;',
899
+ '\x26': '\x26amp;',
900
+ '\x27': '\x26#39;',
901
+ '\x3c': '\x26lt;',
902
+ '\x3e': '\x26gt;',
903
+ '\x09': '\x26#9;',
904
+ '\x0a': '\x26#10;',
905
+ '\x0b': '\x26#11;',
906
+ '\x0c': '\x26#12;',
907
+ '\x0d': '\x26#13;',
908
+ ' ': '\x26#32;',
909
+ '-': '\x26#45;',
910
+ '\/': '\x26#47;',
911
+ '\x3d': '\x26#61;',
912
+ '`': '\x26#96;',
913
+ '\x85': '\x26#133;',
914
+ '\xa0': '\x26#160;',
915
+ '\u2028': '\x26#8232;',
916
+ '\u2029': '\x26#8233;'
917
+ };
918
+
919
+ /**
920
+ * A function that can be used with String.replace..
921
+ * @param {string} ch A single character matched by a compatible matcher.
922
+ * @return {string} A token in the output language.
923
+ * @private
924
+ */
925
+ soy.esc.$$REPLACER_FOR_ESCAPE_HTML__AND__NORMALIZE_HTML__AND__ESCAPE_HTML_NOSPACE__AND__NORMALIZE_HTML_NOSPACE_ = function(ch) {
926
+ return soy.esc.$$ESCAPE_MAP_FOR_ESCAPE_HTML__AND__NORMALIZE_HTML__AND__ESCAPE_HTML_NOSPACE__AND__NORMALIZE_HTML_NOSPACE_[ch];
927
+ };
928
+
929
+ /**
930
+ * Maps charcters to the escaped versions for the named escape directives.
931
+ * @type {Object.<string, string>}
932
+ * @private
933
+ */
934
+ soy.esc.$$ESCAPE_MAP_FOR_ESCAPE_JS_STRING__AND__ESCAPE_JS_REGEX_ = {
935
+ '\x00': '\\x00',
936
+ '\x08': '\\x08',
937
+ '\x09': '\\t',
938
+ '\x0a': '\\n',
939
+ '\x0b': '\\x0b',
940
+ '\x0c': '\\f',
941
+ '\x0d': '\\r',
942
+ '\x22': '\\x22',
943
+ '\x26': '\\x26',
944
+ '\x27': '\\x27',
945
+ '\/': '\\\/',
946
+ '\x3c': '\\x3c',
947
+ '\x3d': '\\x3d',
948
+ '\x3e': '\\x3e',
949
+ '\\': '\\\\',
950
+ '\x85': '\\x85',
951
+ '\u2028': '\\u2028',
952
+ '\u2029': '\\u2029',
953
+ '$': '\\x24',
954
+ '(': '\\x28',
955
+ ')': '\\x29',
956
+ '*': '\\x2a',
957
+ '+': '\\x2b',
958
+ ',': '\\x2c',
959
+ '-': '\\x2d',
960
+ '.': '\\x2e',
961
+ ':': '\\x3a',
962
+ '?': '\\x3f',
963
+ '[': '\\x5b',
964
+ ']': '\\x5d',
965
+ '^': '\\x5e',
966
+ '{': '\\x7b',
967
+ '|': '\\x7c',
968
+ '}': '\\x7d'
969
+ };
970
+
971
+ /**
972
+ * A function that can be used with String.replace..
973
+ * @param {string} ch A single character matched by a compatible matcher.
974
+ * @return {string} A token in the output language.
975
+ * @private
976
+ */
977
+ soy.esc.$$REPLACER_FOR_ESCAPE_JS_STRING__AND__ESCAPE_JS_REGEX_ = function(ch) {
978
+ return soy.esc.$$ESCAPE_MAP_FOR_ESCAPE_JS_STRING__AND__ESCAPE_JS_REGEX_[ch];
979
+ };
980
+
981
+ /**
982
+ * Maps charcters to the escaped versions for the named escape directives.
983
+ * @type {Object.<string, string>}
984
+ * @private
985
+ */
986
+ soy.esc.$$ESCAPE_MAP_FOR_ESCAPE_CSS_STRING_ = {
987
+ '\x00': '\\0 ',
988
+ '\x08': '\\8 ',
989
+ '\x09': '\\9 ',
990
+ '\x0a': '\\a ',
991
+ '\x0b': '\\b ',
992
+ '\x0c': '\\c ',
993
+ '\x0d': '\\d ',
994
+ '\x22': '\\22 ',
995
+ '\x26': '\\26 ',
996
+ '\x27': '\\27 ',
997
+ '(': '\\28 ',
998
+ ')': '\\29 ',
999
+ '*': '\\2a ',
1000
+ '\/': '\\2f ',
1001
+ ':': '\\3a ',
1002
+ ';': '\\3b ',
1003
+ '\x3c': '\\3c ',
1004
+ '\x3d': '\\3d ',
1005
+ '\x3e': '\\3e ',
1006
+ '@': '\\40 ',
1007
+ '\\': '\\5c ',
1008
+ '{': '\\7b ',
1009
+ '}': '\\7d ',
1010
+ '\x85': '\\85 ',
1011
+ '\xa0': '\\a0 ',
1012
+ '\u2028': '\\2028 ',
1013
+ '\u2029': '\\2029 '
1014
+ };
1015
+
1016
+ /**
1017
+ * A function that can be used with String.replace..
1018
+ * @param {string} ch A single character matched by a compatible matcher.
1019
+ * @return {string} A token in the output language.
1020
+ * @private
1021
+ */
1022
+ soy.esc.$$REPLACER_FOR_ESCAPE_CSS_STRING_ = function(ch) {
1023
+ return soy.esc.$$ESCAPE_MAP_FOR_ESCAPE_CSS_STRING_[ch];
1024
+ };
1025
+
1026
+ /**
1027
+ * Maps charcters to the escaped versions for the named escape directives.
1028
+ * @type {Object.<string, string>}
1029
+ * @private
1030
+ */
1031
+ soy.esc.$$ESCAPE_MAP_FOR_NORMALIZE_URI__AND__FILTER_NORMALIZE_URI_ = {
1032
+ '\x00': '%00',
1033
+ '\x01': '%01',
1034
+ '\x02': '%02',
1035
+ '\x03': '%03',
1036
+ '\x04': '%04',
1037
+ '\x05': '%05',
1038
+ '\x06': '%06',
1039
+ '\x07': '%07',
1040
+ '\x08': '%08',
1041
+ '\x09': '%09',
1042
+ '\x0a': '%0A',
1043
+ '\x0b': '%0B',
1044
+ '\x0c': '%0C',
1045
+ '\x0d': '%0D',
1046
+ '\x0e': '%0E',
1047
+ '\x0f': '%0F',
1048
+ '\x10': '%10',
1049
+ '\x11': '%11',
1050
+ '\x12': '%12',
1051
+ '\x13': '%13',
1052
+ '\x14': '%14',
1053
+ '\x15': '%15',
1054
+ '\x16': '%16',
1055
+ '\x17': '%17',
1056
+ '\x18': '%18',
1057
+ '\x19': '%19',
1058
+ '\x1a': '%1A',
1059
+ '\x1b': '%1B',
1060
+ '\x1c': '%1C',
1061
+ '\x1d': '%1D',
1062
+ '\x1e': '%1E',
1063
+ '\x1f': '%1F',
1064
+ ' ': '%20',
1065
+ '\x22': '%22',
1066
+ '\x27': '%27',
1067
+ '(': '%28',
1068
+ ')': '%29',
1069
+ '\x3c': '%3C',
1070
+ '\x3e': '%3E',
1071
+ '\\': '%5C',
1072
+ '{': '%7B',
1073
+ '}': '%7D',
1074
+ '\x7f': '%7F',
1075
+ '\x85': '%C2%85',
1076
+ '\xa0': '%C2%A0',
1077
+ '\u2028': '%E2%80%A8',
1078
+ '\u2029': '%E2%80%A9',
1079
+ '\uff01': '%EF%BC%81',
1080
+ '\uff03': '%EF%BC%83',
1081
+ '\uff04': '%EF%BC%84',
1082
+ '\uff06': '%EF%BC%86',
1083
+ '\uff07': '%EF%BC%87',
1084
+ '\uff08': '%EF%BC%88',
1085
+ '\uff09': '%EF%BC%89',
1086
+ '\uff0a': '%EF%BC%8A',
1087
+ '\uff0b': '%EF%BC%8B',
1088
+ '\uff0c': '%EF%BC%8C',
1089
+ '\uff0f': '%EF%BC%8F',
1090
+ '\uff1a': '%EF%BC%9A',
1091
+ '\uff1b': '%EF%BC%9B',
1092
+ '\uff1d': '%EF%BC%9D',
1093
+ '\uff1f': '%EF%BC%9F',
1094
+ '\uff20': '%EF%BC%A0',
1095
+ '\uff3b': '%EF%BC%BB',
1096
+ '\uff3d': '%EF%BC%BD'
1097
+ };
1098
+
1099
+ /**
1100
+ * A function that can be used with String.replace..
1101
+ * @param {string} ch A single character matched by a compatible matcher.
1102
+ * @return {string} A token in the output language.
1103
+ * @private
1104
+ */
1105
+ soy.esc.$$REPLACER_FOR_NORMALIZE_URI__AND__FILTER_NORMALIZE_URI_ = function(ch) {
1106
+ return soy.esc.$$ESCAPE_MAP_FOR_NORMALIZE_URI__AND__FILTER_NORMALIZE_URI_[ch];
1107
+ };
1108
+
1109
+ /**
1110
+ * Matches characters that need to be escaped for the named directives.
1111
+ * @type RegExp
1112
+ * @private
1113
+ */
1114
+ soy.esc.$$MATCHER_FOR_ESCAPE_HTML_ = /[\x00\x22\x26\x27\x3c\x3e]/g;
1115
+
1116
+ /**
1117
+ * Matches characters that need to be escaped for the named directives.
1118
+ * @type RegExp
1119
+ * @private
1120
+ */
1121
+ soy.esc.$$MATCHER_FOR_NORMALIZE_HTML_ = /[\x00\x22\x27\x3c\x3e]/g;
1122
+
1123
+ /**
1124
+ * Matches characters that need to be escaped for the named directives.
1125
+ * @type RegExp
1126
+ * @private
1127
+ */
1128
+ soy.esc.$$MATCHER_FOR_ESCAPE_HTML_NOSPACE_ = /[\x00\x09-\x0d \x22\x26\x27\x2d\/\x3c-\x3e`\x85\xa0\u2028\u2029]/g;
1129
+
1130
+ /**
1131
+ * Matches characters that need to be escaped for the named directives.
1132
+ * @type RegExp
1133
+ * @private
1134
+ */
1135
+ soy.esc.$$MATCHER_FOR_NORMALIZE_HTML_NOSPACE_ = /[\x00\x09-\x0d \x22\x27\x2d\/\x3c-\x3e`\x85\xa0\u2028\u2029]/g;
1136
+
1137
+ /**
1138
+ * Matches characters that need to be escaped for the named directives.
1139
+ * @type RegExp
1140
+ * @private
1141
+ */
1142
+ soy.esc.$$MATCHER_FOR_ESCAPE_JS_STRING_ = /[\x00\x08-\x0d\x22\x26\x27\/\x3c-\x3e\\\x85\u2028\u2029]/g;
1143
+
1144
+ /**
1145
+ * Matches characters that need to be escaped for the named directives.
1146
+ * @type RegExp
1147
+ * @private
1148
+ */
1149
+ soy.esc.$$MATCHER_FOR_ESCAPE_JS_REGEX_ = /[\x00\x08-\x0d\x22\x24\x26-\/\x3a\x3c-\x3f\x5b-\x5e\x7b-\x7d\x85\u2028\u2029]/g;
1150
+
1151
+ /**
1152
+ * Matches characters that need to be escaped for the named directives.
1153
+ * @type RegExp
1154
+ * @private
1155
+ */
1156
+ soy.esc.$$MATCHER_FOR_ESCAPE_CSS_STRING_ = /[\x00\x08-\x0d\x22\x26-\x2a\/\x3a-\x3e@\\\x7b\x7d\x85\xa0\u2028\u2029]/g;
1157
+
1158
+ /**
1159
+ * Matches characters that need to be escaped for the named directives.
1160
+ * @type RegExp
1161
+ * @private
1162
+ */
1163
+ soy.esc.$$MATCHER_FOR_NORMALIZE_URI__AND__FILTER_NORMALIZE_URI_ = /[\x00- \x22\x27-\x29\x3c\x3e\\\x7b\x7d\x7f\x85\xa0\u2028\u2029\uff01\uff03\uff04\uff06-\uff0c\uff0f\uff1a\uff1b\uff1d\uff1f\uff20\uff3b\uff3d]/g;
1164
+
1165
+ /**
1166
+ * A pattern that vets values produced by the named directives.
1167
+ * @type RegExp
1168
+ * @private
1169
+ */
1170
+ soy.esc.$$FILTER_FOR_FILTER_CSS_VALUE_ = /^(?!-*(?:expression|(?:moz-)?binding))(?:[.#]?-?(?:[_a-z0-9-]+)(?:-[_a-z0-9-]+)*-?|-?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)(?:[a-z]{1,2}|%)?|!important|)$/i;
1171
+
1172
+ /**
1173
+ * A pattern that vets values produced by the named directives.
1174
+ * @type RegExp
1175
+ * @private
1176
+ */
1177
+ soy.esc.$$FILTER_FOR_FILTER_NORMALIZE_URI_ = /^(?:(?:https?|mailto):|[^&:\/?#]*(?:[\/?#]|$))/i;
1178
+
1179
+ /**
1180
+ * A pattern that vets values produced by the named directives.
1181
+ * @type RegExp
1182
+ * @private
1183
+ */
1184
+ soy.esc.$$FILTER_FOR_FILTER_HTML_ATTRIBUTE_ = /^(?!style|on|action|archive|background|cite|classid|codebase|data|dsync|href|longdesc|src|usemap)(?:[a-z0-9_$:-]*)$/i;
1185
+
1186
+ /**
1187
+ * A pattern that vets values produced by the named directives.
1188
+ * @type RegExp
1189
+ * @private
1190
+ */
1191
+ soy.esc.$$FILTER_FOR_FILTER_HTML_ELEMENT_NAME_ = /^(?!script|style|title|textarea|xmp|no)[a-z0-9_$:-]*$/i;
1192
+
1193
+ /**
1194
+ * A helper for the Soy directive |escapeHtml
1195
+ * @param {*} value Can be of any type but will be coerced to a string.
1196
+ * @return {string} The escaped text.
1197
+ */
1198
+ soy.esc.$$escapeHtmlHelper = function(value) {
1199
+ var str = String(value);
1200
+ return str.replace(
1201
+ soy.esc.$$MATCHER_FOR_ESCAPE_HTML_,
1202
+ soy.esc.$$REPLACER_FOR_ESCAPE_HTML__AND__NORMALIZE_HTML__AND__ESCAPE_HTML_NOSPACE__AND__NORMALIZE_HTML_NOSPACE_);
1203
+ };
1204
+
1205
+ /**
1206
+ * A helper for the Soy directive |normalizeHtml
1207
+ * @param {*} value Can be of any type but will be coerced to a string.
1208
+ * @return {string} The escaped text.
1209
+ */
1210
+ soy.esc.$$normalizeHtmlHelper = function(value) {
1211
+ var str = String(value);
1212
+ return str.replace(
1213
+ soy.esc.$$MATCHER_FOR_NORMALIZE_HTML_,
1214
+ soy.esc.$$REPLACER_FOR_ESCAPE_HTML__AND__NORMALIZE_HTML__AND__ESCAPE_HTML_NOSPACE__AND__NORMALIZE_HTML_NOSPACE_);
1215
+ };
1216
+
1217
+ /**
1218
+ * A helper for the Soy directive |escapeHtmlNospace
1219
+ * @param {*} value Can be of any type but will be coerced to a string.
1220
+ * @return {string} The escaped text.
1221
+ */
1222
+ soy.esc.$$escapeHtmlNospaceHelper = function(value) {
1223
+ var str = String(value);
1224
+ return str.replace(
1225
+ soy.esc.$$MATCHER_FOR_ESCAPE_HTML_NOSPACE_,
1226
+ soy.esc.$$REPLACER_FOR_ESCAPE_HTML__AND__NORMALIZE_HTML__AND__ESCAPE_HTML_NOSPACE__AND__NORMALIZE_HTML_NOSPACE_);
1227
+ };
1228
+
1229
+ /**
1230
+ * A helper for the Soy directive |normalizeHtmlNospace
1231
+ * @param {*} value Can be of any type but will be coerced to a string.
1232
+ * @return {string} The escaped text.
1233
+ */
1234
+ soy.esc.$$normalizeHtmlNospaceHelper = function(value) {
1235
+ var str = String(value);
1236
+ return str.replace(
1237
+ soy.esc.$$MATCHER_FOR_NORMALIZE_HTML_NOSPACE_,
1238
+ soy.esc.$$REPLACER_FOR_ESCAPE_HTML__AND__NORMALIZE_HTML__AND__ESCAPE_HTML_NOSPACE__AND__NORMALIZE_HTML_NOSPACE_);
1239
+ };
1240
+
1241
+ /**
1242
+ * A helper for the Soy directive |escapeJsString
1243
+ * @param {*} value Can be of any type but will be coerced to a string.
1244
+ * @return {string} The escaped text.
1245
+ */
1246
+ soy.esc.$$escapeJsStringHelper = function(value) {
1247
+ var str = String(value);
1248
+ return str.replace(
1249
+ soy.esc.$$MATCHER_FOR_ESCAPE_JS_STRING_,
1250
+ soy.esc.$$REPLACER_FOR_ESCAPE_JS_STRING__AND__ESCAPE_JS_REGEX_);
1251
+ };
1252
+
1253
+ /**
1254
+ * A helper for the Soy directive |escapeJsRegex
1255
+ * @param {*} value Can be of any type but will be coerced to a string.
1256
+ * @return {string} The escaped text.
1257
+ */
1258
+ soy.esc.$$escapeJsRegexHelper = function(value) {
1259
+ var str = String(value);
1260
+ return str.replace(
1261
+ soy.esc.$$MATCHER_FOR_ESCAPE_JS_REGEX_,
1262
+ soy.esc.$$REPLACER_FOR_ESCAPE_JS_STRING__AND__ESCAPE_JS_REGEX_);
1263
+ };
1264
+
1265
+ /**
1266
+ * A helper for the Soy directive |escapeCssString
1267
+ * @param {*} value Can be of any type but will be coerced to a string.
1268
+ * @return {string} The escaped text.
1269
+ */
1270
+ soy.esc.$$escapeCssStringHelper = function(value) {
1271
+ var str = String(value);
1272
+ return str.replace(
1273
+ soy.esc.$$MATCHER_FOR_ESCAPE_CSS_STRING_,
1274
+ soy.esc.$$REPLACER_FOR_ESCAPE_CSS_STRING_);
1275
+ };
1276
+
1277
+ /**
1278
+ * A helper for the Soy directive |filterCssValue
1279
+ * @param {*} value Can be of any type but will be coerced to a string.
1280
+ * @return {string} The escaped text.
1281
+ */
1282
+ soy.esc.$$filterCssValueHelper = function(value) {
1283
+ var str = String(value);
1284
+ if (!soy.esc.$$FILTER_FOR_FILTER_CSS_VALUE_.test(str)) {
1285
+ goog.asserts.fail('Bad value `%s` for |filterCssValue', [str]);
1286
+ return 'zSoyz';
1287
+ }
1288
+ return str;
1289
+ };
1290
+
1291
+ /**
1292
+ * A helper for the Soy directive |normalizeUri
1293
+ * @param {*} value Can be of any type but will be coerced to a string.
1294
+ * @return {string} The escaped text.
1295
+ */
1296
+ soy.esc.$$normalizeUriHelper = function(value) {
1297
+ var str = String(value);
1298
+ return str.replace(
1299
+ soy.esc.$$MATCHER_FOR_NORMALIZE_URI__AND__FILTER_NORMALIZE_URI_,
1300
+ soy.esc.$$REPLACER_FOR_NORMALIZE_URI__AND__FILTER_NORMALIZE_URI_);
1301
+ };
1302
+
1303
+ /**
1304
+ * A helper for the Soy directive |filterNormalizeUri
1305
+ * @param {*} value Can be of any type but will be coerced to a string.
1306
+ * @return {string} The escaped text.
1307
+ */
1308
+ soy.esc.$$filterNormalizeUriHelper = function(value) {
1309
+ var str = String(value);
1310
+ if (!soy.esc.$$FILTER_FOR_FILTER_NORMALIZE_URI_.test(str)) {
1311
+ goog.asserts.fail('Bad value `%s` for |filterNormalizeUri', [str]);
1312
+ return 'zSoyz';
1313
+ }
1314
+ return str.replace(
1315
+ soy.esc.$$MATCHER_FOR_NORMALIZE_URI__AND__FILTER_NORMALIZE_URI_,
1316
+ soy.esc.$$REPLACER_FOR_NORMALIZE_URI__AND__FILTER_NORMALIZE_URI_);
1317
+ };
1318
+
1319
+ /**
1320
+ * A helper for the Soy directive |filterHtmlAttribute
1321
+ * @param {*} value Can be of any type but will be coerced to a string.
1322
+ * @return {string} The escaped text.
1323
+ */
1324
+ soy.esc.$$filterHtmlAttributeHelper = function(value) {
1325
+ var str = String(value);
1326
+ if (!soy.esc.$$FILTER_FOR_FILTER_HTML_ATTRIBUTE_.test(str)) {
1327
+ goog.asserts.fail('Bad value `%s` for |filterHtmlAttribute', [str]);
1328
+ return 'zSoyz';
1329
+ }
1330
+ return str;
1331
+ };
1332
+
1333
+ /**
1334
+ * A helper for the Soy directive |filterHtmlElementName
1335
+ * @param {*} value Can be of any type but will be coerced to a string.
1336
+ * @return {string} The escaped text.
1337
+ */
1338
+ soy.esc.$$filterHtmlElementNameHelper = function(value) {
1339
+ var str = String(value);
1340
+ if (!soy.esc.$$FILTER_FOR_FILTER_HTML_ELEMENT_NAME_.test(str)) {
1341
+ goog.asserts.fail('Bad value `%s` for |filterHtmlElementName', [str]);
1342
+ return 'zSoyz';
1343
+ }
1344
+ return str;
1345
+ };
1346
+
1347
+ /**
1348
+ * Matches all tags, HTML comments, and DOCTYPEs in tag soup HTML.
1349
+ *
1350
+ * @type {RegExp}
1351
+ * @private
1352
+ */
1353
+ soy.esc.$$HTML_TAG_REGEX_ = /<(?:!|\/?[a-zA-Z])(?:[^>'"]|"[^"]*"|'[^']*')*>/g;
1354
+
1355
+ // END GENERATED CODE