diff options
author | Andrew Dolgov <[email protected]> | 2013-03-18 10:26:24 +0400 |
---|---|---|
committer | Andrew Dolgov <[email protected]> | 2013-03-18 10:26:26 +0400 |
commit | f0cfe83e3725f9a3928da97a6e3085e79cb25309 (patch) | |
tree | 4b0af188defaa807c7bc6ff3a101b41c9166c463 /lib/dijit/_TemplatedMixin.js.uncompressed.js | |
parent | 9a2885da170ffd64358b99194095851a2d09c1b6 (diff) |
upgrade dojo to 1.8.3 (refs #570)
Diffstat (limited to 'lib/dijit/_TemplatedMixin.js.uncompressed.js')
-rw-r--r-- | lib/dijit/_TemplatedMixin.js.uncompressed.js | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/lib/dijit/_TemplatedMixin.js.uncompressed.js b/lib/dijit/_TemplatedMixin.js.uncompressed.js new file mode 100644 index 000000000..7473b92b9 --- /dev/null +++ b/lib/dijit/_TemplatedMixin.js.uncompressed.js @@ -0,0 +1,309 @@ +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/sniff", // has("ie") + "dojo/_base/unload" // unload.addOnWindowUnload +], function(lang, touch, _WidgetBase, string, cache, array, declare, domConstruct, has, unload) { + + // module: + // dijit/_TemplatedMixin + + 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(/*===== params, srcNodeRef =====*/){ + // summary: + // Create the widget. + // params: Object|null + // Hash of initialization parameters for widget, including scalar values (like title, duration etc.) + // and functions, typically callbacks like onClick. + // The hash can contain any of the widget's properties, excluding read-only properties. + // srcNodeRef: DOMNode|String? + // If a srcNodeRef (DOM node) is specified, replace srcNodeRef with my generated DOM tree. + + 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, this.ownerDocument); + + var node; + if(lang.isString(cached)){ + node = domConstruct.toDom(this._stringRepl(cached), this.ownerDocument); + 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 < 0 || nodes[x]; x++){ // don't access nodes.length on IE, see #14346 + 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, doc){ + // 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 + // doc: Document? + // The target document. Defaults to document global if unspecified. + // 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 == (doc || document)){ + // 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, doc); + 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.). + // Remove for 2.0. Also, hide from API doc parser. + lang.extend(_WidgetBase, /*===== {} || =====*/ { + dojoAttachEvent: "", + dojoAttachPoint: "" + }); + + return _TemplatedMixin; +}); |