Subversion Repositories Applications.papyrus

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2150 mathias 1
if(!dojo._hasResource["dijit._Templated"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2
dojo._hasResource["dijit._Templated"] = true;
3
dojo.provide("dijit._Templated");
4
 
5
dojo.require("dijit._Widget");
6
 
7
dojo.require("dojo.string");
8
dojo.require("dojo.parser");
9
 
10
dojo.declare("dijit._Templated",
11
	null,
12
	{
13
		// summary:
14
		//		mixin for widgets that are instantiated from a template
15
 
16
		// templateNode: DomNode
17
		//		a node that represents the widget template. Pre-empts both templateString and templatePath.
18
		templateNode: null,
19
 
20
		// templateString String:
21
		//		a string that represents the widget template. Pre-empts the
22
		//		templatePath. In builds that have their strings "interned", the
23
		//		templatePath is converted to an inline templateString, thereby
24
		//		preventing a synchronous network call.
25
		templateString: null,
26
 
27
		// templatePath: String
28
		//	Path to template (HTML file) for this widget
29
		templatePath: null,
30
 
31
		// widgetsInTemplate Boolean:
32
		//		should we parse the template to find widgets that might be
33
		//		declared in markup inside it? false by default.
34
		widgetsInTemplate: false,
35
 
36
		// containerNode DomNode:
37
		//		holds child elements. "containerNode" is generally set via a
38
		//		dojoAttachPoint assignment and it designates where children of
39
		//		the src dom node will be placed
40
		containerNode: null,
41
 
42
		// skipNodeCache Boolean:
43
		//		if using a cached widget template node poses issues for a
44
		//		particular widget class, it can set this property to ensure
45
		//		that its template is always re-built from a string
46
		_skipNodeCache: false,
47
 
48
		// method over-ride
49
		buildRendering: function(){
50
			// summary:
51
			//		Construct the UI for this widget from a template, setting this.domNode.
52
 
53
			// Lookup cached version of template, and download to cache if it
54
			// isn't there already.  Returns either a DomNode or a string, depending on
55
			// whether or not the template contains ${foo} replacement parameters.
56
			var cached = dijit._Templated.getCachedTemplate(this.templatePath, this.templateString, this._skipNodeCache);
57
 
58
			var node;
59
			if(dojo.isString(cached)){
60
				var className = this.declaredClass, _this = this;
61
				// Cache contains a string because we need to do property replacement
62
				// do the property replacement
63
				var tstr = dojo.string.substitute(cached, this, function(value, key){
64
					if(key.charAt(0) == '!'){ value = _this[key.substr(1)]; }
65
					if(typeof value == "undefined"){ throw new Error(className+" template:"+key); } // a debugging aide
66
					if(!value){ return ""; }
67
 
68
					// Substitution keys beginning with ! will skip the transform step,
69
					// in case a user wishes to insert unescaped markup, e.g. ${!foo}
70
					return key.charAt(0) == "!" ? value :
71
						// Safer substitution, see heading "Attribute values" in
72
						// http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2
73
						value.toString().replace(/"/g,"""); //TODO: add &amp? use encodeXML method?
74
				}, this);
75
 
76
				node = dijit._Templated._createNodesFromText(tstr)[0];
77
			}else{
78
				// if it's a node, all we have to do is clone it
79
				node = cached.cloneNode(true);
80
			}
81
 
82
			// recurse through the node, looking for, and attaching to, our
83
			// attachment points which should be defined on the template node.
84
			this._attachTemplateNodes(node);
85
 
86
			var source = this.srcNodeRef;
87
			if(source && source.parentNode){
88
				source.parentNode.replaceChild(node, source);
89
			}
90
 
91
			this.domNode = node;
92
			if(this.widgetsInTemplate){
93
				var childWidgets = dojo.parser.parse(node);
94
				this._attachTemplateNodes(childWidgets, function(n,p){
95
					return n[p];
96
				});
97
			}
98
 
99
			this._fillContent(source);
100
		},
101
 
102
		_fillContent: function(/*DomNode*/ source){
103
			// summary:
104
			//		relocate source contents to templated container node
105
			//		this.containerNode must be able to receive children, or exceptions will be thrown
106
			var dest = this.containerNode;
107
			if(source && dest){
108
				while(source.hasChildNodes()){
109
					dest.appendChild(source.firstChild);
110
				}
111
			}
112
		},
113
 
114
		_attachTemplateNodes: function(rootNode, getAttrFunc){
115
			// summary:
116
			//		map widget properties and functions to the handlers specified in
117
			//		the dom node and it's descendants. This function iterates over all
118
			//		nodes and looks for these properties:
119
			//			* dojoAttachPoint
120
			//			* dojoAttachEvent
121
			//			* waiRole
122
			//			* waiState
123
			// rootNode: DomNode|Array[Widgets]
124
			//		the node to search for properties. All children will be searched.
125
			// getAttrFunc: function?
126
			//		a function which will be used to obtain property for a given
127
			//		DomNode/Widget
128
 
129
			getAttrFunc = getAttrFunc || function(n,p){ return n.getAttribute(p); };
130
 
131
			var nodes = dojo.isArray(rootNode) ? rootNode : (rootNode.all || rootNode.getElementsByTagName("*"));
132
			var x=dojo.isArray(rootNode)?0:-1;
133
			for(; x<nodes.length; x++){
134
				var baseNode = (x == -1) ? rootNode : nodes[x];
135
				if(this.widgetsInTemplate && getAttrFunc(baseNode,'dojoType')){
136
					continue;
137
				}
138
				// Process dojoAttachPoint
139
				var attachPoint = getAttrFunc(baseNode, "dojoAttachPoint");
140
				if(attachPoint){
141
					var point, points = attachPoint.split(/\s*,\s*/);
142
					while(point=points.shift()){
143
						if(dojo.isArray(this[point])){
144
							this[point].push(baseNode);
145
						}else{
146
							this[point]=baseNode;
147
						}
148
					}
149
				}
150
 
151
				// Process dojoAttachEvent
152
				var attachEvent = getAttrFunc(baseNode, "dojoAttachEvent");
153
				if(attachEvent){
154
					// NOTE: we want to support attributes that have the form
155
					// "domEvent: nativeEvent; ..."
156
					var event, events = attachEvent.split(/\s*,\s*/);
157
					var trim = dojo.trim;
158
					while(event=events.shift()){
159
						if(event){
160
							var thisFunc = null;
161
							if(event.indexOf(":") != -1){
162
								// oh, if only JS had tuple assignment
163
								var funcNameArr = event.split(":");
164
								event = trim(funcNameArr[0]);
165
								thisFunc = trim(funcNameArr[1]);
166
							}else{
167
								event = trim(event);
168
							}
169
							if(!thisFunc){
170
								thisFunc = event;
171
							}
172
							this.connect(baseNode, event, thisFunc);
173
						}
174
					}
175
				}
176
 
177
				// waiRole, waiState
178
				var role = getAttrFunc(baseNode, "waiRole");
179
				if(role){
180
					dijit.setWaiRole(baseNode, role);
181
				}
182
				var values = getAttrFunc(baseNode, "waiState");
183
				if(values){
184
					dojo.forEach(values.split(/\s*,\s*/), function(stateValue){
185
						if(stateValue.indexOf('-') != -1){
186
							var pair = stateValue.split('-');
187
							dijit.setWaiState(baseNode, pair[0], pair[1]);
188
						}
189
					});
190
				}
191
 
192
			}
193
		}
194
	}
195
);
196
 
197
// key is either templatePath or templateString; object is either string or DOM tree
198
dijit._Templated._templateCache = {};
199
 
200
dijit._Templated.getCachedTemplate = function(templatePath, templateString, alwaysUseString){
201
	// summary:
202
	//		static method to get a template based on the templatePath or
203
	//		templateString key
204
	// templatePath: String
205
	//		the URL to get the template from. dojo.uri.Uri is often passed as well.
206
	// templateString: String?
207
	//		a string to use in lieu of fetching the template from a URL
208
	// Returns:
209
	//	Either string (if there are ${} variables that need to be replaced) or just
210
	//	a DOM tree (if the node can be cloned directly)
211
 
212
	// is it already cached?
213
	var tmplts = dijit._Templated._templateCache;
214
	var key = templateString || templatePath;
215
	var cached = tmplts[key];
216
	if(cached){
217
		return cached;
218
	}
219
 
220
	// If necessary, load template string from template path
221
	if(!templateString){
222
		templateString = dijit._Templated._sanitizeTemplateString(dojo._getText(templatePath));
223
	}
224
 
225
	templateString = dojo.string.trim(templateString);
226
 
227
	if(templateString.match(/\$\{([^\}]+)\}/g) || alwaysUseString){
228
		// there are variables in the template so all we can do is cache the string
229
		return (tmplts[key] = templateString); //String
230
	}else{
231
		// there are no variables in the template so we can cache the DOM tree
232
		return (tmplts[key] = dijit._Templated._createNodesFromText(templateString)[0]); //Node
233
	}
234
};
235
 
236
dijit._Templated._sanitizeTemplateString = function(/*String*/tString){
237
	// summary:
238
	//		Strips <?xml ...?> declarations so that external SVG and XML
239
	// 		documents can be added to a document without worry. Also, if the string
240
	//		is an HTML document, only the part inside the body tag is returned.
241
	if(tString){
242
		tString = tString.replace(/^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, "");
243
		var matches = tString.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
244
		if(matches){
245
			tString = matches[1];
246
		}
247
	}else{
248
		tString = "";
249
	}
250
	return tString; //String
251
};
252
 
253
 
254
if(dojo.isIE){
255
	dojo.addOnUnload(function(){
256
		var cache = dijit._Templated._templateCache;
257
		for(var key in cache){
258
			var value = cache[key];
259
			if(!isNaN(value.nodeType)){ // isNode equivalent
260
				dojo._destroyElement(value);
261
			}
262
			delete cache[key];
263
		}
264
	});
265
}
266
 
267
(function(){
268
	var tagMap = {
269
		cell: {re: /^<t[dh][\s\r\n>]/i, pre: "<table><tbody><tr>", post: "</tr></tbody></table>"},
270
		row: {re: /^<tr[\s\r\n>]/i, pre: "<table><tbody>", post: "</tbody></table>"},
271
		section: {re: /^<(thead|tbody|tfoot)[\s\r\n>]/i, pre: "<table>", post: "</table>"}
272
	};
273
 
274
	// dummy container node used temporarily to hold nodes being created
275
	var tn;
276
 
277
	dijit._Templated._createNodesFromText = function(/*String*/text){
278
		// summary:
279
		//	Attempts to create a set of nodes based on the structure of the passed text.
280
 
281
		if(!tn){
282
			tn = dojo.doc.createElement("div");
283
			tn.style.display="none";
284
			dojo.body().appendChild(tn);
285
		}
286
		var tableType = "none";
287
		var rtext = text.replace(/^\s+/, "");
288
		for(var type in tagMap){
289
			var map = tagMap[type];
290
			if(map.re.test(rtext)){
291
				tableType = type;
292
				text = map.pre + text + map.post;
293
				break;
294
			}
295
		}
296
 
297
		tn.innerHTML = text;
298
		if(tn.normalize){
299
			tn.normalize();
300
		}
301
 
302
		var tag = { cell: "tr", row: "tbody", section: "table" }[tableType];
303
		var _parent = (typeof tag != "undefined") ?
304
						tn.getElementsByTagName(tag)[0] :
305
						tn;
306
 
307
		var nodes = [];
308
		while(_parent.firstChild){
309
			nodes.push(_parent.removeChild(_parent.firstChild));
310
		}
311
		tn.innerHTML="";
312
		return nodes;	//	Array
313
	}
314
})();
315
 
316
// These arguments can be specified for widgets which are used in templates.
317
// Since any widget can be specified as sub widgets in template, mix it
318
// into the base widget class.  (This is a hack, but it's effective.)
319
dojo.extend(dijit._Widget,{
320
	dojoAttachEvent: "",
321
	dojoAttachPoint: "",
322
	waiRole: "",
323
	waiState:""
324
})
325
 
326
}