New file |
0,0 → 1,326 |
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 |
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, |
|
// 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)){ |
var className = this.declaredClass, _this = this; |
// Cache contains a string because we need to do property replacement |
// do the property replacement |
var tstr = dojo.string.substitute(cached, 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); |
|
node = dijit._Templated._createNodesFromText(tstr)[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 childWidgets = dojo.parser.parse(node); |
this._attachTemplateNodes(childWidgets, 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: |
// 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 |
// Returns: |
// 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(templateString.match(/\$\{([^\}]+)\}/g) || alwaysUseString){ |
// 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:"" |
}) |
|
} |