summaryrefslogtreecommitdiff
path: root/lib/dojo/parser.js.uncompressed.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dojo/parser.js.uncompressed.js')
-rw-r--r--lib/dojo/parser.js.uncompressed.js594
1 files changed, 594 insertions, 0 deletions
diff --git a/lib/dojo/parser.js.uncompressed.js b/lib/dojo/parser.js.uncompressed.js
new file mode 100644
index 000000000..6d340fc24
--- /dev/null
+++ b/lib/dojo/parser.js.uncompressed.js
@@ -0,0 +1,594 @@
+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;
+});