| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304 | define("dijit/_TemplatedMixin", [	"dojo/_base/lang", // lang.getObject	"dojo/touch",	"./_WidgetBase",	"dojo/string", // string.substitute string.trim	"dojo/cache",	// dojo.cache	"dojo/_base/array", // array.forEach	"dojo/_base/declare", // declare	"dojo/dom-construct", // domConstruct.destroy, domConstruct.toDom	"dojo/_base/sniff", // has("ie")	"dojo/_base/unload", // unload.addOnWindowUnload	"dojo/_base/window" // win.doc], function(lang, touch, _WidgetBase, string, cache, array, declare, domConstruct, has, unload, win) {/*=====	var _WidgetBase = dijit._WidgetBase;=====*/	// module:	//		dijit/_TemplatedMixin	// summary:	//		Mixin for widgets that are instantiated from a template	var _TemplatedMixin = declare("dijit._TemplatedMixin", null, {		// summary:		//		Mixin for widgets that are instantiated from a template		// templateString: [protected] String		//		A string that represents the widget template.		//		Use in conjunction with dojo.cache() to load from a file.		templateString: null,		// templatePath: [protected deprecated] String		//		Path to template (HTML file) for this widget relative to dojo.baseUrl.		//		Deprecated: use templateString with require([... "dojo/text!..."], ...) instead		templatePath: null,		// skipNodeCache: [protected] Boolean		//		If using a cached widget template nodes poses issues for a		//		particular widget class, it can set this property to ensure		//		that its template is always re-built from a string		_skipNodeCache: false,		// _earlyTemplatedStartup: Boolean		//		A fallback to preserve the 1.0 - 1.3 behavior of children in		//		templates having their startup called before the parent widget		//		fires postCreate. Defaults to 'false', causing child widgets to		//		have their .startup() called immediately before a parent widget		//		.startup(), but always after the parent .postCreate(). Set to		//		'true' to re-enable to previous, arguably broken, behavior.		_earlyTemplatedStartup: false,/*=====		// _attachPoints: [private] String[]		//		List of widget attribute names associated with data-dojo-attach-point=... in the		//		template, ex: ["containerNode", "labelNode"] 		_attachPoints: [], =====*//*=====		// _attachEvents: [private] Handle[]		//		List of connections associated with data-dojo-attach-event=... in the		//		template 		_attachEvents: [], =====*/		constructor: function(){			this._attachPoints = [];			this._attachEvents = [];		},		_stringRepl: function(tmpl){			// summary:			//		Does substitution of ${foo} type properties in template string			// tags:			//		private			var className = this.declaredClass, _this = this;			// Cache contains a string because we need to do property replacement			// do the property replacement			return string.substitute(tmpl, this, function(value, key){				if(key.charAt(0) == '!'){ value = lang.getObject(key.substr(1), false, _this); }				if(typeof value == "undefined"){ throw new Error(className+" template:"+key); } // a debugging aide				if(value == null){ return ""; }				// Substitution keys beginning with ! will skip the transform step,				// in case a user wishes to insert unescaped markup, e.g. ${!foo}				return key.charAt(0) == "!" ? value :					// Safer substitution, see heading "Attribute values" in					// http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2					value.toString().replace(/"/g,"""); //TODO: add &? use encodeXML method?			}, this);		},		buildRendering: function(){			// summary:			//		Construct the UI for this widget from a template, setting this.domNode.			// tags:			//		protected			if(!this.templateString){				this.templateString = cache(this.templatePath, {sanitize: true});			}			// Lookup cached version of template, and download to cache if it			// isn't there already.  Returns either a DomNode or a string, depending on			// whether or not the template contains ${foo} replacement parameters.			var cached = _TemplatedMixin.getCachedTemplate(this.templateString, this._skipNodeCache);			var node;			if(lang.isString(cached)){				node = domConstruct.toDom(this._stringRepl(cached));				if(node.nodeType != 1){					// Flag common problems such as templates with multiple top level nodes (nodeType == 11)					throw new Error("Invalid template: " + cached);				}			}else{				// if it's a node, all we have to do is clone it				node = cached.cloneNode(true);			}			this.domNode = node;			// Call down to _Widget.buildRendering() to get base classes assigned			// TODO: change the baseClass assignment to _setBaseClassAttr			this.inherited(arguments);			// recurse through the node, looking for, and attaching to, our			// attachment points and events, which should be defined on the template node.			this._attachTemplateNodes(node, function(n,p){ return n.getAttribute(p); });			this._beforeFillContent();		// hook for _WidgetsInTemplateMixin			this._fillContent(this.srcNodeRef);		},		_beforeFillContent: function(){		},		_fillContent: function(/*DomNode*/ source){			// summary:			//		Relocate source contents to templated container node.			//		this.containerNode must be able to receive children, or exceptions will be thrown.			// tags:			//		protected			var dest = this.containerNode;			if(source && dest){				while(source.hasChildNodes()){					dest.appendChild(source.firstChild);				}			}		},		_attachTemplateNodes: function(rootNode, getAttrFunc){			// summary:			//		Iterate through the template and attach functions and nodes accordingly.			//		Alternately, if rootNode is an array of widgets, then will process data-dojo-attach-point			//		etc. for those widgets.			// description:			//		Map widget properties and functions to the handlers specified in			//		the dom node and it's descendants. This function iterates over all			//		nodes and looks for these properties:			//			* dojoAttachPoint/data-dojo-attach-point			//			* dojoAttachEvent/data-dojo-attach-event			// rootNode: DomNode|Widget[]			//		the node to search for properties. All children will be searched.			// getAttrFunc: Function			//		a function which will be used to obtain property for a given			//		DomNode/Widget			// tags:			//		private			var nodes = lang.isArray(rootNode) ? rootNode : (rootNode.all || rootNode.getElementsByTagName("*"));			var x = lang.isArray(rootNode) ? 0 : -1;			for(; x<nodes.length; x++){				var baseNode = (x == -1) ? rootNode : nodes[x];				if(this.widgetsInTemplate && (getAttrFunc(baseNode, "dojoType") || getAttrFunc(baseNode, "data-dojo-type"))){					continue;				}				// Process data-dojo-attach-point				var attachPoint = getAttrFunc(baseNode, "dojoAttachPoint") || getAttrFunc(baseNode, "data-dojo-attach-point");				if(attachPoint){					var point, points = attachPoint.split(/\s*,\s*/);					while((point = points.shift())){						if(lang.isArray(this[point])){							this[point].push(baseNode);						}else{							this[point]=baseNode;						}						this._attachPoints.push(point);					}				}				// Process data-dojo-attach-event				var attachEvent = getAttrFunc(baseNode, "dojoAttachEvent") || getAttrFunc(baseNode, "data-dojo-attach-event");				if(attachEvent){					// NOTE: we want to support attributes that have the form					// "domEvent: nativeEvent; ..."					var event, events = attachEvent.split(/\s*,\s*/);					var trim = lang.trim;					while((event = events.shift())){						if(event){							var thisFunc = null;							if(event.indexOf(":") != -1){								// oh, if only JS had tuple assignment								var funcNameArr = event.split(":");								event = trim(funcNameArr[0]);								thisFunc = trim(funcNameArr[1]);							}else{								event = trim(event);							}							if(!thisFunc){								thisFunc = event;							}							// Map "press", "move" and "release" to keys.touch, keys.move, keys.release							this._attachEvents.push(this.connect(baseNode, touch[event] || event, thisFunc));						}					}				}			}		},		destroyRendering: function(){			// Delete all attach points to prevent IE6 memory leaks.			array.forEach(this._attachPoints, function(point){				delete this[point];			}, this);			this._attachPoints = [];			// And same for event handlers			array.forEach(this._attachEvents, this.disconnect, this);			this._attachEvents = [];			this.inherited(arguments);		}	});	// key is templateString; object is either string or DOM tree	_TemplatedMixin._templateCache = {};	_TemplatedMixin.getCachedTemplate = function(templateString, alwaysUseString){		// summary:		//		Static method to get a template based on the templatePath or		//		templateString key		// templateString: String		//		The template		// alwaysUseString: Boolean		//		Don't cache the DOM tree for this template, even if it doesn't have any variables		// returns: Mixed		//		Either string (if there are ${} variables that need to be replaced) or just		//		a DOM tree (if the node can be cloned directly)		// is it already cached?		var tmplts = _TemplatedMixin._templateCache;		var key = templateString;		var cached = tmplts[key];		if(cached){			try{				// if the cached value is an innerHTML string (no ownerDocument) or a DOM tree created within the current document, then use the current cached value				if(!cached.ownerDocument || cached.ownerDocument == win.doc){					// string or node of the same document					return cached;				}			}catch(e){ /* squelch */ } // IE can throw an exception if cached.ownerDocument was reloaded			domConstruct.destroy(cached);		}		templateString = string.trim(templateString);		if(alwaysUseString || templateString.match(/\$\{([^\}]+)\}/g)){			// there are variables in the template so all we can do is cache the string			return (tmplts[key] = templateString); //String		}else{			// there are no variables in the template so we can cache the DOM tree			var node = domConstruct.toDom(templateString);			if(node.nodeType != 1){				throw new Error("Invalid template: " + templateString);			}			return (tmplts[key] = node); //Node		}	};	if(has("ie")){		unload.addOnWindowUnload(function(){			var cache = _TemplatedMixin._templateCache;			for(var key in cache){				var value = cache[key];				if(typeof value == "object"){ // value is either a string or a DOM node template					domConstruct.destroy(value);				}				delete cache[key];			}		});	}	// These arguments can be specified for widgets which are used in templates.	// Since any widget can be specified as sub widgets in template, mix it	// into the base widget class.  (This is a hack, but it's effective.)	lang.extend(_WidgetBase,{		dojoAttachEvent: "",		dojoAttachPoint: ""	});	return _TemplatedMixin;});
 |