diff options
Diffstat (limited to 'includes/js/dijit/_Templated.js')
-rw-r--r-- | includes/js/dijit/_Templated.js | 329 |
1 files changed, 329 insertions, 0 deletions
diff --git a/includes/js/dijit/_Templated.js b/includes/js/dijit/_Templated.js new file mode 100644 index 0000000..2de10e1 --- /dev/null +++ b/includes/js/dijit/_Templated.js @@ -0,0 +1,329 @@ +if(!dojo._hasResource["dijit._Templated"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dijit._Templated"] = true; +dojo.provide("dijit._Templated"); + +dojo.require("dijit._Widget"); +dojo.require("dojo.string"); +dojo.require("dojo.parser"); + +dojo.declare("dijit._Templated", + null, + { + // summary: + // Mixin for widgets that are instantiated from a template + // + // templateNode: DomNode + // a node that represents the widget template. Pre-empts both templateString and templatePath. + templateNode: null, + + // templateString: String + // a string that represents the widget template. Pre-empts the + // templatePath. In builds that have their strings "interned", the + // templatePath is converted to an inline templateString, thereby + // preventing a synchronous network call. + templateString: null, + + // templatePath: String + // Path to template (HTML file) for this widget relative to dojo.baseUrl + templatePath: null, + + // widgetsInTemplate: Boolean + // should we parse the template to find widgets that might be + // declared in markup inside it? false by default. + widgetsInTemplate: false, + + // containerNode: DomNode + // holds child elements. "containerNode" is generally set via a + // dojoAttachPoint assignment and it designates where children of + // the src dom node will be placed + containerNode: null, + + // skipNodeCache: Boolean + // if using a cached widget template node 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, + + _stringRepl: function(tmpl){ + var className = this.declaredClass, _this = this; + // Cache contains a string because we need to do property replacement + // do the property replacement + return dojo.string.substitute(tmpl, this, function(value, key){ + if(key.charAt(0) == '!'){ value = _this[key.substr(1)]; } + if(typeof value == "undefined"){ throw new Error(className+" template:"+key); } // a debugging aide + if(!value){ 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); + }, + + // method over-ride + buildRendering: function(){ + // summary: + // Construct the UI for this widget from a template, setting this.domNode. + + // 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 = dijit._Templated.getCachedTemplate(this.templatePath, this.templateString, this._skipNodeCache); + + var node; + if(dojo.isString(cached)){ + node = dijit._Templated._createNodesFromText(this._stringRepl(cached))[0]; + }else{ + // if it's a node, all we have to do is clone it + node = cached.cloneNode(true); + } + + // recurse through the node, looking for, and attaching to, our + // attachment points which should be defined on the template node. + this._attachTemplateNodes(node); + + var source = this.srcNodeRef; + if(source && source.parentNode){ + source.parentNode.replaceChild(node, source); + } + + this.domNode = node; + if(this.widgetsInTemplate){ + var cw = this._supportingWidgets = dojo.parser.parse(node); + this._attachTemplateNodes(cw, function(n,p){ + return n[p]; + }); + } + + this._fillContent(source); + }, + + _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 + 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. + // 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 + // * dojoAttachEvent + // * waiRole + // * waiState + // rootNode: DomNode|Array[Widgets] + // 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 + + getAttrFunc = getAttrFunc || function(n,p){ return n.getAttribute(p); }; + + var nodes = dojo.isArray(rootNode) ? rootNode : (rootNode.all || rootNode.getElementsByTagName("*")); + var x=dojo.isArray(rootNode)?0:-1; + for(; x<nodes.length; x++){ + var baseNode = (x == -1) ? rootNode : nodes[x]; + if(this.widgetsInTemplate && getAttrFunc(baseNode,'dojoType')){ + continue; + } + // Process dojoAttachPoint + var attachPoint = getAttrFunc(baseNode, "dojoAttachPoint"); + if(attachPoint){ + var point, points = attachPoint.split(/\s*,\s*/); + while((point = points.shift())){ + if(dojo.isArray(this[point])){ + this[point].push(baseNode); + }else{ + this[point]=baseNode; + } + } + } + + // Process dojoAttachEvent + var attachEvent = getAttrFunc(baseNode, "dojoAttachEvent"); + if(attachEvent){ + // NOTE: we want to support attributes that have the form + // "domEvent: nativeEvent; ..." + var event, events = attachEvent.split(/\s*,\s*/); + var trim = dojo.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; + } + this.connect(baseNode, event, thisFunc); + } + } + } + + // waiRole, waiState + var role = getAttrFunc(baseNode, "waiRole"); + if(role){ + dijit.setWaiRole(baseNode, role); + } + var values = getAttrFunc(baseNode, "waiState"); + if(values){ + dojo.forEach(values.split(/\s*,\s*/), function(stateValue){ + if(stateValue.indexOf('-') != -1){ + var pair = stateValue.split('-'); + dijit.setWaiState(baseNode, pair[0], pair[1]); + } + }); + } + + } + } + } +); + +// key is either templatePath or templateString; object is either string or DOM tree +dijit._Templated._templateCache = {}; + +dijit._Templated.getCachedTemplate = function(templatePath, templateString, alwaysUseString){ + // summary: + // Static method to get a template based on the templatePath or + // templateString key + // templatePath: String + // The URL to get the template from. dojo.uri.Uri is often passed as well. + // templateString: String? + // a string to use in lieu of fetching the template from a URL. Takes precedence + // over templatePath + // 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 = dijit._Templated._templateCache; + var key = templateString || templatePath; + var cached = tmplts[key]; + if(cached){ + return cached; + } + + // If necessary, load template string from template path + if(!templateString){ + templateString = dijit._Templated._sanitizeTemplateString(dojo._getText(templatePath)); + } + + templateString = dojo.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 + return (tmplts[key] = dijit._Templated._createNodesFromText(templateString)[0]); //Node + } +}; + +dijit._Templated._sanitizeTemplateString = function(/*String*/tString){ + // summary: + // Strips <?xml ...?> declarations so that external SVG and XML + // documents can be added to a document without worry. Also, if the string + // is an HTML document, only the part inside the body tag is returned. + if(tString){ + tString = tString.replace(/^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, ""); + var matches = tString.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im); + if(matches){ + tString = matches[1]; + } + }else{ + tString = ""; + } + return tString; //String +}; + + +if(dojo.isIE){ + dojo.addOnUnload(function(){ + var cache = dijit._Templated._templateCache; + for(var key in cache){ + var value = cache[key]; + if(!isNaN(value.nodeType)){ // isNode equivalent + dojo._destroyElement(value); + } + delete cache[key]; + } + }); +} + +(function(){ + var tagMap = { + cell: {re: /^<t[dh][\s\r\n>]/i, pre: "<table><tbody><tr>", post: "</tr></tbody></table>"}, + row: {re: /^<tr[\s\r\n>]/i, pre: "<table><tbody>", post: "</tbody></table>"}, + section: {re: /^<(thead|tbody|tfoot)[\s\r\n>]/i, pre: "<table>", post: "</table>"} + }; + + // dummy container node used temporarily to hold nodes being created + var tn; + + dijit._Templated._createNodesFromText = function(/*String*/text){ + // summary: + // Attempts to create a set of nodes based on the structure of the passed text. + + if(!tn){ + tn = dojo.doc.createElement("div"); + tn.style.display="none"; + dojo.body().appendChild(tn); + } + var tableType = "none"; + var rtext = text.replace(/^\s+/, ""); + for(var type in tagMap){ + var map = tagMap[type]; + if(map.re.test(rtext)){ + tableType = type; + text = map.pre + text + map.post; + break; + } + } + + tn.innerHTML = text; + if(tn.normalize){ + tn.normalize(); + } + + var tag = { cell: "tr", row: "tbody", section: "table" }[tableType]; + var _parent = (typeof tag != "undefined") ? + tn.getElementsByTagName(tag)[0] : + tn; + + var nodes = []; + while(_parent.firstChild){ + nodes.push(_parent.removeChild(_parent.firstChild)); + } + tn.innerHTML=""; + return nodes; // Array + } +})(); + +// 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.) +dojo.extend(dijit._Widget,{ + dojoAttachEvent: "", + dojoAttachPoint: "", + waiRole: "", + waiState:"" +}) + +} |