596 lines
21 KiB
JavaScript
596 lines
21 KiB
JavaScript
//>>built
|
|
define(
|
|
"dojo/parser", ["./_base/kernel", "./_base/lang", "./_base/array", "./_base/html", "./_base/window", "./_base/url",
|
|
"./_base/json", "./aspect", "./date/stamp", "./query", "./on", "./ready"],
|
|
function(dojo, dlang, darray, dhtml, dwindow, _Url, djson, aspect, dates, query, don){
|
|
|
|
// module:
|
|
// dojo/parser
|
|
// summary:
|
|
// The Dom/Widget parsing package
|
|
|
|
new Date("X"); // workaround for #11279, new Date("") == NaN
|
|
|
|
var features = {
|
|
// Feature detection for when node.attributes only lists the attributes specified in the markup
|
|
// rather than old IE/quirks behavior where it lists every default value too
|
|
"dom-attributes-explicit": document.createElement("div").attributes.length < 40
|
|
};
|
|
function has(feature){
|
|
return features[feature];
|
|
}
|
|
|
|
|
|
dojo.parser = new function(){
|
|
// summary:
|
|
// The Dom/Widget parsing package
|
|
|
|
var _nameMap = {
|
|
// Map from widget name (ex: "dijit.form.Button") to structure mapping
|
|
// lowercase version of attribute names to the version in the widget ex:
|
|
// {
|
|
// label: "label",
|
|
// onclick: "onClick"
|
|
// }
|
|
};
|
|
function getNameMap(proto){
|
|
// summary:
|
|
// Returns map from lowercase name to attribute name in class, ex: {onclick: "onClick"}
|
|
var map = {};
|
|
for(var name in proto){
|
|
if(name.charAt(0)=="_"){ continue; } // skip internal properties
|
|
map[name.toLowerCase()] = name;
|
|
}
|
|
return map;
|
|
}
|
|
// Widgets like BorderContainer add properties to _Widget via dojo.extend().
|
|
// If BorderContainer is loaded after _Widget's parameter list has been cached,
|
|
// we need to refresh that parameter list (for _Widget and all widgets that extend _Widget).
|
|
aspect.after(dlang, "extend", function(){
|
|
_nameMap = {};
|
|
}, true);
|
|
|
|
// Map from widget name (ex: "dijit.form.Button") to constructor
|
|
var _ctorMap = {};
|
|
|
|
this._functionFromScript = function(script, attrData){
|
|
// summary:
|
|
// Convert a <script type="dojo/method" args="a, b, c"> ... </script>
|
|
// into a function
|
|
// script: DOMNode
|
|
// The <script> DOMNode
|
|
// attrData: String
|
|
// For HTML5 compliance, searches for attrData + "args" (typically
|
|
// "data-dojo-args") instead of "args"
|
|
var preamble = "";
|
|
var suffix = "";
|
|
var argsStr = (script.getAttribute(attrData + "args") || script.getAttribute("args"));
|
|
if(argsStr){
|
|
darray.forEach(argsStr.split(/\s*,\s*/), function(part, idx){
|
|
preamble += "var "+part+" = arguments["+idx+"]; ";
|
|
});
|
|
}
|
|
var withStr = script.getAttribute("with");
|
|
if(withStr && withStr.length){
|
|
darray.forEach(withStr.split(/\s*,\s*/), function(part){
|
|
preamble += "with("+part+"){";
|
|
suffix += "}";
|
|
});
|
|
}
|
|
return new Function(preamble+script.innerHTML+suffix);
|
|
};
|
|
|
|
this.instantiate = /*====== dojo.parser.instantiate= ======*/function(nodes, mixin, args){
|
|
// summary:
|
|
// Takes array of nodes, and turns them into class instances and
|
|
// potentially calls a startup method to allow them to connect with
|
|
// any children.
|
|
// nodes: Array
|
|
// Array of nodes or objects like
|
|
// | {
|
|
// | type: "dijit.form.Button",
|
|
// | node: DOMNode,
|
|
// | scripts: [ ... ], // array of <script type="dojo/..."> children of node
|
|
// | inherited: { ... } // settings inherited from ancestors like dir, theme, etc.
|
|
// | }
|
|
// mixin: Object?
|
|
// An object that will be mixed in with each node in the array.
|
|
// Values in the mixin will override values in the node, if they
|
|
// exist.
|
|
// args: Object?
|
|
// An object used to hold kwArgs for instantiation.
|
|
// See parse.args argument for details.
|
|
|
|
var thelist = [],
|
|
mixin = mixin||{};
|
|
args = args||{};
|
|
|
|
// Precompute names of special attributes we are looking for
|
|
// TODO: for 2.0 default to data-dojo- regardless of scopeName (or maybe scopeName won't exist in 2.0)
|
|
var dojoType = (args.scope || dojo._scopeName) + "Type", // typically "dojoType"
|
|
attrData = "data-" + (args.scope || dojo._scopeName) + "-",// typically "data-dojo-"
|
|
dataDojoType = attrData + "type", // typically "data-dojo-type"
|
|
dataDojoProps = attrData + "props", // typically "data-dojo-props"
|
|
dataDojoAttachPoint = attrData + "attach-point",
|
|
dataDojoAttachEvent = attrData + "attach-event",
|
|
dataDojoId = attrData + "id";
|
|
|
|
// And make hash to quickly check if a given attribute is special, and to map the name to something friendly
|
|
var specialAttrs = {};
|
|
darray.forEach([dataDojoProps, dataDojoType, dojoType, dataDojoId, "jsId", dataDojoAttachPoint,
|
|
dataDojoAttachEvent, "dojoAttachPoint", "dojoAttachEvent", "class", "style"], function(name){
|
|
specialAttrs[name.toLowerCase()] = name.replace(args.scope, "dojo");
|
|
});
|
|
|
|
darray.forEach(nodes, function(obj){
|
|
if(!obj){ return; }
|
|
|
|
var node = obj.node || obj,
|
|
type = dojoType in mixin ? mixin[dojoType] : obj.node ? obj.type : (node.getAttribute(dataDojoType) || node.getAttribute(dojoType)),
|
|
ctor = _ctorMap[type] || (_ctorMap[type] = dlang.getObject(type)),
|
|
proto = ctor && ctor.prototype;
|
|
if(!ctor){
|
|
throw new Error("Could not load class '" + type);
|
|
}
|
|
|
|
// Setup hash to hold parameter settings for this widget. Start with the parameter
|
|
// settings inherited from ancestors ("dir" and "lang").
|
|
// Inherited setting may later be overridden by explicit settings on node itself.
|
|
var params = {};
|
|
|
|
if(args.defaults){
|
|
// settings for the document itself (or whatever subtree is being parsed)
|
|
dlang.mixin(params, args.defaults);
|
|
}
|
|
if(obj.inherited){
|
|
// settings from dir=rtl or lang=... on a node above this node
|
|
dlang.mixin(params, obj.inherited);
|
|
}
|
|
|
|
// Get list of attributes explicitly listed in the markup
|
|
var attributes;
|
|
if(has("dom-attributes-explicit")){
|
|
// Standard path to get list of user specified attributes
|
|
attributes = node.attributes;
|
|
}else{
|
|
// Special path for IE, avoid (sometimes >100) bogus entries in node.attributes
|
|
var clone = /^input$|^img$/i.test(node.nodeName) ? node : node.cloneNode(false),
|
|
attrs = clone.outerHTML.replace(/=[^\s"']+|="[^"]*"|='[^']*'/g, "").replace(/^\s*<[a-zA-Z0-9]*/, "").replace(/>.*$/, "");
|
|
|
|
attributes = darray.map(attrs.split(/\s+/), function(name){
|
|
var lcName = name.toLowerCase();
|
|
return {
|
|
name: name,
|
|
// getAttribute() doesn't work for button.value, returns innerHTML of button.
|
|
// but getAttributeNode().value doesn't work for the form.encType or li.value
|
|
value: (node.nodeName == "LI" && name == "value") || lcName == "enctype" ?
|
|
node.getAttribute(lcName) : node.getAttributeNode(lcName).value,
|
|
specified: true
|
|
};
|
|
});
|
|
}
|
|
|
|
// Read in attributes and process them, including data-dojo-props, data-dojo-type,
|
|
// dojoAttachPoint, etc., as well as normal foo=bar attributes.
|
|
var i=0, item;
|
|
while(item = attributes[i++]){
|
|
if(!item || !item.specified){
|
|
continue;
|
|
}
|
|
|
|
var name = item.name,
|
|
lcName = name.toLowerCase(),
|
|
value = item.value;
|
|
|
|
if(lcName in specialAttrs){
|
|
switch(specialAttrs[lcName]){
|
|
|
|
// Data-dojo-props. Save for later to make sure it overrides direct foo=bar settings
|
|
case "data-dojo-props":
|
|
var extra = value;
|
|
break;
|
|
|
|
// data-dojo-id or jsId. TODO: drop jsId in 2.0
|
|
case "data-dojo-id":
|
|
case "jsId":
|
|
var jsname = value;
|
|
break;
|
|
|
|
// For the benefit of _Templated
|
|
case "data-dojo-attach-point":
|
|
case "dojoAttachPoint":
|
|
params.dojoAttachPoint = value;
|
|
break;
|
|
case "data-dojo-attach-event":
|
|
case "dojoAttachEvent":
|
|
params.dojoAttachEvent = value;
|
|
break;
|
|
|
|
// Special parameter handling needed for IE
|
|
case "class":
|
|
params["class"] = node.className;
|
|
break;
|
|
case "style":
|
|
params["style"] = node.style && node.style.cssText;
|
|
break;
|
|
}
|
|
}else{
|
|
// Normal attribute, ex: value="123"
|
|
|
|
// Find attribute in widget corresponding to specified name.
|
|
// May involve case conversion, ex: onclick --> onClick
|
|
if(!(name in proto)){
|
|
var map = (_nameMap[type] || (_nameMap[type] = getNameMap(proto)));
|
|
name = map[lcName] || name;
|
|
}
|
|
|
|
// Set params[name] to value, doing type conversion
|
|
if(name in proto){
|
|
switch(typeof proto[name]){
|
|
case "string":
|
|
params[name] = value;
|
|
break;
|
|
case "number":
|
|
params[name] = value.length ? Number(value) : NaN;
|
|
break;
|
|
case "boolean":
|
|
// for checked/disabled value might be "" or "checked". interpret as true.
|
|
params[name] = value.toLowerCase() != "false";
|
|
break;
|
|
case "function":
|
|
if(value === "" || value.search(/[^\w\.]+/i) != -1){
|
|
// The user has specified some text for a function like "return x+5"
|
|
params[name] = new Function(value);
|
|
}else{
|
|
// The user has specified the name of a function like "myOnClick"
|
|
// or a single word function "return"
|
|
params[name] = dlang.getObject(value, false) || new Function(value);
|
|
}
|
|
break;
|
|
default:
|
|
var pVal = proto[name];
|
|
params[name] =
|
|
(pVal && "length" in pVal) ? (value ? value.split(/\s*,\s*/) : []) : // array
|
|
(pVal instanceof Date) ?
|
|
(value == "" ? new Date("") : // the NaN of dates
|
|
value == "now" ? new Date() : // current date
|
|
dates.fromISOString(value)) :
|
|
(pVal instanceof dojo._Url) ? (dojo.baseUrl + value) :
|
|
djson.fromJson(value);
|
|
}
|
|
}else{
|
|
params[name] = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Mix things found in data-dojo-props into the params, overriding any direct settings
|
|
if(extra){
|
|
try{
|
|
extra = djson.fromJson.call(args.propsThis, "{" + extra + "}");
|
|
dlang.mixin(params, extra);
|
|
}catch(e){
|
|
// give the user a pointer to their invalid parameters. FIXME: can we kill this in production?
|
|
throw new Error(e.toString() + " in data-dojo-props='" + extra + "'");
|
|
}
|
|
}
|
|
|
|
// Any parameters specified in "mixin" override everything else.
|
|
dlang.mixin(params, mixin);
|
|
|
|
var scripts = obj.node ? obj.scripts : (ctor && (ctor._noScript || proto._noScript) ? [] :
|
|
query("> script[type^='dojo/']", node));
|
|
|
|
// Process <script type="dojo/*"> script tags
|
|
// <script type="dojo/method" event="foo"> tags are added to params, and passed to
|
|
// the widget on instantiation.
|
|
// <script type="dojo/method"> tags (with no event) are executed after instantiation
|
|
// <script type="dojo/connect" data-dojo-event="foo"> tags are dojo.connected after instantiation
|
|
// <script type="dojo/watch" data-dojo-prop="foo"> tags are dojo.watch after instantiation
|
|
// <script type="dojo/on" data-dojo-event="foo"> tags are dojo.on after instantiation
|
|
// note: dojo/* script tags cannot exist in self closing widgets, like <input />
|
|
var connects = [], // functions to connect after instantiation
|
|
calls = [], // functions to call after instantiation
|
|
watch = [], //functions to watch after instantiation
|
|
on = []; //functions to on after instantiation
|
|
|
|
if(scripts){
|
|
for(i=0; i<scripts.length; i++){
|
|
var script = scripts[i];
|
|
node.removeChild(script);
|
|
// FIXME: drop event="" support in 2.0. use data-dojo-event="" instead
|
|
var event = (script.getAttribute(attrData + "event") || script.getAttribute("event")),
|
|
prop = script.getAttribute(attrData + "prop"),
|
|
type = script.getAttribute("type"),
|
|
nf = this._functionFromScript(script, attrData);
|
|
if(event){
|
|
if(type == "dojo/connect"){
|
|
connects.push({event: event, func: nf});
|
|
}else if(type == "dojo/on"){
|
|
on.push({event: event, func: nf});
|
|
}else{
|
|
params[event] = nf;
|
|
}
|
|
}else if(type == "dojo/watch"){
|
|
watch.push({prop: prop, func: nf});
|
|
}else{
|
|
calls.push(nf);
|
|
}
|
|
}
|
|
}
|
|
|
|
// create the instance
|
|
var markupFactory = ctor.markupFactory || proto.markupFactory;
|
|
var instance = markupFactory ? markupFactory(params, node, ctor) : new ctor(params, node);
|
|
thelist.push(instance);
|
|
|
|
// map it to the JS namespace if that makes sense
|
|
if(jsname){
|
|
dlang.setObject(jsname, instance);
|
|
}
|
|
|
|
// process connections and startup functions
|
|
for(i=0; i<connects.length; i++){
|
|
aspect.after(instance, connects[i].event, dojo.hitch(instance, connects[i].func), true);
|
|
}
|
|
for(i=0; i<calls.length; i++){
|
|
calls[i].call(instance);
|
|
}
|
|
for(i=0; i<watch.length; i++){
|
|
instance.watch(watch[i].prop, watch[i].func);
|
|
}
|
|
for(i=0; i<on.length; i++){
|
|
don(instance, on[i].event, on[i].func);
|
|
}
|
|
}, this);
|
|
|
|
// Call startup on each top level instance if it makes sense (as for
|
|
// widgets). Parent widgets will recursively call startup on their
|
|
// (non-top level) children
|
|
if(!mixin._started){
|
|
darray.forEach(thelist, function(instance){
|
|
if( !args.noStart && instance &&
|
|
dlang.isFunction(instance.startup) &&
|
|
!instance._started
|
|
){
|
|
instance.startup();
|
|
}
|
|
});
|
|
}
|
|
return thelist;
|
|
};
|
|
|
|
this.parse = /*====== dojo.parser.parse= ======*/ function(rootNode, args){
|
|
// summary:
|
|
// Scan the DOM for class instances, and instantiate them.
|
|
//
|
|
// description:
|
|
// Search specified node (or root node) recursively for class instances,
|
|
// and instantiate them. Searches for either data-dojo-type="Class" or
|
|
// dojoType="Class" where "Class" is a a fully qualified class name,
|
|
// like `dijit.form.Button`
|
|
//
|
|
// Using `data-dojo-type`:
|
|
// Attributes using can be mixed into the parameters used to instantiate the
|
|
// Class by using a `data-dojo-props` attribute on the node being converted.
|
|
// `data-dojo-props` should be a string attribute to be converted from JSON.
|
|
//
|
|
// Using `dojoType`:
|
|
// Attributes are read from the original domNode and converted to appropriate
|
|
// types by looking up the Class prototype values. This is the default behavior
|
|
// from Dojo 1.0 to Dojo 1.5. `dojoType` support is deprecated, and will
|
|
// go away in Dojo 2.0.
|
|
//
|
|
// rootNode: DomNode?
|
|
// A default starting root node from which to start the parsing. Can be
|
|
// omitted, defaulting to the entire document. If omitted, the `args`
|
|
// object can be passed in this place. If the `args` object has a
|
|
// `rootNode` member, that is used.
|
|
//
|
|
// args: Object
|
|
// a kwArgs object passed along to instantiate()
|
|
//
|
|
// * noStart: Boolean?
|
|
// when set will prevent the parser from calling .startup()
|
|
// when locating the nodes.
|
|
// * rootNode: DomNode?
|
|
// identical to the function's `rootNode` argument, though
|
|
// allowed to be passed in via this `args object.
|
|
// * template: Boolean
|
|
// If true, ignores ContentPane's stopParser flag and parses contents inside of
|
|
// a ContentPane inside of a template. This allows dojoAttachPoint on widgets/nodes
|
|
// nested inside the ContentPane to work.
|
|
// * inherited: Object
|
|
// Hash possibly containing dir and lang settings to be applied to
|
|
// parsed widgets, unless there's another setting on a sub-node that overrides
|
|
// * scope: String
|
|
// Root for attribute names to search for. If scopeName is dojo,
|
|
// will search for data-dojo-type (or dojoType). For backwards compatibility
|
|
// reasons defaults to dojo._scopeName (which is "dojo" except when
|
|
// multi-version support is used, when it will be something like dojo16, dojo20, etc.)
|
|
// * propsThis: Object
|
|
// If specified, "this" referenced from data-dojo-props will refer to propsThis.
|
|
// Intended for use from the widgets-in-template feature of `dijit._WidgetsInTemplateMixin`
|
|
//
|
|
// example:
|
|
// Parse all widgets on a page:
|
|
// | dojo.parser.parse();
|
|
//
|
|
// example:
|
|
// Parse all classes within the node with id="foo"
|
|
// | dojo.parser.parse(dojo.byId('foo'));
|
|
//
|
|
// example:
|
|
// Parse all classes in a page, but do not call .startup() on any
|
|
// child
|
|
// | dojo.parser.parse({ noStart: true })
|
|
//
|
|
// example:
|
|
// Parse all classes in a node, but do not call .startup()
|
|
// | dojo.parser.parse(someNode, { noStart:true });
|
|
// | // or
|
|
// | dojo.parser.parse({ noStart:true, rootNode: someNode });
|
|
|
|
// determine the root node based on the passed arguments.
|
|
var root;
|
|
if(!args && rootNode && rootNode.rootNode){
|
|
args = rootNode;
|
|
root = args.rootNode;
|
|
}else{
|
|
root = rootNode;
|
|
}
|
|
root = root ? dhtml.byId(root) : dwindow.body();
|
|
args = args || {};
|
|
|
|
var dojoType = (args.scope || dojo._scopeName) + "Type", // typically "dojoType"
|
|
attrData = "data-" + (args.scope || dojo._scopeName) + "-", // typically "data-dojo-"
|
|
dataDojoType = attrData + "type", // typically "data-dojo-type"
|
|
dataDojoTextDir = attrData + "textdir"; // typically "data-dojo-textdir"
|
|
|
|
// List of all nodes on page w/dojoType specified
|
|
var list = [];
|
|
|
|
// Info on DOMNode currently being processed
|
|
var node = root.firstChild;
|
|
|
|
// Info on parent of DOMNode currently being processed
|
|
// - inherited: dir, lang, and textDir setting of parent, or inherited by parent
|
|
// - parent: pointer to identical structure for my parent (or null if no parent)
|
|
// - scripts: if specified, collects <script type="dojo/..."> type nodes from children
|
|
var inherited = args && args.inherited;
|
|
if(!inherited){
|
|
function findAncestorAttr(node, attr){
|
|
return (node.getAttribute && node.getAttribute(attr)) ||
|
|
(node !== dwindow.doc && node !== dwindow.doc.documentElement && node.parentNode ? findAncestorAttr(node.parentNode, attr) : null);
|
|
}
|
|
inherited = {
|
|
dir: findAncestorAttr(root, "dir"),
|
|
lang: findAncestorAttr(root, "lang"),
|
|
textDir: findAncestorAttr(root, dataDojoTextDir)
|
|
};
|
|
for(var key in inherited){
|
|
if(!inherited[key]){ delete inherited[key]; }
|
|
}
|
|
}
|
|
var parent = {
|
|
inherited: inherited
|
|
};
|
|
|
|
// For collecting <script type="dojo/..."> type nodes (when null, we don't need to collect)
|
|
var scripts;
|
|
|
|
// when true, only look for <script type="dojo/..."> tags, and don't recurse to children
|
|
var scriptsOnly;
|
|
|
|
function getEffective(parent){
|
|
// summary:
|
|
// Get effective dir, lang, textDir settings for specified obj
|
|
// (matching "parent" object structure above), and do caching.
|
|
// Take care not to return null entries.
|
|
if(!parent.inherited){
|
|
parent.inherited = {};
|
|
var node = parent.node,
|
|
grandparent = getEffective(parent.parent);
|
|
var inherited = {
|
|
dir: node.getAttribute("dir") || grandparent.dir,
|
|
lang: node.getAttribute("lang") || grandparent.lang,
|
|
textDir: node.getAttribute(dataDojoTextDir) || grandparent.textDir
|
|
};
|
|
for(var key in inherited){
|
|
if(inherited[key]){
|
|
parent.inherited[key] = inherited[key];
|
|
}
|
|
}
|
|
}
|
|
return parent.inherited;
|
|
}
|
|
|
|
// DFS on DOM tree, collecting nodes with data-dojo-type specified.
|
|
while(true){
|
|
if(!node){
|
|
// Finished this level, continue to parent's next sibling
|
|
if(!parent || !parent.node){
|
|
break;
|
|
}
|
|
node = parent.node.nextSibling;
|
|
scripts = parent.scripts;
|
|
scriptsOnly = false;
|
|
parent = parent.parent;
|
|
continue;
|
|
}
|
|
|
|
if(node.nodeType != 1){
|
|
// Text or comment node, skip to next sibling
|
|
node = node.nextSibling;
|
|
continue;
|
|
}
|
|
|
|
if(scripts && node.nodeName.toLowerCase() == "script"){
|
|
// Save <script type="dojo/..."> for parent, then continue to next sibling
|
|
type = node.getAttribute("type");
|
|
if(type && /^dojo\/\w/i.test(type)){
|
|
scripts.push(node);
|
|
}
|
|
node = node.nextSibling;
|
|
continue;
|
|
}
|
|
if(scriptsOnly){
|
|
node = node.nextSibling;
|
|
continue;
|
|
}
|
|
|
|
// Check for data-dojo-type attribute, fallback to backward compatible dojoType
|
|
var type = node.getAttribute(dataDojoType) || node.getAttribute(dojoType);
|
|
|
|
// Short circuit for leaf nodes containing nothing [but text]
|
|
var firstChild = node.firstChild;
|
|
if(!type && (!firstChild || (firstChild.nodeType == 3 && !firstChild.nextSibling))){
|
|
node = node.nextSibling;
|
|
continue;
|
|
}
|
|
|
|
// Setup data structure to save info on current node for when we return from processing descendant nodes
|
|
var current = {
|
|
node: node,
|
|
scripts: scripts,
|
|
parent: parent
|
|
};
|
|
|
|
// If dojoType/data-dojo-type specified, add to output array of nodes to instantiate
|
|
var ctor = type && (_ctorMap[type] || (_ctorMap[type] = dlang.getObject(type))), // note: won't find classes declared via dojo.Declaration
|
|
childScripts = ctor && !ctor.prototype._noScript ? [] : null; // <script> nodes that are parent's children
|
|
if(type){
|
|
list.push({
|
|
"type": type,
|
|
node: node,
|
|
scripts: childScripts,
|
|
inherited: getEffective(current) // dir & lang settings for current node, explicit or inherited
|
|
});
|
|
}
|
|
|
|
// Recurse, collecting <script type="dojo/..."> children, and also looking for
|
|
// descendant nodes with dojoType specified (unless the widget has the stopParser flag).
|
|
// When finished with children, go to my next sibling.
|
|
node = firstChild;
|
|
scripts = childScripts;
|
|
scriptsOnly = ctor && ctor.prototype.stopParser && !(args && args.template);
|
|
parent = current;
|
|
|
|
}
|
|
|
|
// go build the object instances
|
|
var mixin = args && args.template ? {template: true} : null;
|
|
return this.instantiate(list, mixin, args); // Array
|
|
};
|
|
}();
|
|
|
|
|
|
//Register the parser callback. It should be the first callback
|
|
//after the a11y test.
|
|
if(dojo.config.parseOnLoad){
|
|
dojo.ready(100, dojo.parser, "parse");
|
|
}
|
|
|
|
return dojo.parser;
|
|
});
|