Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/closure/goog/soy/renderer.js
2868 views
1
// Copyright 2010 The Closure Library Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS-IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
/**
16
* @fileoverview Provides a soy renderer that allows registration of
17
* injected data ("globals") that will be passed into the rendered
18
* templates.
19
*
20
* There is also an interface {@link goog.soy.InjectedDataSupplier} that
21
* user should implement to provide the injected data for a specific
22
* application. The injected data format is a JavaScript object:
23
* <pre>
24
* {'dataKey': 'value', 'otherDataKey': 'otherValue'}
25
* </pre>
26
*
27
* The injected data can then be referred to in any soy templates as
28
* part of a magic "ij" parameter. For example, {@code $ij.dataKey}
29
* will evaluate to 'value' with the above injected data.
30
*
31
* @author [email protected] (Henry Wong)
32
* @author [email protected] (Chris Henry)
33
*/
34
35
goog.provide('goog.soy.InjectedDataSupplier');
36
goog.provide('goog.soy.Renderer');
37
38
goog.require('goog.asserts');
39
goog.require('goog.dom');
40
goog.require('goog.html.uncheckedconversions');
41
goog.require('goog.soy');
42
goog.require('goog.soy.data.SanitizedContent');
43
goog.require('goog.soy.data.SanitizedContentKind');
44
goog.require('goog.string.Const');
45
46
47
48
/**
49
* Creates a new soy renderer. Note that the renderer will only be
50
* guaranteed to work correctly within the document scope provided in
51
* the DOM helper.
52
*
53
* @param {goog.soy.InjectedDataSupplier=} opt_injectedDataSupplier A supplier
54
* that provides an injected data.
55
* @param {goog.dom.DomHelper=} opt_domHelper Optional DOM helper;
56
* defaults to that provided by {@code goog.dom.getDomHelper()}.
57
* @constructor
58
*/
59
goog.soy.Renderer = function(opt_injectedDataSupplier, opt_domHelper) {
60
/**
61
* @type {goog.dom.DomHelper}
62
* @private
63
*/
64
this.dom_ = opt_domHelper || goog.dom.getDomHelper();
65
66
/**
67
* @type {goog.soy.InjectedDataSupplier}
68
* @private
69
*/
70
this.supplier_ = opt_injectedDataSupplier || null;
71
72
/**
73
* Map from template name to the data used to render that template.
74
* @type {!goog.soy.Renderer.SavedTemplateRender}
75
* @private
76
*/
77
this.savedTemplateRenders_ = [];
78
};
79
80
81
/**
82
* @typedef {Array<{template: string, data: Object, ijData: Object}>}
83
*/
84
goog.soy.Renderer.SavedTemplateRender;
85
86
87
/**
88
* Renders a Soy template into a single node or a document fragment.
89
* Delegates to {@code goog.soy.renderAsFragment}.
90
*
91
* @param {?function(ARG_TYPES, Object<string, *>=):*|
92
* ?function(ARG_TYPES, null=, Object<string, *>=):*} template
93
* The Soy template defining the element's content.
94
* @param {ARG_TYPES=} opt_templateData The data for the template.
95
* @return {!Node} The resulting node or document fragment.
96
* @template ARG_TYPES
97
*/
98
goog.soy.Renderer.prototype.renderAsFragment = function(
99
template, opt_templateData) {
100
this.saveTemplateRender_(template, opt_templateData);
101
var node = goog.soy.renderAsFragment(
102
template, opt_templateData, this.getInjectedData_(), this.dom_);
103
this.handleRender(node);
104
return node;
105
};
106
107
108
/**
109
* Renders a Soy template into a single node. If the rendered HTML
110
* string represents a single node, then that node is returned.
111
* Otherwise, a DIV element is returned containing the rendered nodes.
112
* Delegates to {@code goog.soy.renderAsElement}.
113
*
114
* @param {?function(ARG_TYPES, Object<string, *>=):*|
115
* ?function(ARG_TYPES, null=, Object<string, *>=):*} template
116
* The Soy template defining the element's content.
117
* @param {ARG_TYPES=} opt_templateData The data for the template.
118
* @return {!Element} Rendered template contents, wrapped in a parent DIV
119
* element if necessary.
120
* @template ARG_TYPES
121
*/
122
goog.soy.Renderer.prototype.renderAsElement = function(
123
template, opt_templateData) {
124
this.saveTemplateRender_(template, opt_templateData);
125
var element = goog.soy.renderAsElement(
126
template, opt_templateData, this.getInjectedData_(), this.dom_);
127
this.handleRender(element);
128
return element;
129
};
130
131
132
/**
133
* Renders a Soy template and then set the output string as the
134
* innerHTML of the given element. Delegates to {@code goog.soy.renderElement}.
135
*
136
* @param {Element} element The element whose content we are rendering.
137
* @param {?function(ARG_TYPES, Object<string, *>=):*|
138
* ?function(ARG_TYPES, null=, Object<string, *>=):*} template
139
* The Soy template defining the element's content.
140
* @param {ARG_TYPES=} opt_templateData The data for the template.
141
* @template ARG_TYPES
142
*/
143
goog.soy.Renderer.prototype.renderElement = function(
144
element, template, opt_templateData) {
145
this.saveTemplateRender_(template, opt_templateData);
146
goog.soy.renderElement(
147
element, template, opt_templateData, this.getInjectedData_());
148
this.handleRender(element);
149
};
150
151
152
/**
153
* Renders a Soy template and returns the output string.
154
* If the template is strict, it must be of kind HTML. To render strict
155
* templates of other kinds, use {@code renderText} (for {@code kind="text"}) or
156
* {@code renderStrictOfKind}.
157
*
158
* @param {?function(ARG_TYPES, Object<string, *>=):*|
159
* ?function(ARG_TYPES, null=, Object<string, *>=):*} template
160
* The Soy template to render.
161
* @param {ARG_TYPES=} opt_templateData The data for the template.
162
* @return {string} The return value of rendering the template directly.
163
* @template ARG_TYPES
164
*/
165
goog.soy.Renderer.prototype.render = function(template, opt_templateData) {
166
var result =
167
template(opt_templateData || {}, undefined, this.getInjectedData_());
168
goog.asserts.assert(
169
!(result instanceof goog.soy.data.SanitizedContent) ||
170
result.contentKind === goog.soy.data.SanitizedContentKind.HTML,
171
'render was called with a strict template of kind other than "html"' +
172
' (consider using renderText or renderStrict)');
173
this.saveTemplateRender_(template, opt_templateData);
174
this.handleRender();
175
return String(result);
176
};
177
178
179
/**
180
* Renders a strict Soy template of kind="text" and returns the output string.
181
* It is an error to use renderText on non-strict templates, or strict templates
182
* of kinds other than "text".
183
*
184
* @param {?function(ARG_TYPES, Object<string, *>=):?goog.soy.data.UnsanitizedText|
185
* ?function(ARG_TYPES, null=, Object<string, *>=):
186
* ?goog.soy.data.UnsanitizedText} template The Soy template to render.
187
* @param {ARG_TYPES=} opt_templateData The data for the template.
188
* @return {string} The return value of rendering the template directly.
189
* @template ARG_TYPES
190
*/
191
goog.soy.Renderer.prototype.renderText = function(template, opt_templateData) {
192
var result =
193
template(opt_templateData || {}, undefined, this.getInjectedData_());
194
goog.asserts.assertInstanceof(
195
result, goog.soy.data.SanitizedContent,
196
'renderText cannot be called on a non-strict soy template');
197
goog.asserts.assert(
198
result.contentKind === goog.soy.data.SanitizedContentKind.TEXT,
199
'renderText was called with a template of kind other than "text"');
200
this.saveTemplateRender_(template, opt_templateData);
201
this.handleRender();
202
return String(result);
203
};
204
205
206
/**
207
* Renders a strict Soy HTML template and returns the output SanitizedHtml
208
* object.
209
* @param {?function(ARG_TYPES, Object<string, *>=):!goog.soy.data.SanitizedHtml|
210
* ?function(ARG_TYPES, null=, Object<string, *>=):
211
* !goog.soy.data.SanitizedHtml} template The Soy template to render.
212
* @param {ARG_TYPES=} opt_templateData The data for the template.
213
* @return {!goog.soy.data.SanitizedHtml}
214
* @template ARG_TYPES
215
*/
216
goog.soy.Renderer.prototype.renderStrict = function(
217
template, opt_templateData) {
218
return this.renderStrictOfKind(
219
template, opt_templateData, goog.soy.data.SanitizedContentKind.HTML);
220
};
221
222
223
/**
224
* Renders a strict Soy template and returns the output SanitizedUri object.
225
*
226
* @param {!function(ARG_TYPES, ?Object<string, *>=):!goog.soy.data.SanitizedUri|
227
* !function(ARG_TYPES, null=, ?Object<string, *>=):
228
* !goog.soy.data.SanitizedUri} template The Soy template to render.
229
* @param {ARG_TYPES=} opt_templateData The data for the template.
230
* @return {!goog.soy.data.SanitizedUri}
231
* @template ARG_TYPES
232
*/
233
goog.soy.Renderer.prototype.renderStrictUri = function(
234
template, opt_templateData) {
235
return this.renderStrictOfKind(
236
template, opt_templateData, goog.soy.data.SanitizedContentKind.URI);
237
};
238
239
240
/**
241
* Renders a strict Soy template and returns the output SanitizedContent object.
242
*
243
* @param {?function(ARG_TYPES, ?Object<string, *>=): RETURN_TYPE|
244
* ?function(ARG_TYPES, null=, ?Object<string, *>=): RETURN_TYPE}
245
* template The Soy template to render.
246
* @param {ARG_TYPES=} opt_templateData The data for the template.
247
* @param {goog.soy.data.SanitizedContentKind=} opt_kind The output kind to
248
* assert. If null, the template must be of kind="html" (i.e., opt_kind
249
* defaults to goog.soy.data.SanitizedContentKind.HTML).
250
* @return {RETURN_TYPE} The SanitizedContent object. This return type is
251
* generic based on the return type of the template, such as
252
* goog.soy.data.SanitizedHtml.
253
* @template ARG_TYPES, RETURN_TYPE
254
*/
255
goog.soy.Renderer.prototype.renderStrictOfKind = function(
256
template, opt_templateData, opt_kind) {
257
var result =
258
template(opt_templateData || {}, undefined, this.getInjectedData_());
259
goog.asserts.assertInstanceof(
260
result, goog.soy.data.SanitizedContent,
261
'renderStrict cannot be called on a non-strict soy template');
262
goog.asserts.assert(
263
result.contentKind ===
264
(opt_kind || goog.soy.data.SanitizedContentKind.HTML),
265
'renderStrict was called with the wrong kind of template');
266
this.saveTemplateRender_(template, opt_templateData);
267
this.handleRender();
268
return result;
269
};
270
271
272
/**
273
* Renders a strict Soy template of kind="html" and returns the result as
274
* a goog.html.SafeHtml object.
275
*
276
* Rendering a template that is not a strict template of kind="html" results in
277
* a runtime error.
278
*
279
* @param {?function(ARG_TYPES, Object<string, *>=): !goog.soy.data.SanitizedHtml|
280
* ?function(ARG_TYPES, null=, Object<string, *>=):
281
* !goog.soy.data.SanitizedHtml} template The Soy template to render.
282
* @param {ARG_TYPES=} opt_templateData The data for the template.
283
* @return {!goog.html.SafeHtml}
284
* @template ARG_TYPES
285
*/
286
goog.soy.Renderer.prototype.renderSafeHtml = function(
287
template, opt_templateData) {
288
var result = this.renderStrict(template, opt_templateData);
289
// Convert from SanitizedHtml to SafeHtml.
290
return result.toSafeHtml();
291
};
292
293
294
/**
295
* Renders a strict Soy template of kind="css" and returns the result as
296
* a goog.html.SafeStyleSheet object.
297
*
298
* Rendering a template that is not a strict template of kind="css" results in
299
* a runtime and compile-time error.
300
*
301
* @param {?function(ARG_TYPES, Object<string, *>=): !goog.soy.data.SanitizedCss|
302
* ?function(ARG_TYPES, null=, Object<string, *>=):
303
* !goog.soy.data.SanitizedCss} template The Soy template to render.
304
* @param {ARG_TYPES=} opt_templateData The data for the template.
305
* @return {!goog.html.SafeStyleSheet}
306
* @template ARG_TYPES
307
*/
308
goog.soy.Renderer.prototype.renderSafeStyleSheet = function(
309
template, opt_templateData) {
310
var result = this.renderStrictOfKind(
311
template, opt_templateData, goog.soy.data.SanitizedContentKind.CSS);
312
// TODO(mlourenco): Call result.toSafeStyleSheet() once that exists.
313
return goog.html.uncheckedconversions
314
.safeStyleSheetFromStringKnownToSatisfyTypeContract(
315
goog.string.Const.from(
316
'Soy templates of kind CSS produce ' +
317
'SafeStyleSheet-contract-compliant value.'),
318
result.toString());
319
};
320
321
322
/**
323
* @return {!goog.soy.Renderer.SavedTemplateRender} Saved template data for
324
* the renders that have happened so far.
325
*/
326
goog.soy.Renderer.prototype.getSavedTemplateRenders = function() {
327
return this.savedTemplateRenders_;
328
};
329
330
331
/**
332
* Observes rendering of templates by this renderer.
333
* @param {Node=} opt_node Relevant node, if available. The node may or may
334
* not be in the document, depending on whether Soy is creating an element
335
* or writing into an existing one.
336
* @protected
337
*/
338
goog.soy.Renderer.prototype.handleRender = goog.nullFunction;
339
340
341
/**
342
* Saves information about the current template render for debug purposes.
343
* @param {Function} template The Soy template defining the element's content.
344
* @param {Object=} opt_templateData The data for the template.
345
* @private
346
* @suppress {missingProperties} SoyJs compiler adds soyTemplateName to the
347
* template.
348
*/
349
goog.soy.Renderer.prototype.saveTemplateRender_ = function(
350
template, opt_templateData) {
351
if (goog.DEBUG) {
352
this.savedTemplateRenders_.push({
353
template: template.soyTemplateName,
354
data: opt_templateData || null,
355
ijData: this.getInjectedData_()
356
});
357
}
358
};
359
360
361
/**
362
* Creates the injectedParams map if necessary and calls the configuration
363
* service to prepopulate it.
364
* @return {Object} The injected params.
365
* @private
366
*/
367
goog.soy.Renderer.prototype.getInjectedData_ = function() {
368
return this.supplier_ ? this.supplier_.getData() : {};
369
};
370
371
372
373
/**
374
* An interface for a supplier that provides Soy injected data.
375
* @interface
376
*/
377
goog.soy.InjectedDataSupplier = function() {};
378
379
380
/**
381
* Gets the injected data. Implementation may assume that
382
* {@code goog.soy.Renderer} will treat the returned data as
383
* immutable. The renderer will call this every time one of its
384
* {@code render*} methods is called.
385
* @return {Object} A key-value pair representing the injected data.
386
*/
387
goog.soy.InjectedDataSupplier.prototype.getData = function() {};
388
389