storage/ndb/mcc/frontend/dojo/dijit/dijit.js.uncompressed.js (3,850 lines of code) (raw):

/* Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved. Available via Academic Free License >= 2.1 OR the modified BSD license. see: http://dojotoolkit.org/license for details */ /* This is an optimized version of Dojo, built for deployment and not for development. To get sources and documentation, please visit: http://dojotoolkit.org */ //>>built require({cache:{ 'dojo/uacss':function(){ define(["./dom-geometry", "./_base/lang", "./ready", "./_base/sniff", "./_base/window"], function(geometry, lang, ready, has, baseWindow){ // module: // dojo/uacss // summary: // Applies pre-set CSS classes to the top-level HTML node, based on: // - browser (ex: dj_ie) // - browser version (ex: dj_ie6) // - box model (ex: dj_contentBox) // - text direction (ex: dijitRtl) // // In addition, browser, browser version, and box model are // combined with an RTL flag when browser text is RTL. ex: dj_ie-rtl. var html = baseWindow.doc.documentElement, ie = has("ie"), opera = has("opera"), maj = Math.floor, ff = has("ff"), boxModel = geometry.boxModel.replace(/-/,''), classes = { "dj_ie": ie, "dj_ie6": maj(ie) == 6, "dj_ie7": maj(ie) == 7, "dj_ie8": maj(ie) == 8, "dj_ie9": maj(ie) == 9, "dj_quirks": has("quirks"), "dj_iequirks": ie && has("quirks"), // NOTE: Opera not supported by dijit "dj_opera": opera, "dj_khtml": has("khtml"), "dj_webkit": has("webkit"), "dj_safari": has("safari"), "dj_chrome": has("chrome"), "dj_gecko": has("mozilla"), "dj_ff3": maj(ff) == 3 }; // no dojo unsupported browsers classes["dj_" + boxModel] = true; // apply browser, browser version, and box model class names var classStr = ""; for(var clz in classes){ if(classes[clz]){ classStr += clz + " "; } } html.className = lang.trim(html.className + " " + classStr); // If RTL mode, then add dj_rtl flag plus repeat existing classes with -rtl extension. // We can't run the code below until the <body> tag has loaded (so we can check for dir=rtl). // priority is 90 to run ahead of parser priority of 100 ready(90, function(){ if(!geometry.isBodyLtr()){ var rtlClassStr = "dj_rtl dijitRtl " + classStr.replace(/ /g, "-rtl "); html.className = lang.trim(html.className + " " + rtlClassStr + "dj_rtl dijitRtl " + classStr.replace(/ /g, "-rtl ")); } }); return has; }); }, 'dojo/text':function(){ define(["./_base/kernel", "require", "./has", "./_base/xhr"], function(dojo, require, has, xhr){ // module: // dojo/text // summary: // This module implements the !dojo/text plugin and the dojo.cache API. // description: // We choose to include our own plugin to leverage functionality already contained in dojo // and thereby reduce the size of the plugin compared to various foreign loader implementations. // Also, this allows foreign AMD loaders to be used without their plugins. // // CAUTION: this module is designed to optionally function synchronously to support the dojo v1.x synchronous // loader. This feature is outside the scope of the CommonJS plugins specification. var getText; if(1){ getText= function(url, sync, load){ xhr("GET", {url:url, sync:!!sync, load:load}); }; }else{ // TODOC: only works for dojo AMD loader if(require.getText){ getText= require.getText; }else{ console.error("dojo/text plugin failed to load because loader does not support getText"); } } var theCache= {}, strip= function(text){ //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(text){ text= text.replace(/^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, ""); var matches= text.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im); if(matches){ text= matches[1]; } }else{ text = ""; } return text; }, notFound = {}, pending = {}, result= { dynamic: // the dojo/text caches it's own resources because of dojo.cache true, normalize:function(id, toAbsMid){ // id is something like (path may be relative): // // "path/to/text.html" // "path/to/text.html!strip" var parts= id.split("!"), url= parts[0]; return (/^\./.test(url) ? toAbsMid(url) : url) + (parts[1] ? "!" + parts[1] : ""); }, load:function(id, require, load){ // id is something like (path is always absolute): // // "path/to/text.html" // "path/to/text.html!strip" var parts= id.split("!"), stripFlag= parts.length>1, absMid= parts[0], url = require.toUrl(parts[0]), text = notFound, finish = function(text){ load(stripFlag ? strip(text) : text); }; if(absMid in theCache){ text = theCache[absMid]; }else if(url in require.cache){ text = require.cache[url]; }else if(url in theCache){ text = theCache[url]; } if(text===notFound){ if(pending[url]){ pending[url].push(finish); }else{ var pendingList = pending[url] = [finish]; getText(url, !require.async, function(text){ theCache[absMid]= theCache[url]= text; for(var i = 0; i<pendingList.length;){ pendingList[i++](text); } delete pending[url]; }); } }else{ finish(text); } } }; dojo.cache= function(/*String||Object*/module, /*String*/url, /*String||Object?*/value){ // * (string string [value]) => (module, url, value) // * (object [value]) => (module, value), url defaults to "" // // * if module is an object, then it must be convertable to a string // * (module, url) module + (url ? ("/" + url) : "") must be a legal argument to require.toUrl // * value may be a string or an object; if an object then may have the properties "value" and/or "sanitize" var key; if(typeof module=="string"){ if(/\//.test(module)){ // module is a version 1.7+ resolved path key = module; value = url; }else{ // module is a version 1.6- argument to dojo.moduleUrl key = require.toUrl(module.replace(/\./g, "/") + (url ? ("/" + url) : "")); } }else{ key = module + ""; value = url; } var val = (value != undefined && typeof value != "string") ? value.value : value, sanitize = value && value.sanitize; if(typeof val == "string"){ //We have a string, set cache value theCache[key] = val; return sanitize ? strip(val) : val; }else if(val === null){ //Remove cached value delete theCache[key]; return null; }else{ //Allow cache values to be empty strings. If key property does //not exist, fetch it. if(!(key in theCache)){ getText(key, true, function(text){ theCache[key]= text; }); } return sanitize ? strip(theCache[key]) : theCache[key]; } }; return result; /*===== dojo.cache = function(module, url, value){ // summary: // A getter and setter for storing the string content associated with the // module and url arguments. // description: // If module is a string that contains slashes, then it is interpretted as a fully // resolved path (typically a result returned by require.toUrl), and url should not be // provided. This is the preferred signature. If module is a string that does not // contain slashes, then url must also be provided and module and url are used to // call `dojo.moduleUrl()` to generate a module URL. This signature is deprecated. // If value is specified, the cache value for the moduleUrl will be set to // that value. Otherwise, dojo.cache will fetch the moduleUrl and store it // in its internal cache and return that cached value for the URL. To clear // a cache value pass null for value. Since XMLHttpRequest (XHR) is used to fetch the // the URL contents, only modules on the same domain of the page can use this capability. // The build system can inline the cache values though, to allow for xdomain hosting. // module: String||Object // If a String with slashes, a fully resolved path; if a String without slashes, the // module name to use for the base part of the URL, similar to module argument // to `dojo.moduleUrl`. If an Object, something that has a .toString() method that // generates a valid path for the cache item. For example, a dojo._Url object. // url: String // The rest of the path to append to the path derived from the module argument. If // module is an object, then this second argument should be the "value" argument instead. // value: String||Object? // If a String, the value to use in the cache for the module/url combination. // If an Object, it can have two properties: value and sanitize. The value property // should be the value to use in the cache, and sanitize can be set to true or false, // to indicate if XML declarations should be removed from the value and if the HTML // inside a body tag in the value should be extracted as the real value. The value argument // or the value property on the value argument are usually only used by the build system // as it inlines cache content. // example: // To ask dojo.cache to fetch content and store it in the cache (the dojo["cache"] style // of call is used to avoid an issue with the build system erroneously trying to intern // this example. To get the build system to intern your dojo.cache calls, use the // "dojo.cache" style of call): // | //If template.html contains "<h1>Hello</h1>" that will be // | //the value for the text variable. // | var text = dojo["cache"]("my.module", "template.html"); // example: // To ask dojo.cache to fetch content and store it in the cache, and sanitize the input // (the dojo["cache"] style of call is used to avoid an issue with the build system // erroneously trying to intern this example. To get the build system to intern your // dojo.cache calls, use the "dojo.cache" style of call): // | //If template.html contains "<html><body><h1>Hello</h1></body></html>", the // | //text variable will contain just "<h1>Hello</h1>". // | var text = dojo["cache"]("my.module", "template.html", {sanitize: true}); // example: // Same example as previous, but demostrates how an object can be passed in as // the first argument, then the value argument can then be the second argument. // | //If template.html contains "<html><body><h1>Hello</h1></body></html>", the // | //text variable will contain just "<h1>Hello</h1>". // | var text = dojo["cache"](new dojo._Url("my/module/template.html"), {sanitize: true}); return val; //String }; =====*/ }); }, 'dijit/hccss':function(){ define("dijit/hccss", [ "require", // require.toUrl "dojo/_base/config", // config.blankGif "dojo/dom-class", // domClass.add domConstruct.create domStyle.getComputedStyle "dojo/dom-construct", // domClass.add domConstruct.create domStyle.getComputedStyle "dojo/dom-style", // domClass.add domConstruct.create domStyle.getComputedStyle "dojo/ready", // ready "dojo/_base/sniff", // has("ie") has("mozilla") "dojo/_base/window" // win.body ], function(require, config, domClass, domConstruct, domStyle, ready, has, win){ // module: // dijit/hccss // summary: // Test if computer is in high contrast mode, and sets dijit_a11y flag on <body> if it is. if(has("ie") || has("mozilla")){ // NOTE: checking in Safari messes things up // priority is 90 to run ahead of parser priority of 100 ready(90, function(){ // summary: // Detects if we are in high-contrast mode or not // create div for testing if high contrast mode is on or images are turned off var div = domConstruct.create("div",{ id: "a11yTestNode", style:{ cssText:'border: 1px solid;' + 'border-color:red green;' + 'position: absolute;' + 'height: 5px;' + 'top: -999px;' + 'background-image: url("' + (config.blankGif || require.toUrl("dojo/resources/blank.gif")) + '");' } }, win.body()); // test it var cs = domStyle.getComputedStyle(div); if(cs){ var bkImg = cs.backgroundImage; var needsA11y = (cs.borderTopColor == cs.borderRightColor) || (bkImg != null && (bkImg == "none" || bkImg == "url(invalid-url:)" )); if(needsA11y){ domClass.add(win.body(), "dijit_a11y"); } if(has("ie")){ div.outerHTML = ""; // prevent mixed-content warning, see http://support.microsoft.com/kb/925014 }else{ win.body().removeChild(div); } } }); } }); }, 'dijit/_Contained':function(){ define("dijit/_Contained", [ "dojo/_base/declare", // declare "./registry" // registry.getEnclosingWidget(), registry.byNode() ], function(declare, registry){ // module: // dijit/_Contained // summary: // Mixin for widgets that are children of a container widget return declare("dijit._Contained", null, { // summary: // Mixin for widgets that are children of a container widget // // example: // | // make a basic custom widget that knows about it's parents // | declare("my.customClass",[dijit._Widget,dijit._Contained],{}); _getSibling: function(/*String*/ which){ // summary: // Returns next or previous sibling // which: // Either "next" or "previous" // tags: // private var node = this.domNode; do{ node = node[which+"Sibling"]; }while(node && node.nodeType != 1); return node && registry.byNode(node); // dijit._Widget }, getPreviousSibling: function(){ // summary: // Returns null if this is the first child of the parent, // otherwise returns the next element sibling to the "left". return this._getSibling("previous"); // dijit._Widget }, getNextSibling: function(){ // summary: // Returns null if this is the last child of the parent, // otherwise returns the next element sibling to the "right". return this._getSibling("next"); // dijit._Widget }, getIndexInParent: function(){ // summary: // Returns the index of this widget within its container parent. // It returns -1 if the parent does not exist, or if the parent // is not a dijit._Container var p = this.getParent(); if(!p || !p.getIndexOfChild){ return -1; // int } return p.getIndexOfChild(this); // int } }); }); }, 'dojo/parser':function(){ define( ["./_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; }); }, 'dijit/_Container':function(){ define("dijit/_Container", [ "dojo/_base/array", // array.forEach array.indexOf "dojo/_base/declare", // declare "dojo/dom-construct", // domConstruct.place "./registry" // registry.byNode() ], function(array, declare, domConstruct, registry){ // module: // dijit/_Container // summary: // Mixin for widgets that contain a set of widget children. return declare("dijit._Container", null, { // summary: // Mixin for widgets that contain a set of widget children. // description: // Use this mixin for widgets that needs to know about and // keep track of their widget children. Suitable for widgets like BorderContainer // and TabContainer which contain (only) a set of child widgets. // // It's not suitable for widgets like ContentPane // which contains mixed HTML (plain DOM nodes in addition to widgets), // and where contained widgets are not necessarily directly below // this.containerNode. In that case calls like addChild(node, position) // wouldn't make sense. buildRendering: function(){ this.inherited(arguments); if(!this.containerNode){ // all widgets with descendants must set containerNode this.containerNode = this.domNode; } }, addChild: function(/*dijit._Widget*/ widget, /*int?*/ insertIndex){ // summary: // Makes the given widget a child of this widget. // description: // Inserts specified child widget's dom node as a child of this widget's // container node, and possibly does other processing (such as layout). var refNode = this.containerNode; if(insertIndex && typeof insertIndex == "number"){ var children = this.getChildren(); if(children && children.length >= insertIndex){ refNode = children[insertIndex-1].domNode; insertIndex = "after"; } } domConstruct.place(widget.domNode, refNode, insertIndex); // If I've been started but the child widget hasn't been started, // start it now. Make sure to do this after widget has been // inserted into the DOM tree, so it can see that it's being controlled by me, // so it doesn't try to size itself. if(this._started && !widget._started){ widget.startup(); } }, removeChild: function(/*Widget|int*/ widget){ // summary: // Removes the passed widget instance from this widget but does // not destroy it. You can also pass in an integer indicating // the index within the container to remove if(typeof widget == "number"){ widget = this.getChildren()[widget]; } if(widget){ var node = widget.domNode; if(node && node.parentNode){ node.parentNode.removeChild(node); // detach but don't destroy } } }, hasChildren: function(){ // summary: // Returns true if widget has children, i.e. if this.containerNode contains something. return this.getChildren().length > 0; // Boolean }, _getSiblingOfChild: function(/*dijit._Widget*/ child, /*int*/ dir){ // summary: // Get the next or previous widget sibling of child // dir: // if 1, get the next sibling // if -1, get the previous sibling // tags: // private var node = child.domNode, which = (dir>0 ? "nextSibling" : "previousSibling"); do{ node = node[which]; }while(node && (node.nodeType != 1 || !registry.byNode(node))); return node && registry.byNode(node); // dijit._Widget }, getIndexOfChild: function(/*dijit._Widget*/ child){ // summary: // Gets the index of the child in this container or -1 if not found return array.indexOf(this.getChildren(), child); // int } }); }); }, 'dijit/_base/scroll':function(){ define("dijit/_base/scroll", [ "dojo/window", // windowUtils.scrollIntoView ".." // export symbol to dijit ], function(windowUtils, dijit){ // module: // dijit/_base/scroll // summary: // Back compatibility module, new code should use windowUtils directly instead of using this module. dijit.scrollIntoView = function(/*DomNode*/ node, /*Object?*/ pos){ // summary: // Scroll the passed node into view, if it is not already. // Deprecated, use `windowUtils.scrollIntoView` instead. windowUtils.scrollIntoView(node, pos); }; }); }, 'dijit/layout/_LayoutWidget':function(){ define("dijit/layout/_LayoutWidget", [ "dojo/_base/lang", // lang.mixin "../_Widget", "../_Container", "../_Contained", "dojo/_base/declare", // declare "dojo/dom-class", // domClass.add domClass.remove "dojo/dom-geometry", // domGeometry.marginBox "dojo/dom-style", // domStyle.getComputedStyle "dojo/_base/sniff", // has("ie") "dojo/_base/window" // win.global ], function(lang, _Widget, _Container, _Contained, declare, domClass, domGeometry, domStyle, has, win){ /*===== var _Widget = dijit._Widget; var _Container = dijit._Container; var _Contained = dijit._Contained; =====*/ // module: // dijit/layout/_LayoutWidget // summary: // _LayoutWidget Base class for a _Container widget which is responsible for laying out its children. // Widgets which mixin this code must define layout() to manage placement and sizing of the children. return declare("dijit.layout._LayoutWidget", [_Widget, _Container, _Contained], { // summary: // Base class for a _Container widget which is responsible for laying out its children. // Widgets which mixin this code must define layout() to manage placement and sizing of the children. // baseClass: [protected extension] String // This class name is applied to the widget's domNode // and also may be used to generate names for sub nodes, // for example dijitTabContainer-content. baseClass: "dijitLayoutContainer", // isLayoutContainer: [protected] Boolean // Indicates that this widget is going to call resize() on its // children widgets, setting their size, when they become visible. isLayoutContainer: true, buildRendering: function(){ this.inherited(arguments); domClass.add(this.domNode, "dijitContainer"); }, startup: function(){ // summary: // Called after all the widgets have been instantiated and their // dom nodes have been inserted somewhere under win.doc.body. // // Widgets should override this method to do any initialization // dependent on other widgets existing, and then call // this superclass method to finish things off. // // startup() in subclasses shouldn't do anything // size related because the size of the widget hasn't been set yet. if(this._started){ return; } // Need to call inherited first - so that child widgets get started // up correctly this.inherited(arguments); // If I am a not being controlled by a parent layout widget... var parent = this.getParent && this.getParent(); if(!(parent && parent.isLayoutContainer)){ // Do recursive sizing and layout of all my descendants // (passing in no argument to resize means that it has to glean the size itself) this.resize(); // Since my parent isn't a layout container, and my style *may be* width=height=100% // or something similar (either set directly or via a CSS class), // monitor when viewport size changes so that I can re-layout. this.connect(win.global, 'onresize', function(){ // Using function(){} closure to ensure no arguments passed to resize(). this.resize(); }); } }, resize: function(changeSize, resultSize){ // summary: // Call this to resize a widget, or after its size has changed. // description: // Change size mode: // When changeSize is specified, changes the marginBox of this widget // and forces it to relayout its contents accordingly. // changeSize may specify height, width, or both. // // If resultSize is specified it indicates the size the widget will // become after changeSize has been applied. // // Notification mode: // When changeSize is null, indicates that the caller has already changed // the size of the widget, or perhaps it changed because the browser // window was resized. Tells widget to relayout its contents accordingly. // // If resultSize is also specified it indicates the size the widget has // become. // // In either mode, this method also: // 1. Sets this._borderBox and this._contentBox to the new size of // the widget. Queries the current domNode size if necessary. // 2. Calls layout() to resize contents (and maybe adjust child widgets). // // changeSize: Object? // Sets the widget to this margin-box size and position. // May include any/all of the following properties: // | {w: int, h: int, l: int, t: int} // // resultSize: Object? // The margin-box size of this widget after applying changeSize (if // changeSize is specified). If caller knows this size and // passes it in, we don't need to query the browser to get the size. // | {w: int, h: int} var node = this.domNode; // set margin box size, unless it wasn't specified, in which case use current size if(changeSize){ domGeometry.setMarginBox(node, changeSize); } // If either height or width wasn't specified by the user, then query node for it. // But note that setting the margin box and then immediately querying dimensions may return // inaccurate results, so try not to depend on it. var mb = resultSize || {}; lang.mixin(mb, changeSize || {}); // changeSize overrides resultSize if( !("h" in mb) || !("w" in mb) ){ mb = lang.mixin(domGeometry.getMarginBox(node), mb); // just use domGeometry.marginBox() to fill in missing values } // Compute and save the size of my border box and content box // (w/out calling domGeometry.getContentBox() since that may fail if size was recently set) var cs = domStyle.getComputedStyle(node); var me = domGeometry.getMarginExtents(node, cs); var be = domGeometry.getBorderExtents(node, cs); var bb = (this._borderBox = { w: mb.w - (me.w + be.w), h: mb.h - (me.h + be.h) }); var pe = domGeometry.getPadExtents(node, cs); this._contentBox = { l: domStyle.toPixelValue(node, cs.paddingLeft), t: domStyle.toPixelValue(node, cs.paddingTop), w: bb.w - pe.w, h: bb.h - pe.h }; // Callback for widget to adjust size of its children this.layout(); }, layout: function(){ // summary: // Widgets override this method to size and position their contents/children. // When this is called this._contentBox is guaranteed to be set (see resize()). // // This is called after startup(), and also when the widget's size has been // changed. // tags: // protected extension }, _setupChild: function(/*dijit._Widget*/child){ // summary: // Common setup for initial children and children which are added after startup // tags: // protected extension var cls = this.baseClass + "-child " + (child.baseClass ? this.baseClass + "-" + child.baseClass : ""); domClass.add(child.domNode, cls); }, addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){ // Overrides _Container.addChild() to call _setupChild() this.inherited(arguments); if(this._started){ this._setupChild(child); } }, removeChild: function(/*dijit._Widget*/ child){ // Overrides _Container.removeChild() to remove class added by _setupChild() var cls = this.baseClass + "-child" + (child.baseClass ? " " + this.baseClass + "-" + child.baseClass : ""); domClass.remove(child.domNode, cls); this.inherited(arguments); } }); }); }, 'dijit/_base':function(){ define("dijit/_base", [ ".", "./a11y", // used to be in dijit/_base/manager "./WidgetSet", // used to be in dijit/_base/manager "./_base/focus", "./_base/manager", "./_base/place", "./_base/popup", "./_base/scroll", "./_base/sniff", "./_base/typematic", "./_base/wai", "./_base/window" ], function(dijit){ // module: // dijit/_base // summary: // Includes all the modules in dijit/_base return dijit._base; }); }, 'dijit/form/_FormWidgetMixin':function(){ define("dijit/form/_FormWidgetMixin", [ "dojo/_base/array", // array.forEach "dojo/_base/declare", // declare "dojo/dom-attr", // domAttr.set "dojo/dom-style", // domStyle.get "dojo/_base/lang", // lang.hitch lang.isArray "dojo/mouse", // mouse.isLeft "dojo/_base/sniff", // has("webkit") "dojo/_base/window", // win.body "dojo/window", // winUtils.scrollIntoView "../a11y" // a11y.hasDefaultTabStop ], function(array, declare, domAttr, domStyle, lang, mouse, has, win, winUtils, a11y){ // module: // dijit/form/_FormWidgetMixin // summary: // Mixin for widgets corresponding to native HTML elements such as <checkbox> or <button>, // which can be children of a <form> node or a `dijit.form.Form` widget. return declare("dijit.form._FormWidgetMixin", null, { // summary: // Mixin for widgets corresponding to native HTML elements such as <checkbox> or <button>, // which can be children of a <form> node or a `dijit.form.Form` widget. // // description: // Represents a single HTML element. // All these widgets should have these attributes just like native HTML input elements. // You can set them during widget construction or afterwards, via `dijit._Widget.attr`. // // They also share some common methods. // name: [const] String // Name used when submitting form; same as "name" attribute or plain HTML elements name: "", // alt: String // Corresponds to the native HTML <input> element's attribute. alt: "", // value: String // Corresponds to the native HTML <input> element's attribute. value: "", // type: [const] String // Corresponds to the native HTML <input> element's attribute. type: "text", // tabIndex: Integer // Order fields are traversed when user hits the tab key tabIndex: "0", _setTabIndexAttr: "focusNode", // force copy even when tabIndex default value, needed since Button is <span> // disabled: Boolean // Should this widget respond to user input? // In markup, this is specified as "disabled='disabled'", or just "disabled". disabled: false, // intermediateChanges: Boolean // Fires onChange for each value change or only on demand intermediateChanges: false, // scrollOnFocus: Boolean // On focus, should this widget scroll into view? scrollOnFocus: true, // Override _WidgetBase mapping id to this.domNode, needs to be on focusNode so <label> etc. // works with screen reader _setIdAttr: "focusNode", postCreate: function(){ this.inherited(arguments); this.connect(this.domNode, "onmousedown", "_onMouseDown"); }, _setDisabledAttr: function(/*Boolean*/ value){ this._set("disabled", value); domAttr.set(this.focusNode, 'disabled', value); if(this.valueNode){ domAttr.set(this.valueNode, 'disabled', value); } this.focusNode.setAttribute("aria-disabled", value); if(value){ // reset these, because after the domNode is disabled, we can no longer receive // mouse related events, see #4200 this._set("hovering", false); this._set("active", false); // clear tab stop(s) on this widget's focusable node(s) (ComboBox has two focusable nodes) var attachPointNames = "tabIndex" in this.attributeMap ? this.attributeMap.tabIndex : ("_setTabIndexAttr" in this) ? this._setTabIndexAttr : "focusNode"; array.forEach(lang.isArray(attachPointNames) ? attachPointNames : [attachPointNames], function(attachPointName){ var node = this[attachPointName]; // complex code because tabIndex=-1 on a <div> doesn't work on FF if(has("webkit") || a11y.hasDefaultTabStop(node)){ // see #11064 about webkit bug node.setAttribute('tabIndex', "-1"); }else{ node.removeAttribute('tabIndex'); } }, this); }else{ if(this.tabIndex != ""){ this.set('tabIndex', this.tabIndex); } } }, _onFocus: function(e){ if(this.scrollOnFocus){ winUtils.scrollIntoView(this.domNode); } this.inherited(arguments); }, isFocusable: function(){ // summary: // Tells if this widget is focusable or not. Used internally by dijit. // tags: // protected return !this.disabled && this.focusNode && (domStyle.get(this.domNode, "display") != "none"); }, focus: function(){ // summary: // Put focus on this widget if(!this.disabled && this.focusNode.focus){ try{ this.focusNode.focus(); }catch(e){}/*squelch errors from hidden nodes*/ } }, compare: function(/*anything*/ val1, /*anything*/ val2){ // summary: // Compare 2 values (as returned by get('value') for this widget). // tags: // protected if(typeof val1 == "number" && typeof val2 == "number"){ return (isNaN(val1) && isNaN(val2)) ? 0 : val1 - val2; }else if(val1 > val2){ return 1; }else if(val1 < val2){ return -1; }else{ return 0; } }, onChange: function(/*===== newValue =====*/){ // summary: // Callback when this widget's value is changed. // tags: // callback }, // _onChangeActive: [private] Boolean // Indicates that changes to the value should call onChange() callback. // This is false during widget initialization, to avoid calling onChange() // when the initial value is set. _onChangeActive: false, _handleOnChange: function(/*anything*/ newValue, /*Boolean?*/ priorityChange){ // summary: // Called when the value of the widget is set. Calls onChange() if appropriate // newValue: // the new value // priorityChange: // For a slider, for example, dragging the slider is priorityChange==false, // but on mouse up, it's priorityChange==true. If intermediateChanges==false, // onChange is only called form priorityChange=true events. // tags: // private if(this._lastValueReported == undefined && (priorityChange === null || !this._onChangeActive)){ // this block executes not for a change, but during initialization, // and is used to store away the original value (or for ToggleButton, the original checked state) this._resetValue = this._lastValueReported = newValue; } this._pendingOnChange = this._pendingOnChange || (typeof newValue != typeof this._lastValueReported) || (this.compare(newValue, this._lastValueReported) != 0); if((this.intermediateChanges || priorityChange || priorityChange === undefined) && this._pendingOnChange){ this._lastValueReported = newValue; this._pendingOnChange = false; if(this._onChangeActive){ if(this._onChangeHandle){ clearTimeout(this._onChangeHandle); } // setTimeout allows hidden value processing to run and // also the onChange handler can safely adjust focus, etc this._onChangeHandle = setTimeout(lang.hitch(this, function(){ this._onChangeHandle = null; this.onChange(newValue); }), 0); // try to collapse multiple onChange's fired faster than can be processed } } }, create: function(){ // Overrides _Widget.create() this.inherited(arguments); this._onChangeActive = true; }, destroy: function(){ if(this._onChangeHandle){ // destroy called before last onChange has fired clearTimeout(this._onChangeHandle); this.onChange(this._lastValueReported); } this.inherited(arguments); }, _onMouseDown: function(e){ // If user clicks on the button, even if the mouse is released outside of it, // this button should get focus (to mimics native browser buttons). // This is also needed on chrome because otherwise buttons won't get focus at all, // which leads to bizarre focus restore on Dialog close etc. // IE exhibits strange scrolling behavior when focusing a node so only do it when !focused. // FF needs the extra help to make sure the mousedown actually gets to the focusNode if((!this.focused || !has("ie")) && !e.ctrlKey && mouse.isLeft(e) && this.isFocusable()){ // !e.ctrlKey to ignore right-click on mac // Set a global event to handle mouseup, so it fires properly // even if the cursor leaves this.domNode before the mouse up event. var mouseUpConnector = this.connect(win.body(), "onmouseup", function(){ if(this.isFocusable()){ this.focus(); } this.disconnect(mouseUpConnector); }); } } }); }); }, 'dijit/BackgroundIframe':function(){ define("dijit/BackgroundIframe", [ "require", // require.toUrl ".", // to export dijit.BackgroundIframe "dojo/_base/config", "dojo/dom-construct", // domConstruct.create "dojo/dom-style", // domStyle.set "dojo/_base/lang", // lang.extend lang.hitch "dojo/on", "dojo/_base/sniff", // has("ie"), has("mozilla"), has("quirks") "dojo/_base/window" // win.doc.createElement ], function(require, dijit, config, domConstruct, domStyle, lang, on, has, win){ // module: // dijit/BackgroundIFrame // summary: // new dijit.BackgroundIframe(node) // Makes a background iframe as a child of node, that fills // area (and position) of node // TODO: remove _frames, it isn't being used much, since popups never release their // iframes (see [22236]) var _frames = new function(){ // summary: // cache of iframes var queue = []; this.pop = function(){ var iframe; if(queue.length){ iframe = queue.pop(); iframe.style.display=""; }else{ if(has("ie") < 9){ var burl = config["dojoBlankHtmlUrl"] || require.toUrl("dojo/resources/blank.html") || "javascript:\"\""; var html="<iframe src='" + burl + "' role='presentation'" + " style='position: absolute; left: 0px; top: 0px;" + "z-index: -1; filter:Alpha(Opacity=\"0\");'>"; iframe = win.doc.createElement(html); }else{ iframe = domConstruct.create("iframe"); iframe.src = 'javascript:""'; iframe.className = "dijitBackgroundIframe"; iframe.setAttribute("role", "presentation"); domStyle.set(iframe, "opacity", 0.1); } iframe.tabIndex = -1; // Magic to prevent iframe from getting focus on tab keypress - as style didn't work. } return iframe; }; this.push = function(iframe){ iframe.style.display="none"; queue.push(iframe); } }(); dijit.BackgroundIframe = function(/*DomNode*/ node){ // summary: // For IE/FF z-index schenanigans. id attribute is required. // // description: // new dijit.BackgroundIframe(node) // Makes a background iframe as a child of node, that fills // area (and position) of node if(!node.id){ throw new Error("no id"); } if(has("ie") || has("mozilla")){ var iframe = (this.iframe = _frames.pop()); node.appendChild(iframe); if(has("ie")<7 || has("quirks")){ this.resize(node); this._conn = on(node, 'resize', lang.hitch(this, function(){ this.resize(node); })); }else{ domStyle.set(iframe, { width: '100%', height: '100%' }); } } }; lang.extend(dijit.BackgroundIframe, { resize: function(node){ // summary: // Resize the iframe so it's the same size as node. // Needed on IE6 and IE/quirks because height:100% doesn't work right. if(this.iframe){ domStyle.set(this.iframe, { width: node.offsetWidth + 'px', height: node.offsetHeight + 'px' }); } }, destroy: function(){ // summary: // destroy the iframe if(this._conn){ this._conn.remove(); this._conn = null; } if(this.iframe){ _frames.push(this.iframe); delete this.iframe; } } }); return dijit.BackgroundIframe; }); }, 'dijit/form/_FormValueMixin':function(){ define("dijit/form/_FormValueMixin", [ "dojo/_base/declare", // declare "dojo/dom-attr", // domAttr.set "dojo/keys", // keys.ESCAPE "dojo/_base/sniff", // has("ie"), has("quirks") "./_FormWidgetMixin" ], function(declare, domAttr, keys, has, _FormWidgetMixin){ /*===== var _FormWidgetMixin = dijit.form._FormWidgetMixin; =====*/ // module: // dijit/form/_FormValueMixin // summary: // Mixin for widgets corresponding to native HTML elements such as <input> or <select> that have user changeable values. return declare("dijit.form._FormValueMixin", _FormWidgetMixin, { // summary: // Mixin for widgets corresponding to native HTML elements such as <input> or <select> that have user changeable values. // description: // Each _FormValueMixin represents a single input value, and has a (possibly hidden) <input> element, // to which it serializes it's input value, so that form submission (either normal submission or via FormBind?) // works as expected. // readOnly: Boolean // Should this widget respond to user input? // In markup, this is specified as "readOnly". // Similar to disabled except readOnly form values are submitted. readOnly: false, _setReadOnlyAttr: function(/*Boolean*/ value){ domAttr.set(this.focusNode, 'readOnly', value); this.focusNode.setAttribute("aria-readonly", value); this._set("readOnly", value); }, postCreate: function(){ this.inherited(arguments); if(has("ie")){ // IE won't stop the event with keypress this.connect(this.focusNode || this.domNode, "onkeydown", this._onKeyDown); } // Update our reset value if it hasn't yet been set (because this.set() // is only called when there *is* a value) if(this._resetValue === undefined){ this._lastValueReported = this._resetValue = this.value; } }, _setValueAttr: function(/*anything*/ newValue, /*Boolean?*/ priorityChange){ // summary: // Hook so set('value', value) works. // description: // Sets the value of the widget. // If the value has changed, then fire onChange event, unless priorityChange // is specified as null (or false?) this._handleOnChange(newValue, priorityChange); }, _handleOnChange: function(/*anything*/ newValue, /*Boolean?*/ priorityChange){ // summary: // Called when the value of the widget has changed. Saves the new value in this.value, // and calls onChange() if appropriate. See _FormWidget._handleOnChange() for details. this._set("value", newValue); this.inherited(arguments); }, undo: function(){ // summary: // Restore the value to the last value passed to onChange this._setValueAttr(this._lastValueReported, false); }, reset: function(){ // summary: // Reset the widget's value to what it was at initialization time this._hasBeenBlurred = false; this._setValueAttr(this._resetValue, true); }, _onKeyDown: function(e){ if(e.keyCode == keys.ESCAPE && !(e.ctrlKey || e.altKey || e.metaKey)){ var te; if(has("ie") < 9 || (has("ie") && has("quirks"))){ e.preventDefault(); // default behavior needs to be stopped here since keypress is too late te = document.createEventObject(); te.keyCode = keys.ESCAPE; te.shiftKey = e.shiftKey; e.srcElement.fireEvent('onkeypress', te); } } } }); }); }, 'dojo/Stateful':function(){ define(["./_base/kernel", "./_base/declare", "./_base/lang", "./_base/array"], function(dojo, declare, lang, array) { // module: // dojo/Stateful // summary: // TODOC return dojo.declare("dojo.Stateful", null, { // summary: // Base class for objects that provide named properties with optional getter/setter // control and the ability to watch for property changes // example: // | var obj = new dojo.Stateful(); // | obj.watch("foo", function(){ // | console.log("foo changed to " + this.get("foo")); // | }); // | obj.set("foo","bar"); postscript: function(mixin){ if(mixin){ lang.mixin(this, mixin); } }, get: function(/*String*/name){ // summary: // Get a property on a Stateful instance. // name: // The property to get. // returns: // The property value on this Stateful instance. // description: // Get a named property on a Stateful object. The property may // potentially be retrieved via a getter method in subclasses. In the base class // this just retrieves the object's property. // For example: // | stateful = new dojo.Stateful({foo: 3}); // | stateful.get("foo") // returns 3 // | stateful.foo // returns 3 return this[name]; //Any }, set: function(/*String*/name, /*Object*/value){ // summary: // Set a property on a Stateful instance // name: // The property to set. // value: // The value to set in the property. // returns: // The function returns this dojo.Stateful instance. // description: // Sets named properties on a stateful object and notifies any watchers of // the property. A programmatic setter may be defined in subclasses. // For example: // | stateful = new dojo.Stateful(); // | stateful.watch(function(name, oldValue, value){ // | // this will be called on the set below // | } // | stateful.set(foo, 5); // // set() may also be called with a hash of name/value pairs, ex: // | myObj.set({ // | foo: "Howdy", // | bar: 3 // | }) // This is equivalent to calling set(foo, "Howdy") and set(bar, 3) if(typeof name === "object"){ for(var x in name){ this.set(x, name[x]); } return this; } var oldValue = this[name]; this[name] = value; if(this._watchCallbacks){ this._watchCallbacks(name, oldValue, value); } return this; //dojo.Stateful }, watch: function(/*String?*/name, /*Function*/callback){ // summary: // Watches a property for changes // name: // Indicates the property to watch. This is optional (the callback may be the // only parameter), and if omitted, all the properties will be watched // returns: // An object handle for the watch. The unwatch method of this object // can be used to discontinue watching this property: // | var watchHandle = obj.watch("foo", callback); // | watchHandle.unwatch(); // callback won't be called now // callback: // The function to execute when the property changes. This will be called after // the property has been changed. The callback will be called with the |this| // set to the instance, the first argument as the name of the property, the // second argument as the old value and the third argument as the new value. var callbacks = this._watchCallbacks; if(!callbacks){ var self = this; callbacks = this._watchCallbacks = function(name, oldValue, value, ignoreCatchall){ var notify = function(propertyCallbacks){ if(propertyCallbacks){ propertyCallbacks = propertyCallbacks.slice(); for(var i = 0, l = propertyCallbacks.length; i < l; i++){ try{ propertyCallbacks[i].call(self, name, oldValue, value); }catch(e){ console.error(e); } } } }; notify(callbacks['_' + name]); if(!ignoreCatchall){ notify(callbacks["*"]); // the catch-all } }; // we use a function instead of an object so it will be ignored by JSON conversion } if(!callback && typeof name === "function"){ callback = name; name = "*"; }else{ // prepend with dash to prevent name conflicts with function (like "name" property) name = '_' + name; } var propertyCallbacks = callbacks[name]; if(typeof propertyCallbacks !== "object"){ propertyCallbacks = callbacks[name] = []; } propertyCallbacks.push(callback); return { unwatch: function(){ propertyCallbacks.splice(array.indexOf(propertyCallbacks, callback), 1); } }; //Object } }); }); }, 'dojo/touch':function(){ define(["./_base/kernel", "./on", "./has", "./mouse"], function(dojo, on, has, mouse){ // module: // dojo/touch /*===== dojo.touch = { // summary: // This module provides unified touch event handlers by exporting // press, move, release and cancel which can also run well on desktop. // Based on http://dvcs.w3.org/hg/webevents/raw-file/tip/touchevents.html // // example: // 1. Used with dojo.connect() // | dojo.connect(node, dojo.touch.press, function(e){}); // | dojo.connect(node, dojo.touch.move, function(e){}); // | dojo.connect(node, dojo.touch.release, function(e){}); // | dojo.connect(node, dojo.touch.cancel, function(e){}); // // 2. Used with dojo.on // | define(["dojo/on", "dojo/touch"], function(on, touch){ // | on(node, touch.press, function(e){}); // | on(node, touch.move, function(e){}); // | on(node, touch.release, function(e){}); // | on(node, touch.cancel, function(e){}); // // 3. Used with dojo.touch.* directly // | dojo.touch.press(node, function(e){}); // | dojo.touch.move(node, function(e){}); // | dojo.touch.release(node, function(e){}); // | dojo.touch.cancel(node, function(e){}); press: function(node, listener){ // summary: // Register a listener to 'touchstart'|'mousedown' for the given node // node: Dom // Target node to listen to // listener: Function // Callback function // returns: // A handle which will be used to remove the listener by handle.remove() }, move: function(node, listener){ // summary: // Register a listener to 'touchmove'|'mousemove' for the given node // node: Dom // Target node to listen to // listener: Function // Callback function // returns: // A handle which will be used to remove the listener by handle.remove() }, release: function(node, listener){ // summary: // Register a listener to 'touchend'|'mouseup' for the given node // node: Dom // Target node to listen to // listener: Function // Callback function // returns: // A handle which will be used to remove the listener by handle.remove() }, cancel: function(node, listener){ // summary: // Register a listener to 'touchcancel'|'mouseleave' for the given node // node: Dom // Target node to listen to // listener: Function // Callback function // returns: // A handle which will be used to remove the listener by handle.remove() } }; =====*/ function _handle(/*String - press | move | release | cancel*/type){ return function(node, listener){//called by on(), see dojo.on return on(node, type, listener); }; } var touch = has("touch"); //device neutral events - dojo.touch.press|move|release|cancel dojo.touch = { press: _handle(touch ? "touchstart": "mousedown"), move: _handle(touch ? "touchmove": "mousemove"), release: _handle(touch ? "touchend": "mouseup"), cancel: touch ? _handle("touchcancel") : mouse.leave }; return dojo.touch; }); }, 'dijit/_CssStateMixin':function(){ define("dijit/_CssStateMixin", [ "dojo/touch", "dojo/_base/array", // array.forEach array.map "dojo/_base/declare", // declare "dojo/dom-class", // domClass.toggle "dojo/_base/lang", // lang.hitch "dojo/_base/window" // win.body ], function(touch, array, declare, domClass, lang, win){ // module: // dijit/_CssStateMixin // summary: // Mixin for widgets to set CSS classes on the widget DOM nodes depending on hover/mouse press/focus // state changes, and also higher-level state changes such becoming disabled or selected. return declare("dijit._CssStateMixin", [], { // summary: // Mixin for widgets to set CSS classes on the widget DOM nodes depending on hover/mouse press/focus // state changes, and also higher-level state changes such becoming disabled or selected. // // description: // By mixing this class into your widget, and setting the this.baseClass attribute, it will automatically // maintain CSS classes on the widget root node (this.domNode) depending on hover, // active, focus, etc. state. Ex: with a baseClass of dijitButton, it will apply the classes // dijitButtonHovered and dijitButtonActive, as the user moves the mouse over the widget and clicks it. // // It also sets CSS like dijitButtonDisabled based on widget semantic state. // // By setting the cssStateNodes attribute, a widget can also track events on subnodes (like buttons // within the widget). // cssStateNodes: [protected] Object // List of sub-nodes within the widget that need CSS classes applied on mouse hover/press and focus //. // Each entry in the hash is a an attachpoint names (like "upArrowButton") mapped to a CSS class names // (like "dijitUpArrowButton"). Example: // | { // | "upArrowButton": "dijitUpArrowButton", // | "downArrowButton": "dijitDownArrowButton" // | } // The above will set the CSS class dijitUpArrowButton to the this.upArrowButton DOMNode when it // is hovered, etc. cssStateNodes: {}, // hovering: [readonly] Boolean // True if cursor is over this widget hovering: false, // active: [readonly] Boolean // True if mouse was pressed while over this widget, and hasn't been released yet active: false, _applyAttributes: function(){ // This code would typically be in postCreate(), but putting in _applyAttributes() for // performance: so the class changes happen before DOM is inserted into the document. // Change back to postCreate() in 2.0. See #11635. this.inherited(arguments); // Automatically monitor mouse events (essentially :hover and :active) on this.domNode array.forEach(["onmouseenter", "onmouseleave", touch.press], function(e){ this.connect(this.domNode, e, "_cssMouseEvent"); }, this); // Monitoring changes to disabled, readonly, etc. state, and update CSS class of root node array.forEach(["disabled", "readOnly", "checked", "selected", "focused", "state", "hovering", "active"], function(attr){ this.watch(attr, lang.hitch(this, "_setStateClass")); }, this); // Events on sub nodes within the widget for(var ap in this.cssStateNodes){ this._trackMouseState(this[ap], this.cssStateNodes[ap]); } // Set state initially; there's probably no hover/active/focus state but widget might be // disabled/readonly/checked/selected so we want to set CSS classes for those conditions. this._setStateClass(); }, _cssMouseEvent: function(/*Event*/ event){ // summary: // Sets hovering and active properties depending on mouse state, // which triggers _setStateClass() to set appropriate CSS classes for this.domNode. if(!this.disabled){ switch(event.type){ case "mouseenter": case "mouseover": // generated on non-IE browsers even though we connected to mouseenter this._set("hovering", true); this._set("active", this._mouseDown); break; case "mouseleave": case "mouseout": // generated on non-IE browsers even though we connected to mouseleave this._set("hovering", false); this._set("active", false); break; case "mousedown": case "touchpress": this._set("active", true); this._mouseDown = true; // Set a global event to handle mouseup, so it fires properly // even if the cursor leaves this.domNode before the mouse up event. // Alternately could set active=false on mouseout. var mouseUpConnector = this.connect(win.body(), touch.release, function(){ this._mouseDown = false; this._set("active", false); this.disconnect(mouseUpConnector); }); break; } } }, _setStateClass: function(){ // summary: // Update the visual state of the widget by setting the css classes on this.domNode // (or this.stateNode if defined) by combining this.baseClass with // various suffixes that represent the current widget state(s). // // description: // In the case where a widget has multiple // states, it sets the class based on all possible // combinations. For example, an invalid form widget that is being hovered // will be "dijitInput dijitInputInvalid dijitInputHover dijitInputInvalidHover". // // The widget may have one or more of the following states, determined // by this.state, this.checked, this.valid, and this.selected: // - Error - ValidationTextBox sets this.state to "Error" if the current input value is invalid // - Incomplete - ValidationTextBox sets this.state to "Incomplete" if the current input value is not finished yet // - Checked - ex: a checkmark or a ToggleButton in a checked state, will have this.checked==true // - Selected - ex: currently selected tab will have this.selected==true // // In addition, it may have one or more of the following states, // based on this.disabled and flags set in _onMouse (this.active, this.hovering) and from focus manager (this.focused): // - Disabled - if the widget is disabled // - Active - if the mouse (or space/enter key?) is being pressed down // - Focused - if the widget has focus // - Hover - if the mouse is over the widget // Compute new set of classes var newStateClasses = this.baseClass.split(" "); function multiply(modifier){ newStateClasses = newStateClasses.concat(array.map(newStateClasses, function(c){ return c+modifier; }), "dijit"+modifier); } if(!this.isLeftToRight()){ // For RTL mode we need to set an addition class like dijitTextBoxRtl. multiply("Rtl"); } var checkedState = this.checked == "mixed" ? "Mixed" : (this.checked ? "Checked" : ""); if(this.checked){ multiply(checkedState); } if(this.state){ multiply(this.state); } if(this.selected){ multiply("Selected"); } if(this.disabled){ multiply("Disabled"); }else if(this.readOnly){ multiply("ReadOnly"); }else{ if(this.active){ multiply("Active"); }else if(this.hovering){ multiply("Hover"); } } if(this.focused){ multiply("Focused"); } // Remove old state classes and add new ones. // For performance concerns we only write into domNode.className once. var tn = this.stateNode || this.domNode, classHash = {}; // set of all classes (state and otherwise) for node array.forEach(tn.className.split(" "), function(c){ classHash[c] = true; }); if("_stateClasses" in this){ array.forEach(this._stateClasses, function(c){ delete classHash[c]; }); } array.forEach(newStateClasses, function(c){ classHash[c] = true; }); var newClasses = []; for(var c in classHash){ newClasses.push(c); } tn.className = newClasses.join(" "); this._stateClasses = newStateClasses; }, _trackMouseState: function(/*DomNode*/ node, /*String*/ clazz){ // summary: // Track mouse/focus events on specified node and set CSS class on that node to indicate // current state. Usually not called directly, but via cssStateNodes attribute. // description: // Given class=foo, will set the following CSS class on the node // - fooActive: if the user is currently pressing down the mouse button while over the node // - fooHover: if the user is hovering the mouse over the node, but not pressing down a button // - fooFocus: if the node is focused // // Note that it won't set any classes if the widget is disabled. // node: DomNode // Should be a sub-node of the widget, not the top node (this.domNode), since the top node // is handled specially and automatically just by mixing in this class. // clazz: String // CSS class name (ex: dijitSliderUpArrow). // Current state of node (initially false) // NB: setting specifically to false because domClass.toggle() needs true boolean as third arg var hovering=false, active=false, focused=false; var self = this, cn = lang.hitch(this, "connect", node); function setClass(){ var disabled = ("disabled" in self && self.disabled) || ("readonly" in self && self.readonly); domClass.toggle(node, clazz+"Hover", hovering && !active && !disabled); domClass.toggle(node, clazz+"Active", active && !disabled); domClass.toggle(node, clazz+"Focused", focused && !disabled); } // Mouse cn("onmouseenter", function(){ hovering = true; setClass(); }); cn("onmouseleave", function(){ hovering = false; active = false; setClass(); }); cn(touch.press, function(){ active = true; setClass(); }); cn(touch.release, function(){ active = false; setClass(); }); // Focus cn("onfocus", function(){ focused = true; setClass(); }); cn("onblur", function(){ focused = false; setClass(); }); // Just in case widget is enabled/disabled while it has focus/hover/active state. // Maybe this is overkill. this.watch("disabled", setClass); this.watch("readOnly", setClass); } }); }); }, 'dojo/_base/url':function(){ define(["./kernel"], function(dojo) { // module: // dojo/url // summary: // This module contains dojo._Url var ore = new RegExp("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$"), ire = new RegExp("^((([^\\[:]+):)?([^@]+)@)?(\\[([^\\]]+)\\]|([^\\[:]*))(:([0-9]+))?$"), _Url = function(){ var n = null, _a = arguments, uri = [_a[0]]; // resolve uri components relative to each other for(var i = 1; i<_a.length; i++){ if(!_a[i]){ continue; } // Safari doesn't support this.constructor so we have to be explicit // FIXME: Tracked (and fixed) in Webkit bug 3537. // http://bugs.webkit.org/show_bug.cgi?id=3537 var relobj = new _Url(_a[i]+""), uriobj = new _Url(uri[0]+""); if( relobj.path == "" && !relobj.scheme && !relobj.authority && !relobj.query ){ if(relobj.fragment != n){ uriobj.fragment = relobj.fragment; } relobj = uriobj; }else if(!relobj.scheme){ relobj.scheme = uriobj.scheme; if(!relobj.authority){ relobj.authority = uriobj.authority; if(relobj.path.charAt(0) != "/"){ var path = uriobj.path.substring(0, uriobj.path.lastIndexOf("/") + 1) + relobj.path; var segs = path.split("/"); for(var j = 0; j < segs.length; j++){ if(segs[j] == "."){ // flatten "./" references if(j == segs.length - 1){ segs[j] = ""; }else{ segs.splice(j, 1); j--; } }else if(j > 0 && !(j == 1 && segs[0] == "") && segs[j] == ".." && segs[j-1] != ".."){ // flatten "../" references if(j == (segs.length - 1)){ segs.splice(j, 1); segs[j - 1] = ""; }else{ segs.splice(j - 1, 2); j -= 2; } } } relobj.path = segs.join("/"); } } } uri = []; if(relobj.scheme){ uri.push(relobj.scheme, ":"); } if(relobj.authority){ uri.push("//", relobj.authority); } uri.push(relobj.path); if(relobj.query){ uri.push("?", relobj.query); } if(relobj.fragment){ uri.push("#", relobj.fragment); } } this.uri = uri.join(""); // break the uri into its main components var r = this.uri.match(ore); this.scheme = r[2] || (r[1] ? "" : n); this.authority = r[4] || (r[3] ? "" : n); this.path = r[5]; // can never be undefined this.query = r[7] || (r[6] ? "" : n); this.fragment = r[9] || (r[8] ? "" : n); if(this.authority != n){ // server based naming authority r = this.authority.match(ire); this.user = r[3] || n; this.password = r[4] || n; this.host = r[6] || r[7]; // ipv6 || ipv4 this.port = r[9] || n; } }; _Url.prototype.toString = function(){ return this.uri; }; return dojo._Url = _Url; }); }, 'dojo/string':function(){ define(["./_base/kernel", "./_base/lang"], function(dojo, lang) { // module: // dojo/string // summary: // TODOC lang.getObject("string", true, dojo); /*===== dojo.string = { // summary: String utilities for Dojo }; =====*/ dojo.string.rep = function(/*String*/str, /*Integer*/num){ // summary: // Efficiently replicate a string `n` times. // str: // the string to replicate // num: // number of times to replicate the string if(num <= 0 || !str){ return ""; } var buf = []; for(;;){ if(num & 1){ buf.push(str); } if(!(num >>= 1)){ break; } str += str; } return buf.join(""); // String }; dojo.string.pad = function(/*String*/text, /*Integer*/size, /*String?*/ch, /*Boolean?*/end){ // summary: // Pad a string to guarantee that it is at least `size` length by // filling with the character `ch` at either the start or end of the // string. Pads at the start, by default. // text: // the string to pad // size: // length to provide padding // ch: // character to pad, defaults to '0' // end: // adds padding at the end if true, otherwise pads at start // example: // | // Fill the string to length 10 with "+" characters on the right. Yields "Dojo++++++". // | dojo.string.pad("Dojo", 10, "+", true); if(!ch){ ch = '0'; } var out = String(text), pad = dojo.string.rep(ch, Math.ceil((size - out.length) / ch.length)); return end ? out + pad : pad + out; // String }; dojo.string.substitute = function( /*String*/ template, /*Object|Array*/map, /*Function?*/ transform, /*Object?*/ thisObject){ // summary: // Performs parameterized substitutions on a string. Throws an // exception if any parameter is unmatched. // template: // a string with expressions in the form `${key}` to be replaced or // `${key:format}` which specifies a format function. keys are case-sensitive. // map: // hash to search for substitutions // transform: // a function to process all parameters before substitution takes // place, e.g. mylib.encodeXML // thisObject: // where to look for optional format function; default to the global // namespace // example: // Substitutes two expressions in a string from an Array or Object // | // returns "File 'foo.html' is not found in directory '/temp'." // | // by providing substitution data in an Array // | dojo.string.substitute( // | "File '${0}' is not found in directory '${1}'.", // | ["foo.html","/temp"] // | ); // | // | // also returns "File 'foo.html' is not found in directory '/temp'." // | // but provides substitution data in an Object structure. Dotted // | // notation may be used to traverse the structure. // | dojo.string.substitute( // | "File '${name}' is not found in directory '${info.dir}'.", // | { name: "foo.html", info: { dir: "/temp" } } // | ); // example: // Use a transform function to modify the values: // | // returns "file 'foo.html' is not found in directory '/temp'." // | dojo.string.substitute( // | "${0} is not found in ${1}.", // | ["foo.html","/temp"], // | function(str){ // | // try to figure out the type // | var prefix = (str.charAt(0) == "/") ? "directory": "file"; // | return prefix + " '" + str + "'"; // | } // | ); // example: // Use a formatter // | // returns "thinger -- howdy" // | dojo.string.substitute( // | "${0:postfix}", ["thinger"], null, { // | postfix: function(value, key){ // | return value + " -- howdy"; // | } // | } // | ); thisObject = thisObject || dojo.global; transform = transform ? lang.hitch(thisObject, transform) : function(v){ return v; }; return template.replace(/\$\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g, function(match, key, format){ var value = lang.getObject(key, false, map); if(format){ value = lang.getObject(format, false, thisObject).call(thisObject, value, key); } return transform(value, key).toString(); }); // String }; /*===== dojo.string.trim = function(str){ // summary: // Trims whitespace from both sides of the string // str: String // String to be trimmed // returns: String // Returns the trimmed string // description: // This version of trim() was taken from [Steven Levithan's blog](http://blog.stevenlevithan.com/archives/faster-trim-javascript). // The short yet performant version of this function is dojo.trim(), // which is part of Dojo base. Uses String.prototype.trim instead, if available. return ""; // String } =====*/ dojo.string.trim = String.prototype.trim ? lang.trim : // aliasing to the native function function(str){ str = str.replace(/^\s+/, ''); for(var i = str.length - 1; i >= 0; i--){ if(/\S/.test(str.charAt(i))){ str = str.substring(0, i + 1); break; } } return str; }; return dojo.string; }); }, 'dijit/form/_FormValueWidget':function(){ define("dijit/form/_FormValueWidget", [ "dojo/_base/declare", // declare "dojo/_base/sniff", // has("ie") "./_FormWidget", "./_FormValueMixin" ], function(declare, has, _FormWidget, _FormValueMixin){ /*===== var _FormWidget = dijit.form._FormWidget; var _FormValueMixin = dijit.form._FormValueMixin; =====*/ // module: // dijit/form/_FormValueWidget // summary: // FormValueWidget return declare("dijit.form._FormValueWidget", [_FormWidget, _FormValueMixin], { // summary: // Base class for widgets corresponding to native HTML elements such as <input> or <select> that have user changeable values. // description: // Each _FormValueWidget represents a single input value, and has a (possibly hidden) <input> element, // to which it serializes it's input value, so that form submission (either normal submission or via FormBind?) // works as expected. // Don't attempt to mixin the 'type', 'name' attributes here programatically -- they must be declared // directly in the template as read by the parser in order to function. IE is known to specifically // require the 'name' attribute at element creation time. See #8484, #8660. _layoutHackIE7: function(){ // summary: // Work around table sizing bugs on IE7 by forcing redraw if(has("ie") == 7){ // fix IE7 layout bug when the widget is scrolled out of sight var domNode = this.domNode; var parent = domNode.parentNode; var pingNode = domNode.firstChild || domNode; // target node most unlikely to have a custom filter var origFilter = pingNode.style.filter; // save custom filter, most likely nothing var _this = this; while(parent && parent.clientHeight == 0){ // search for parents that haven't rendered yet (function ping(){ var disconnectHandle = _this.connect(parent, "onscroll", function(){ _this.disconnect(disconnectHandle); // only call once pingNode.style.filter = (new Date()).getMilliseconds(); // set to anything that's unique setTimeout(function(){ pingNode.style.filter = origFilter }, 0); // restore custom filter, if any } ); })(); parent = parent.parentNode; } } } }); }); }, 'dijit/registry':function(){ define("dijit/registry", [ "dojo/_base/array", // array.forEach array.map "dojo/_base/sniff", // has("ie") "dojo/_base/unload", // unload.addOnWindowUnload "dojo/_base/window", // win.body "." // dijit._scopeName ], function(array, has, unload, win, dijit){ // module: // dijit/registry // summary: // Registry of existing widget on page, plus some utility methods. // Must be accessed through AMD api, ex: // require(["dijit/registry"], function(registry){ registry.byId("foo"); }) var _widgetTypeCtr = {}, hash = {}; var registry = { // summary: // A set of widgets indexed by id length: 0, add: function(/*dijit._Widget*/ widget){ // summary: // Add a widget to the registry. If a duplicate ID is detected, a error is thrown. // // widget: dijit._Widget // Any dijit._Widget subclass. if(hash[widget.id]){ throw new Error("Tried to register widget with id==" + widget.id + " but that id is already registered"); } hash[widget.id] = widget; this.length++; }, remove: function(/*String*/ id){ // summary: // Remove a widget from the registry. Does not destroy the widget; simply // removes the reference. if(hash[id]){ delete hash[id]; this.length--; } }, byId: function(/*String|Widget*/ id){ // summary: // Find a widget by it's id. // If passed a widget then just returns the widget. return typeof id == "string" ? hash[id] : id; // dijit._Widget }, byNode: function(/*DOMNode*/ node){ // summary: // Returns the widget corresponding to the given DOMNode return hash[node.getAttribute("widgetId")]; // dijit._Widget }, toArray: function(){ // summary: // Convert registry into a true Array // // example: // Work with the widget .domNodes in a real Array // | array.map(dijit.registry.toArray(), function(w){ return w.domNode; }); var ar = []; for(var id in hash){ ar.push(hash[id]); } return ar; // dijit._Widget[] }, getUniqueId: function(/*String*/widgetType){ // summary: // Generates a unique id for a given widgetType var id; do{ id = widgetType + "_" + (widgetType in _widgetTypeCtr ? ++_widgetTypeCtr[widgetType] : _widgetTypeCtr[widgetType] = 0); }while(hash[id]); return dijit._scopeName == "dijit" ? id : dijit._scopeName + "_" + id; // String }, findWidgets: function(/*DomNode*/ root){ // summary: // Search subtree under root returning widgets found. // Doesn't search for nested widgets (ie, widgets inside other widgets). var outAry = []; function getChildrenHelper(root){ for(var node = root.firstChild; node; node = node.nextSibling){ if(node.nodeType == 1){ var widgetId = node.getAttribute("widgetId"); if(widgetId){ var widget = hash[widgetId]; if(widget){ // may be null on page w/multiple dojo's loaded outAry.push(widget); } }else{ getChildrenHelper(node); } } } } getChildrenHelper(root); return outAry; }, _destroyAll: function(){ // summary: // Code to destroy all widgets and do other cleanup on page unload // Clean up focus manager lingering references to widgets and nodes dijit._curFocus = null; dijit._prevFocus = null; dijit._activeStack = []; // Destroy all the widgets, top down array.forEach(registry.findWidgets(win.body()), function(widget){ // Avoid double destroy of widgets like Menu that are attached to <body> // even though they are logically children of other widgets. if(!widget._destroyed){ if(widget.destroyRecursive){ widget.destroyRecursive(); }else if(widget.destroy){ widget.destroy(); } } }); }, getEnclosingWidget: function(/*DOMNode*/ node){ // summary: // Returns the widget whose DOM tree contains the specified DOMNode, or null if // the node is not contained within the DOM tree of any widget while(node){ var id = node.getAttribute && node.getAttribute("widgetId"); if(id){ return hash[id]; } node = node.parentNode; } return null; }, // In case someone needs to access hash. // Actually, this is accessed from WidgetSet back-compatibility code _hash: hash }; if(has("ie")){ // Only run _destroyAll() for IE because we think it's only necessary in that case, // and because it causes problems on FF. See bug #3531 for details. unload.addOnWindowUnload(function(){ registry._destroyAll(); }); } /*===== dijit.registry = { // summary: // A list of widgets on a page. }; =====*/ dijit.registry = registry; return registry; }); }, 'dijit/_base/manager':function(){ define("dijit/_base/manager", [ "dojo/_base/array", "dojo/_base/config", // defaultDuration "../registry", ".." // for setting exports to dijit namespace ], function(array, config, registry, dijit){ // module: // dijit/_base/manager // summary: // Shim to methods on registry, plus a few other declarations. // New code should access dijit/registry directly when possible. /*===== dijit.byId = function(id){ // summary: // Returns a widget by it's id, or if passed a widget, no-op (like dom.byId()) // id: String|dijit._Widget return registry.byId(id); // dijit._Widget }; dijit.getUniqueId = function(widgetType){ // summary: // Generates a unique id for a given widgetType // widgetType: String return registry.getUniqueId(widgetType); // String }; dijit.findWidgets = function(root){ // summary: // Search subtree under root returning widgets found. // Doesn't search for nested widgets (ie, widgets inside other widgets). // root: DOMNode return registry.findWidgets(root); }; dijit._destroyAll = function(){ // summary: // Code to destroy all widgets and do other cleanup on page unload return registry._destroyAll(); }; dijit.byNode = function(node){ // summary: // Returns the widget corresponding to the given DOMNode // node: DOMNode return registry.byNode(node); // dijit._Widget }; dijit.getEnclosingWidget = function(node){ // summary: // Returns the widget whose DOM tree contains the specified DOMNode, or null if // the node is not contained within the DOM tree of any widget // node: DOMNode return registry.getEnclosingWidget(node); }; =====*/ array.forEach(["byId", "getUniqueId", "findWidgets", "_destroyAll", "byNode", "getEnclosingWidget"], function(name){ dijit[name] = registry[name]; }); /*===== dojo.mixin(dijit, { // defaultDuration: Integer // The default fx.animation speed (in ms) to use for all Dijit // transitional fx.animations, unless otherwise specified // on a per-instance basis. Defaults to 200, overrided by // `djConfig.defaultDuration` defaultDuration: 200 }); =====*/ dijit.defaultDuration = config["defaultDuration"] || 200; return dijit; }); }, 'dijit/_base/place':function(){ define("dijit/_base/place", [ "dojo/_base/array", // array.forEach "dojo/_base/lang", // lang.isArray "dojo/window", // windowUtils.getBox "../place", ".." // export to dijit namespace ], function(array, lang, windowUtils, place, dijit){ // module: // dijit/_base/place // summary: // Back compatibility module, new code should use dijit/place directly instead of using this module. dijit.getViewport = function(){ // summary: // Deprecated method to return the dimensions and scroll position of the viewable area of a browser window. // New code should use windowUtils.getBox() return windowUtils.getBox(); }; /*===== dijit.placeOnScreen = function(node, pos, corners, padding){ // summary: // Positions one of the node's corners at specified position // such that node is fully visible in viewport. // Deprecated, new code should use dijit.place.at() instead. }; =====*/ dijit.placeOnScreen = place.at; /*===== dijit.placeOnScreenAroundElement = function(node, aroundElement, aroundCorners, layoutNode){ // summary: // Like dijit.placeOnScreenAroundNode(), except it accepts an arbitrary object // for the "around" argument and finds a proper processor to place a node. // Deprecated, new code should use dijit.place.around() instead. }; ====*/ dijit.placeOnScreenAroundElement = function(node, aroundNode, aroundCorners, layoutNode){ // Convert old style {"BL": "TL", "BR": "TR"} type argument // to style needed by dijit.place code: // [ // {aroundCorner: "BL", corner: "TL" }, // {aroundCorner: "BR", corner: "TR" } // ] var positions; if(lang.isArray(aroundCorners)){ positions = aroundCorners; }else{ positions = []; for(var key in aroundCorners){ positions.push({aroundCorner: key, corner: aroundCorners[key]}); } } return place.around(node, aroundNode, positions, true, layoutNode); }; /*===== dijit.placeOnScreenAroundNode = function(node, aroundNode, aroundCorners, layoutNode){ // summary: // Position node adjacent or kitty-corner to aroundNode // such that it's fully visible in viewport. // Deprecated, new code should use dijit.place.around() instead. }; =====*/ dijit.placeOnScreenAroundNode = dijit.placeOnScreenAroundElement; /*===== dijit.placeOnScreenAroundRectangle = function(node, aroundRect, aroundCorners, layoutNode){ // summary: // Like dijit.placeOnScreenAroundNode(), except that the "around" // parameter is an arbitrary rectangle on the screen (x, y, width, height) // instead of a dom node. // Deprecated, new code should use dijit.place.around() instead. }; =====*/ dijit.placeOnScreenAroundRectangle = dijit.placeOnScreenAroundElement; dijit.getPopupAroundAlignment = function(/*Array*/ position, /*Boolean*/ leftToRight){ // summary: // Deprecated method, unneeded when using dijit/place directly. // Transforms the passed array of preferred positions into a format suitable for // passing as the aroundCorners argument to dijit.placeOnScreenAroundElement. // // position: String[] // This variable controls the position of the drop down. // It's an array of strings with the following values: // // * before: places drop down to the left of the target node/widget, or to the right in // the case of RTL scripts like Hebrew and Arabic // * after: places drop down to the right of the target node/widget, or to the left in // the case of RTL scripts like Hebrew and Arabic // * above: drop down goes above target node // * below: drop down goes below target node // // The list is positions is tried, in order, until a position is found where the drop down fits // within the viewport. // // leftToRight: Boolean // Whether the popup will be displaying in leftToRight mode. // var align = {}; array.forEach(position, function(pos){ var ltr = leftToRight; switch(pos){ case "after": align[leftToRight ? "BR" : "BL"] = leftToRight ? "BL" : "BR"; break; case "before": align[leftToRight ? "BL" : "BR"] = leftToRight ? "BR" : "BL"; break; case "below-alt": ltr = !ltr; // fall through case "below": // first try to align left borders, next try to align right borders (or reverse for RTL mode) align[ltr ? "BL" : "BR"] = ltr ? "TL" : "TR"; align[ltr ? "BR" : "BL"] = ltr ? "TR" : "TL"; break; case "above-alt": ltr = !ltr; // fall through case "above": default: // first try to align left borders, next try to align right borders (or reverse for RTL mode) align[ltr ? "TL" : "TR"] = ltr ? "BL" : "BR"; align[ltr ? "TR" : "TL"] = ltr ? "BR" : "BL"; break; } }); return align; }; return dijit; }); }, 'dijit/WidgetSet':function(){ define("dijit/WidgetSet", [ "dojo/_base/array", // array.forEach array.map "dojo/_base/declare", // declare "dojo/_base/window", // win.global "./registry" // to add functions to dijit.registry ], function(array, declare, win, registry){ // module: // dijit/WidgetSet // summary: // Legacy registry code. New modules should just use registry. // Will be removed in 2.0. var WidgetSet = declare("dijit.WidgetSet", null, { // summary: // A set of widgets indexed by id. A default instance of this class is // available as `dijit.registry` // // example: // Create a small list of widgets: // | var ws = new dijit.WidgetSet(); // | ws.add(dijit.byId("one")); // | ws.add(dijit.byId("two")); // | // destroy both: // | ws.forEach(function(w){ w.destroy(); }); // // example: // Using dijit.registry: // | dijit.registry.forEach(function(w){ /* do something */ }); constructor: function(){ this._hash = {}; this.length = 0; }, add: function(/*dijit._Widget*/ widget){ // summary: // Add a widget to this list. If a duplicate ID is detected, a error is thrown. // // widget: dijit._Widget // Any dijit._Widget subclass. if(this._hash[widget.id]){ throw new Error("Tried to register widget with id==" + widget.id + " but that id is already registered"); } this._hash[widget.id] = widget; this.length++; }, remove: function(/*String*/ id){ // summary: // Remove a widget from this WidgetSet. Does not destroy the widget; simply // removes the reference. if(this._hash[id]){ delete this._hash[id]; this.length--; } }, forEach: function(/*Function*/ func, /* Object? */thisObj){ // summary: // Call specified function for each widget in this set. // // func: // A callback function to run for each item. Is passed the widget, the index // in the iteration, and the full hash, similar to `array.forEach`. // // thisObj: // An optional scope parameter // // example: // Using the default `dijit.registry` instance: // | dijit.registry.forEach(function(widget){ // | console.log(widget.declaredClass); // | }); // // returns: // Returns self, in order to allow for further chaining. thisObj = thisObj || win.global; var i = 0, id; for(id in this._hash){ func.call(thisObj, this._hash[id], i++, this._hash); } return this; // dijit.WidgetSet }, filter: function(/*Function*/ filter, /* Object? */thisObj){ // summary: // Filter down this WidgetSet to a smaller new WidgetSet // Works the same as `array.filter` and `NodeList.filter` // // filter: // Callback function to test truthiness. Is passed the widget // reference and the pseudo-index in the object. // // thisObj: Object? // Option scope to use for the filter function. // // example: // Arbitrary: select the odd widgets in this list // | dijit.registry.filter(function(w, i){ // | return i % 2 == 0; // | }).forEach(function(w){ /* odd ones */ }); thisObj = thisObj || win.global; var res = new WidgetSet(), i = 0, id; for(id in this._hash){ var w = this._hash[id]; if(filter.call(thisObj, w, i++, this._hash)){ res.add(w); } } return res; // dijit.WidgetSet }, byId: function(/*String*/ id){ // summary: // Find a widget in this list by it's id. // example: // Test if an id is in a particular WidgetSet // | var ws = new dijit.WidgetSet(); // | ws.add(dijit.byId("bar")); // | var t = ws.byId("bar") // returns a widget // | var x = ws.byId("foo"); // returns undefined return this._hash[id]; // dijit._Widget }, byClass: function(/*String*/ cls){ // summary: // Reduce this widgetset to a new WidgetSet of a particular `declaredClass` // // cls: String // The Class to scan for. Full dot-notated string. // // example: // Find all `dijit.TitlePane`s in a page: // | dijit.registry.byClass("dijit.TitlePane").forEach(function(tp){ tp.close(); }); var res = new WidgetSet(), id, widget; for(id in this._hash){ widget = this._hash[id]; if(widget.declaredClass == cls){ res.add(widget); } } return res; // dijit.WidgetSet }, toArray: function(){ // summary: // Convert this WidgetSet into a true Array // // example: // Work with the widget .domNodes in a real Array // | array.map(dijit.registry.toArray(), function(w){ return w.domNode; }); var ar = []; for(var id in this._hash){ ar.push(this._hash[id]); } return ar; // dijit._Widget[] }, map: function(/* Function */func, /* Object? */thisObj){ // summary: // Create a new Array from this WidgetSet, following the same rules as `array.map` // example: // | var nodes = dijit.registry.map(function(w){ return w.domNode; }); // // returns: // A new array of the returned values. return array.map(this.toArray(), func, thisObj); // Array }, every: function(func, thisObj){ // summary: // A synthetic clone of `array.every` acting explicitly on this WidgetSet // // func: Function // A callback function run for every widget in this list. Exits loop // when the first false return is encountered. // // thisObj: Object? // Optional scope parameter to use for the callback thisObj = thisObj || win.global; var x = 0, i; for(i in this._hash){ if(!func.call(thisObj, this._hash[i], x++, this._hash)){ return false; // Boolean } } return true; // Boolean }, some: function(func, thisObj){ // summary: // A synthetic clone of `array.some` acting explicitly on this WidgetSet // // func: Function // A callback function run for every widget in this list. Exits loop // when the first true return is encountered. // // thisObj: Object? // Optional scope parameter to use for the callback thisObj = thisObj || win.global; var x = 0, i; for(i in this._hash){ if(func.call(thisObj, this._hash[i], x++, this._hash)){ return true; // Boolean } } return false; // Boolean } }); // Add in 1.x compatibility methods to dijit.registry. // These functions won't show up in the API doc but since they are deprecated anyway, // that's probably for the best. array.forEach(["forEach", "filter", "byClass", "map", "every", "some"], function(func){ registry[func] = WidgetSet.prototype[func]; }); return WidgetSet; }); }, 'dijit/a11y':function(){ define("dijit/a11y", [ "dojo/_base/array", // array.forEach array.map "dojo/_base/config", // defaultDuration "dojo/_base/declare", // declare "dojo/dom", // dom.byId "dojo/dom-attr", // domAttr.attr domAttr.has "dojo/dom-style", // style.style "dojo/_base/sniff", // has("ie") "./_base/manager", // manager._isElementShown "." // for exporting methods to dijit namespace ], function(array, config, declare, dom, domAttr, domStyle, has, manager, dijit){ // module: // dijit/a11y // summary: // Accessibility utility functions (keyboard, tab stops, etc.) var shown = (dijit._isElementShown = function(/*Element*/ elem){ var s = domStyle.get(elem); return (s.visibility != "hidden") && (s.visibility != "collapsed") && (s.display != "none") && (domAttr.get(elem, "type") != "hidden"); }); dijit.hasDefaultTabStop = function(/*Element*/ elem){ // summary: // Tests if element is tab-navigable even without an explicit tabIndex setting // No explicit tabIndex setting, need to investigate node type switch(elem.nodeName.toLowerCase()){ case "a": // An <a> w/out a tabindex is only navigable if it has an href return domAttr.has(elem, "href"); case "area": case "button": case "input": case "object": case "select": case "textarea": // These are navigable by default return true; case "iframe": // If it's an editor <iframe> then it's tab navigable. var body; try{ // non-IE var contentDocument = elem.contentDocument; if("designMode" in contentDocument && contentDocument.designMode == "on"){ return true; } body = contentDocument.body; }catch(e1){ // contentWindow.document isn't accessible within IE7/8 // if the iframe.src points to a foreign url and this // page contains an element, that could get focus try{ body = elem.contentWindow.document.body; }catch(e2){ return false; } } return body && (body.contentEditable == 'true' || (body.firstChild && body.firstChild.contentEditable == 'true')); default: return elem.contentEditable == 'true'; } }; var isTabNavigable = (dijit.isTabNavigable = function(/*Element*/ elem){ // summary: // Tests if an element is tab-navigable // TODO: convert (and rename method) to return effective tabIndex; will save time in _getTabNavigable() if(domAttr.get(elem, "disabled")){ return false; }else if(domAttr.has(elem, "tabIndex")){ // Explicit tab index setting return domAttr.get(elem, "tabIndex") >= 0; // boolean }else{ // No explicit tabIndex setting, so depends on node type return dijit.hasDefaultTabStop(elem); } }); dijit._getTabNavigable = function(/*DOMNode*/ root){ // summary: // Finds descendants of the specified root node. // // description: // Finds the following descendants of the specified root node: // * the first tab-navigable element in document order // without a tabIndex or with tabIndex="0" // * the last tab-navigable element in document order // without a tabIndex or with tabIndex="0" // * the first element in document order with the lowest // positive tabIndex value // * the last element in document order with the highest // positive tabIndex value var first, last, lowest, lowestTabindex, highest, highestTabindex, radioSelected = {}; function radioName(node){ // If this element is part of a radio button group, return the name for that group. return node && node.tagName.toLowerCase() == "input" && node.type && node.type.toLowerCase() == "radio" && node.name && node.name.toLowerCase(); } var walkTree = function(/*DOMNode*/parent){ for(var child = parent.firstChild; child; child = child.nextSibling){ // Skip text elements, hidden elements, and also non-HTML elements (those in custom namespaces) in IE, // since show() invokes getAttribute("type"), which crash on VML nodes in IE. if(child.nodeType != 1 || (has("ie") && child.scopeName !== "HTML") || !shown(child)){ continue; } if(isTabNavigable(child)){ var tabindex = domAttr.get(child, "tabIndex"); if(!domAttr.has(child, "tabIndex") || tabindex == 0){ if(!first){ first = child; } last = child; }else if(tabindex > 0){ if(!lowest || tabindex < lowestTabindex){ lowestTabindex = tabindex; lowest = child; } if(!highest || tabindex >= highestTabindex){ highestTabindex = tabindex; highest = child; } } var rn = radioName(child); if(domAttr.get(child, "checked") && rn){ radioSelected[rn] = child; } } if(child.nodeName.toUpperCase() != 'SELECT'){ walkTree(child); } } }; if(shown(root)){ walkTree(root); } function rs(node){ // substitute checked radio button for unchecked one, if there is a checked one with the same name. return radioSelected[radioName(node)] || node; } return { first: rs(first), last: rs(last), lowest: rs(lowest), highest: rs(highest) }; }; dijit.getFirstInTabbingOrder = function(/*String|DOMNode*/ root){ // summary: // Finds the descendant of the specified root node // that is first in the tabbing order var elems = dijit._getTabNavigable(dom.byId(root)); return elems.lowest ? elems.lowest : elems.first; // DomNode }; dijit.getLastInTabbingOrder = function(/*String|DOMNode*/ root){ // summary: // Finds the descendant of the specified root node // that is last in the tabbing order var elems = dijit._getTabNavigable(dom.byId(root)); return elems.last ? elems.last : elems.highest; // DomNode }; return { hasDefaultTabStop: dijit.hasDefaultTabStop, isTabNavigable: dijit.isTabNavigable, _getTabNavigable: dijit._getTabNavigable, getFirstInTabbingOrder: dijit.getFirstInTabbingOrder, getLastInTabbingOrder: dijit.getLastInTabbingOrder }; }); }, 'dijit/typematic':function(){ define([ "dojo/_base/array", // array.forEach "dojo/_base/connect", // connect.connect "dojo/_base/event", // event.stop "dojo/_base/kernel", // kernel.deprecated "dojo/_base/lang", // lang.mixin, lang.hitch "dojo/on", "dojo/_base/sniff", // has("ie") "." // setting dijit.typematic global ], function(array, connect, event, kernel, lang, on, has, dijit){ // module: // dijit/typematic // summary: // These functions are used to repetitively call a user specified callback // method when a specific key or mouse click over a specific DOM node is // held down for a specific amount of time. // Only 1 such event is allowed to occur on the browser page at 1 time. var typematic = (dijit.typematic = { // summary: // These functions are used to repetitively call a user specified callback // method when a specific key or mouse click over a specific DOM node is // held down for a specific amount of time. // Only 1 such event is allowed to occur on the browser page at 1 time. _fireEventAndReload: function(){ this._timer = null; this._callback(++this._count, this._node, this._evt); // Schedule next event, timer is at most minDelay (default 10ms) to avoid // browser overload (particularly avoiding starving DOH robot so it never gets to send a mouseup) this._currentTimeout = Math.max( this._currentTimeout < 0 ? this._initialDelay : (this._subsequentDelay > 1 ? this._subsequentDelay : Math.round(this._currentTimeout * this._subsequentDelay)), this._minDelay); this._timer = setTimeout(lang.hitch(this, "_fireEventAndReload"), this._currentTimeout); }, trigger: function(/*Event*/ evt, /*Object*/ _this, /*DOMNode*/ node, /*Function*/ callback, /*Object*/ obj, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){ // summary: // Start a timed, repeating callback sequence. // If already started, the function call is ignored. // This method is not normally called by the user but can be // when the normal listener code is insufficient. // evt: // key or mouse event object to pass to the user callback // _this: // pointer to the user's widget space. // node: // the DOM node object to pass the the callback function // callback: // function to call until the sequence is stopped called with 3 parameters: // count: // integer representing number of repeated calls (0..n) with -1 indicating the iteration has stopped // node: // the DOM node object passed in // evt: // key or mouse event object // obj: // user space object used to uniquely identify each typematic sequence // subsequentDelay (optional): // if > 1, the number of milliseconds until the 3->n events occur // or else the fractional time multiplier for the next event's delay, default=0.9 // initialDelay (optional): // the number of milliseconds until the 2nd event occurs, default=500ms // minDelay (optional): // the maximum delay in milliseconds for event to fire, default=10ms if(obj != this._obj){ this.stop(); this._initialDelay = initialDelay || 500; this._subsequentDelay = subsequentDelay || 0.90; this._minDelay = minDelay || 10; this._obj = obj; this._evt = evt; this._node = node; this._currentTimeout = -1; this._count = -1; this._callback = lang.hitch(_this, callback); this._fireEventAndReload(); this._evt = lang.mixin({faux: true}, evt); } }, stop: function(){ // summary: // Stop an ongoing timed, repeating callback sequence. if(this._timer){ clearTimeout(this._timer); this._timer = null; } if(this._obj){ this._callback(-1, this._node, this._evt); this._obj = null; } }, addKeyListener: function(/*DOMNode*/ node, /*Object*/ keyObject, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){ // summary: // Start listening for a specific typematic key. // See also the trigger method for other parameters. // keyObject: // an object defining the key to listen for: // charOrCode: // the printable character (string) or keyCode (number) to listen for. // keyCode: // (deprecated - use charOrCode) the keyCode (number) to listen for (implies charCode = 0). // charCode: // (deprecated - use charOrCode) the charCode (number) to listen for. // ctrlKey: // desired ctrl key state to initiate the callback sequence: // - pressed (true) // - released (false) // - either (unspecified) // altKey: // same as ctrlKey but for the alt key // shiftKey: // same as ctrlKey but for the shift key // returns: // a connection handle if(keyObject.keyCode){ keyObject.charOrCode = keyObject.keyCode; kernel.deprecated("keyCode attribute parameter for dijit.typematic.addKeyListener is deprecated. Use charOrCode instead.", "", "2.0"); }else if(keyObject.charCode){ keyObject.charOrCode = String.fromCharCode(keyObject.charCode); kernel.deprecated("charCode attribute parameter for dijit.typematic.addKeyListener is deprecated. Use charOrCode instead.", "", "2.0"); } var handles = [ on(node, connect._keypress, lang.hitch(this, function(evt){ if(evt.charOrCode == keyObject.charOrCode && (keyObject.ctrlKey === undefined || keyObject.ctrlKey == evt.ctrlKey) && (keyObject.altKey === undefined || keyObject.altKey == evt.altKey) && (keyObject.metaKey === undefined || keyObject.metaKey == (evt.metaKey || false)) && // IE doesn't even set metaKey (keyObject.shiftKey === undefined || keyObject.shiftKey == evt.shiftKey)){ event.stop(evt); typematic.trigger(evt, _this, node, callback, keyObject, subsequentDelay, initialDelay, minDelay); }else if(typematic._obj == keyObject){ typematic.stop(); } })), on(node, "keyup", lang.hitch(this, function(){ if(typematic._obj == keyObject){ typematic.stop(); } })) ]; return { remove: function(){ array.forEach(handles, function(h){ h.remove(); }); } }; }, addMouseListener: function(/*DOMNode*/ node, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){ // summary: // Start listening for a typematic mouse click. // See the trigger method for other parameters. // returns: // a connection handle var handles = [ on(node, "mousedown", lang.hitch(this, function(evt){ event.stop(evt); typematic.trigger(evt, _this, node, callback, node, subsequentDelay, initialDelay, minDelay); })), on(node, "mouseup", lang.hitch(this, function(evt){ if(this._obj){ event.stop(evt); } typematic.stop(); })), on(node, "mouseout", lang.hitch(this, function(evt){ event.stop(evt); typematic.stop(); })), on(node, "mousemove", lang.hitch(this, function(evt){ evt.preventDefault(); })), on(node, "dblclick", lang.hitch(this, function(evt){ event.stop(evt); if(has("ie")){ typematic.trigger(evt, _this, node, callback, node, subsequentDelay, initialDelay, minDelay); setTimeout(lang.hitch(this, typematic.stop), 50); } })) ]; return { remove: function(){ array.forEach(handles, function(h){ h.remove(); }); } }; }, addListener: function(/*Node*/ mouseNode, /*Node*/ keyNode, /*Object*/ keyObject, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){ // summary: // Start listening for a specific typematic key and mouseclick. // This is a thin wrapper to addKeyListener and addMouseListener. // See the addMouseListener and addKeyListener methods for other parameters. // mouseNode: // the DOM node object to listen on for mouse events. // keyNode: // the DOM node object to listen on for key events. // returns: // a connection handle var handles = [ this.addKeyListener(keyNode, keyObject, _this, callback, subsequentDelay, initialDelay, minDelay), this.addMouseListener(mouseNode, _this, callback, subsequentDelay, initialDelay, minDelay) ]; return { remove: function(){ array.forEach(handles, function(h){ h.remove(); }); } }; } }); return typematic; }); }, 'dijit/_base/focus':function(){ define("dijit/_base/focus", [ "dojo/_base/array", // array.forEach "dojo/dom", // dom.isDescendant "dojo/_base/lang", // lang.isArray "dojo/topic", // publish "dojo/_base/window", // win.doc win.doc.selection win.global win.global.getSelection win.withGlobal "../focus", ".." // for exporting symbols to dijit ], function(array, dom, lang, topic, win, focus, dijit){ // module: // dijit/_base/focus // summary: // Deprecated module to monitor currently focused node and stack of currently focused widgets. // New code should access dijit/focus directly. lang.mixin(dijit, { // _curFocus: DomNode // Currently focused item on screen _curFocus: null, // _prevFocus: DomNode // Previously focused item on screen _prevFocus: null, isCollapsed: function(){ // summary: // Returns true if there is no text selected return dijit.getBookmark().isCollapsed; }, getBookmark: function(){ // summary: // Retrieves a bookmark that can be used with moveToBookmark to return to the same range var bm, rg, tg, sel = win.doc.selection, cf = focus.curNode; if(win.global.getSelection){ //W3C Range API for selections. sel = win.global.getSelection(); if(sel){ if(sel.isCollapsed){ tg = cf? cf.tagName : ""; if(tg){ //Create a fake rangelike item to restore selections. tg = tg.toLowerCase(); if(tg == "textarea" || (tg == "input" && (!cf.type || cf.type.toLowerCase() == "text"))){ sel = { start: cf.selectionStart, end: cf.selectionEnd, node: cf, pRange: true }; return {isCollapsed: (sel.end <= sel.start), mark: sel}; //Object. } } bm = {isCollapsed:true}; if(sel.rangeCount){ bm.mark = sel.getRangeAt(0).cloneRange(); } }else{ rg = sel.getRangeAt(0); bm = {isCollapsed: false, mark: rg.cloneRange()}; } } }else if(sel){ // If the current focus was a input of some sort and no selection, don't bother saving // a native bookmark. This is because it causes issues with dialog/page selection restore. // So, we need to create psuedo bookmarks to work with. tg = cf ? cf.tagName : ""; tg = tg.toLowerCase(); if(cf && tg && (tg == "button" || tg == "textarea" || tg == "input")){ if(sel.type && sel.type.toLowerCase() == "none"){ return { isCollapsed: true, mark: null } }else{ rg = sel.createRange(); return { isCollapsed: rg.text && rg.text.length?false:true, mark: { range: rg, pRange: true } }; } } bm = {}; //'IE' way for selections. try{ // createRange() throws exception when dojo in iframe //and nothing selected, see #9632 rg = sel.createRange(); bm.isCollapsed = !(sel.type == 'Text' ? rg.htmlText.length : rg.length); }catch(e){ bm.isCollapsed = true; return bm; } if(sel.type.toUpperCase() == 'CONTROL'){ if(rg.length){ bm.mark=[]; var i=0,len=rg.length; while(i<len){ bm.mark.push(rg.item(i++)); } }else{ bm.isCollapsed = true; bm.mark = null; } }else{ bm.mark = rg.getBookmark(); } }else{ console.warn("No idea how to store the current selection for this browser!"); } return bm; // Object }, moveToBookmark: function(/*Object*/ bookmark){ // summary: // Moves current selection to a bookmark // bookmark: // This should be a returned object from dijit.getBookmark() var _doc = win.doc, mark = bookmark.mark; if(mark){ if(win.global.getSelection){ //W3C Rangi API (FF, WebKit, Opera, etc) var sel = win.global.getSelection(); if(sel && sel.removeAllRanges){ if(mark.pRange){ var n = mark.node; n.selectionStart = mark.start; n.selectionEnd = mark.end; }else{ sel.removeAllRanges(); sel.addRange(mark); } }else{ console.warn("No idea how to restore selection for this browser!"); } }else if(_doc.selection && mark){ //'IE' way. var rg; if(mark.pRange){ rg = mark.range; }else if(lang.isArray(mark)){ rg = _doc.body.createControlRange(); //rg.addElement does not have call/apply method, so can not call it directly //rg is not available in "range.addElement(item)", so can't use that either array.forEach(mark, function(n){ rg.addElement(n); }); }else{ rg = _doc.body.createTextRange(); rg.moveToBookmark(mark); } rg.select(); } } }, getFocus: function(/*Widget?*/ menu, /*Window?*/ openedForWindow){ // summary: // Called as getFocus(), this returns an Object showing the current focus // and selected text. // // Called as getFocus(widget), where widget is a (widget representing) a button // that was just pressed, it returns where focus was before that button // was pressed. (Pressing the button may have either shifted focus to the button, // or removed focus altogether.) In this case the selected text is not returned, // since it can't be accurately determined. // // menu: dijit._Widget or {domNode: DomNode} structure // The button that was just pressed. If focus has disappeared or moved // to this button, returns the previous focus. In this case the bookmark // information is already lost, and null is returned. // // openedForWindow: // iframe in which menu was opened // // returns: // A handle to restore focus/selection, to be passed to `dijit.focus` var node = !focus.curNode || (menu && dom.isDescendant(focus.curNode, menu.domNode)) ? dijit._prevFocus : focus.curNode; return { node: node, bookmark: node && (node == focus.curNode) && win.withGlobal(openedForWindow || win.global, dijit.getBookmark), openedForWindow: openedForWindow }; // Object }, // _activeStack: dijit._Widget[] // List of currently active widgets (focused widget and it's ancestors) _activeStack: [], registerIframe: function(/*DomNode*/ iframe){ // summary: // Registers listeners on the specified iframe so that any click // or focus event on that iframe (or anything in it) is reported // as a focus/click event on the <iframe> itself. // description: // Currently only used by editor. // returns: // Handle to pass to unregisterIframe() return focus.registerIframe(iframe); }, unregisterIframe: function(/*Object*/ handle){ // summary: // Unregisters listeners on the specified iframe created by registerIframe. // After calling be sure to delete or null out the handle itself. // handle: // Handle returned by registerIframe() handle && handle.remove(); }, registerWin: function(/*Window?*/targetWindow, /*DomNode?*/ effectiveNode){ // summary: // Registers listeners on the specified window (either the main // window or an iframe's window) to detect when the user has clicked somewhere // or focused somewhere. // description: // Users should call registerIframe() instead of this method. // targetWindow: // If specified this is the window associated with the iframe, // i.e. iframe.contentWindow. // effectiveNode: // If specified, report any focus events inside targetWindow as // an event on effectiveNode, rather than on evt.target. // returns: // Handle to pass to unregisterWin() return focus.registerWin(targetWindow, effectiveNode); }, unregisterWin: function(/*Handle*/ handle){ // summary: // Unregisters listeners on the specified window (either the main // window or an iframe's window) according to handle returned from registerWin(). // After calling be sure to delete or null out the handle itself. handle && handle.remove(); } }); // Override focus singleton's focus function so that dijit.focus() // has backwards compatible behavior of restoring selection (although // probably no one is using that). focus.focus = function(/*Object || DomNode */ handle){ // summary: // Sets the focused node and the selection according to argument. // To set focus to an iframe's content, pass in the iframe itself. // handle: // object returned by get(), or a DomNode if(!handle){ return; } var node = "node" in handle ? handle.node : handle, // because handle is either DomNode or a composite object bookmark = handle.bookmark, openedForWindow = handle.openedForWindow, collapsed = bookmark ? bookmark.isCollapsed : false; // Set the focus // Note that for iframe's we need to use the <iframe> to follow the parentNode chain, // but we need to set focus to iframe.contentWindow if(node){ var focusNode = (node.tagName.toLowerCase() == "iframe") ? node.contentWindow : node; if(focusNode && focusNode.focus){ try{ // Gecko throws sometimes if setting focus is impossible, // node not displayed or something like that focusNode.focus(); }catch(e){/*quiet*/} } focus._onFocusNode(node); } // set the selection // do not need to restore if current selection is not empty // (use keyboard to select a menu item) or if previous selection was collapsed // as it may cause focus shift (Esp in IE). if(bookmark && win.withGlobal(openedForWindow || win.global, dijit.isCollapsed) && !collapsed){ if(openedForWindow){ openedForWindow.focus(); } try{ win.withGlobal(openedForWindow || win.global, dijit.moveToBookmark, null, [bookmark]); }catch(e2){ /*squelch IE internal error, see http://trac.dojotoolkit.org/ticket/1984 */ } } }; // For back compatibility, monitor changes to focused node and active widget stack, // publishing events and copying changes from focus manager variables into dijit (top level) variables focus.watch("curNode", function(name, oldVal, newVal){ dijit._curFocus = newVal; dijit._prevFocus = oldVal; if(newVal){ topic.publish("focusNode", newVal); // publish } }); focus.watch("activeStack", function(name, oldVal, newVal){ dijit._activeStack = newVal; }); focus.on("widget-blur", function(widget, by){ topic.publish("widgetBlur", widget, by); // publish }); focus.on("widget-focus", function(widget, by){ topic.publish("widgetFocus", widget, by); // publish }); return dijit; }); }, 'dijit/place':function(){ define("dijit/place", [ "dojo/_base/array", // array.forEach array.map array.some "dojo/dom-geometry", // domGeometry.getMarginBox domGeometry.position "dojo/dom-style", // domStyle.getComputedStyle "dojo/_base/kernel", // kernel.deprecated "dojo/_base/window", // win.body "dojo/window", // winUtils.getBox "." // dijit (defining dijit.place to match API doc) ], function(array, domGeometry, domStyle, kernel, win, winUtils, dijit){ // module: // dijit/place // summary: // Code to place a popup relative to another node function _place(/*DomNode*/ node, choices, layoutNode, aroundNodeCoords){ // summary: // Given a list of spots to put node, put it at the first spot where it fits, // of if it doesn't fit anywhere then the place with the least overflow // choices: Array // Array of elements like: {corner: 'TL', pos: {x: 10, y: 20} } // Above example says to put the top-left corner of the node at (10,20) // layoutNode: Function(node, aroundNodeCorner, nodeCorner, size) // for things like tooltip, they are displayed differently (and have different dimensions) // based on their orientation relative to the parent. This adjusts the popup based on orientation. // It also passes in the available size for the popup, which is useful for tooltips to // tell them that their width is limited to a certain amount. layoutNode() may return a value expressing // how much the popup had to be modified to fit into the available space. This is used to determine // what the best placement is. // aroundNodeCoords: Object // Size of aroundNode, ex: {w: 200, h: 50} // get {x: 10, y: 10, w: 100, h:100} type obj representing position of // viewport over document var view = winUtils.getBox(); // This won't work if the node is inside a <div style="position: relative">, // so reattach it to win.doc.body. (Otherwise, the positioning will be wrong // and also it might get cutoff) if(!node.parentNode || String(node.parentNode.tagName).toLowerCase() != "body"){ win.body().appendChild(node); } var best = null; array.some(choices, function(choice){ var corner = choice.corner; var pos = choice.pos; var overflow = 0; // calculate amount of space available given specified position of node var spaceAvailable = { w: { 'L': view.l + view.w - pos.x, 'R': pos.x - view.l, 'M': view.w }[corner.charAt(1)], h: { 'T': view.t + view.h - pos.y, 'B': pos.y - view.t, 'M': view.h }[corner.charAt(0)] }; // configure node to be displayed in given position relative to button // (need to do this in order to get an accurate size for the node, because // a tooltip's size changes based on position, due to triangle) if(layoutNode){ var res = layoutNode(node, choice.aroundCorner, corner, spaceAvailable, aroundNodeCoords); overflow = typeof res == "undefined" ? 0 : res; } // get node's size var style = node.style; var oldDisplay = style.display; var oldVis = style.visibility; if(style.display == "none"){ style.visibility = "hidden"; style.display = ""; } var mb = domGeometry. getMarginBox(node); style.display = oldDisplay; style.visibility = oldVis; // coordinates and size of node with specified corner placed at pos, // and clipped by viewport var startXpos = { 'L': pos.x, 'R': pos.x - mb.w, 'M': Math.max(view.l, Math.min(view.l + view.w, pos.x + (mb.w >> 1)) - mb.w) // M orientation is more flexible }[corner.charAt(1)], startYpos = { 'T': pos.y, 'B': pos.y - mb.h, 'M': Math.max(view.t, Math.min(view.t + view.h, pos.y + (mb.h >> 1)) - mb.h) }[corner.charAt(0)], startX = Math.max(view.l, startXpos), startY = Math.max(view.t, startYpos), endX = Math.min(view.l + view.w, startXpos + mb.w), endY = Math.min(view.t + view.h, startYpos + mb.h), width = endX - startX, height = endY - startY; overflow += (mb.w - width) + (mb.h - height); if(best == null || overflow < best.overflow){ best = { corner: corner, aroundCorner: choice.aroundCorner, x: startX, y: startY, w: width, h: height, overflow: overflow, spaceAvailable: spaceAvailable }; } return !overflow; }); // In case the best position is not the last one we checked, need to call // layoutNode() again. if(best.overflow && layoutNode){ layoutNode(node, best.aroundCorner, best.corner, best.spaceAvailable, aroundNodeCoords); } // And then position the node. Do this last, after the layoutNode() above // has sized the node, due to browser quirks when the viewport is scrolled // (specifically that a Tooltip will shrink to fit as though the window was // scrolled to the left). // // In RTL mode, set style.right rather than style.left so in the common case, // window resizes move the popup along with the aroundNode. var l = domGeometry.isBodyLtr(), s = node.style; s.top = best.y + "px"; s[l ? "left" : "right"] = (l ? best.x : view.w - best.x - best.w) + "px"; s[l ? "right" : "left"] = "auto"; // needed for FF or else tooltip goes to far left return best; } /*===== dijit.place.__Position = function(){ // x: Integer // horizontal coordinate in pixels, relative to document body // y: Integer // vertical coordinate in pixels, relative to document body this.x = x; this.y = y; }; =====*/ /*===== dijit.place.__Rectangle = function(){ // x: Integer // horizontal offset in pixels, relative to document body // y: Integer // vertical offset in pixels, relative to document body // w: Integer // width in pixels. Can also be specified as "width" for backwards-compatibility. // h: Integer // height in pixels. Can also be specified as "height" from backwards-compatibility. this.x = x; this.y = y; this.w = w; this.h = h; }; =====*/ return (dijit.place = { // summary: // Code to place a DOMNode relative to another DOMNode. // Load using require(["dijit/place"], function(place){ ... }). at: function(node, pos, corners, padding){ // summary: // Positions one of the node's corners at specified position // such that node is fully visible in viewport. // description: // NOTE: node is assumed to be absolutely or relatively positioned. // node: DOMNode // The node to position // pos: dijit.place.__Position // Object like {x: 10, y: 20} // corners: String[] // Array of Strings representing order to try corners in, like ["TR", "BL"]. // Possible values are: // * "BL" - bottom left // * "BR" - bottom right // * "TL" - top left // * "TR" - top right // padding: dijit.place.__Position? // optional param to set padding, to put some buffer around the element you want to position. // example: // Try to place node's top right corner at (10,20). // If that makes node go (partially) off screen, then try placing // bottom left corner at (10,20). // | place(node, {x: 10, y: 20}, ["TR", "BL"]) var choices = array.map(corners, function(corner){ var c = { corner: corner, pos: {x:pos.x,y:pos.y} }; if(padding){ c.pos.x += corner.charAt(1) == 'L' ? padding.x : -padding.x; c.pos.y += corner.charAt(0) == 'T' ? padding.y : -padding.y; } return c; }); return _place(node, choices); }, around: function( /*DomNode*/ node, /*DomNode || dijit.place.__Rectangle*/ anchor, /*String[]*/ positions, /*Boolean*/ leftToRight, /*Function?*/ layoutNode){ // summary: // Position node adjacent or kitty-corner to anchor // such that it's fully visible in viewport. // // description: // Place node such that corner of node touches a corner of // aroundNode, and that node is fully visible. // // anchor: // Either a DOMNode or a __Rectangle (object with x, y, width, height). // // positions: // Ordered list of positions to try matching up. // * before: places drop down to the left of the anchor node/widget, or to the right in // the case of RTL scripts like Hebrew and Arabic // * after: places drop down to the right of the anchor node/widget, or to the left in // the case of RTL scripts like Hebrew and Arabic // * above: drop down goes above anchor node // * above-alt: same as above except right sides aligned instead of left // * below: drop down goes below anchor node // * below-alt: same as below except right sides aligned instead of left // // layoutNode: Function(node, aroundNodeCorner, nodeCorner) // For things like tooltip, they are displayed differently (and have different dimensions) // based on their orientation relative to the parent. This adjusts the popup based on orientation. // // leftToRight: // True if widget is LTR, false if widget is RTL. Affects the behavior of "above" and "below" // positions slightly. // // example: // | placeAroundNode(node, aroundNode, {'BL':'TL', 'TR':'BR'}); // This will try to position node such that node's top-left corner is at the same position // as the bottom left corner of the aroundNode (ie, put node below // aroundNode, with left edges aligned). If that fails it will try to put // the bottom-right corner of node where the top right corner of aroundNode is // (ie, put node above aroundNode, with right edges aligned) // // if around is a DOMNode (or DOMNode id), convert to coordinates var aroundNodePos = (typeof anchor == "string" || "offsetWidth" in anchor) ? domGeometry.position(anchor, true) : anchor; // Adjust anchor positioning for the case that a parent node has overflw hidden, therefore cuasing the anchor not to be completely visible if(anchor.parentNode){ var parent = anchor.parentNode; while(parent && parent.nodeType == 1 && parent.nodeName != "BODY"){ //ignoring the body will help performance var parentPos = domGeometry.position(parent, true); var parentStyleOverflow = domStyle.getComputedStyle(parent).overflow; if(parentStyleOverflow == "hidden" || parentStyleOverflow == "auto" || parentStyleOverflow == "scroll"){ var bottomYCoord = Math.min(aroundNodePos.y + aroundNodePos.h, parentPos.y + parentPos.h); var rightXCoord = Math.min(aroundNodePos.x + aroundNodePos.w, parentPos.x + parentPos.w); aroundNodePos.x = Math.max(aroundNodePos.x, parentPos.x); aroundNodePos.y = Math.max(aroundNodePos.y, parentPos.y); aroundNodePos.h = bottomYCoord - aroundNodePos.y; aroundNodePos.w = rightXCoord - aroundNodePos.x; } parent = parent.parentNode; } } var x = aroundNodePos.x, y = aroundNodePos.y, width = "w" in aroundNodePos ? aroundNodePos.w : (aroundNodePos.w = aroundNodePos.width), height = "h" in aroundNodePos ? aroundNodePos.h : (kernel.deprecated("place.around: dijit.place.__Rectangle: { x:"+x+", y:"+y+", height:"+aroundNodePos.height+", width:"+width+" } has been deprecated. Please use { x:"+x+", y:"+y+", h:"+aroundNodePos.height+", w:"+width+" }", "", "2.0"), aroundNodePos.h = aroundNodePos.height); // Convert positions arguments into choices argument for _place() var choices = []; function push(aroundCorner, corner){ choices.push({ aroundCorner: aroundCorner, corner: corner, pos: { x: { 'L': x, 'R': x + width, 'M': x + (width >> 1) }[aroundCorner.charAt(1)], y: { 'T': y, 'B': y + height, 'M': y + (height >> 1) }[aroundCorner.charAt(0)] } }) } array.forEach(positions, function(pos){ var ltr = leftToRight; switch(pos){ case "above-centered": push("TM", "BM"); break; case "below-centered": push("BM", "TM"); break; case "after": ltr = !ltr; // fall through case "before": push(ltr ? "ML" : "MR", ltr ? "MR" : "ML"); break; case "below-alt": ltr = !ltr; // fall through case "below": // first try to align left borders, next try to align right borders (or reverse for RTL mode) push(ltr ? "BL" : "BR", ltr ? "TL" : "TR"); push(ltr ? "BR" : "BL", ltr ? "TR" : "TL"); break; case "above-alt": ltr = !ltr; // fall through case "above": // first try to align left borders, next try to align right borders (or reverse for RTL mode) push(ltr ? "TL" : "TR", ltr ? "BL" : "BR"); push(ltr ? "TR" : "TL", ltr ? "BR" : "BL"); break; default: // To assist dijit/_base/place, accept arguments of type {aroundCorner: "BL", corner: "TL"}. // Not meant to be used directly. push(pos.aroundCorner, pos.corner); } }); var position = _place(node, choices, layoutNode, {w: width, h: height}); position.aroundNodePos = aroundNodePos; return position; } }); }); }, 'dijit/_Widget':function(){ define("dijit/_Widget", [ "dojo/aspect", // aspect.around "dojo/_base/config", // config.isDebug "dojo/_base/connect", // connect.connect "dojo/_base/declare", // declare "dojo/_base/kernel", // kernel.deprecated "dojo/_base/lang", // lang.hitch "dojo/query", "dojo/ready", "./registry", // registry.byNode "./_WidgetBase", "./_OnDijitClickMixin", "./_FocusMixin", "dojo/uacss", // browser sniffing (included for back-compat; subclasses may be using) "./hccss" // high contrast mode sniffing (included to set CSS classes on <body>, module ret value unused) ], function(aspect, config, connect, declare, kernel, lang, query, ready, registry, _WidgetBase, _OnDijitClickMixin, _FocusMixin){ /*===== var _WidgetBase = dijit._WidgetBase; var _OnDijitClickMixin = dijit._OnDijitClickMixin; var _FocusMixin = dijit._FocusMixin; =====*/ // module: // dijit/_Widget // summary: // Old base for widgets. New widgets should extend _WidgetBase instead function connectToDomNode(){ // summary: // If user connects to a widget method === this function, then they will // instead actually be connecting the equivalent event on this.domNode } // Trap dojo.connect() calls to connectToDomNode methods, and redirect to _Widget.on() function aroundAdvice(originalConnect){ return function(obj, event, scope, method){ if(obj && typeof event == "string" && obj[event] == connectToDomNode){ return obj.on(event.substring(2).toLowerCase(), lang.hitch(scope, method)); } return originalConnect.apply(connect, arguments); }; } aspect.around(connect, "connect", aroundAdvice); if(kernel.connect){ aspect.around(kernel, "connect", aroundAdvice); } var _Widget = declare("dijit._Widget", [_WidgetBase, _OnDijitClickMixin, _FocusMixin], { // summary: // Base class for all Dijit widgets. // // Extends _WidgetBase, adding support for: // - declaratively/programatically specifying widget initialization parameters like // onMouseMove="foo" that call foo when this.domNode gets a mousemove event // - ondijitclick // Support new data-dojo-attach-event="ondijitclick: ..." that is triggered by a mouse click or a SPACE/ENTER keypress // - focus related functions // In particular, the onFocus()/onBlur() callbacks. Driven internally by // dijit/_base/focus.js. // - deprecated methods // - onShow(), onHide(), onClose() // // Also, by loading code in dijit/_base, turns on: // - browser sniffing (putting browser id like .dj_ie on <html> node) // - high contrast mode sniffing (add .dijit_a11y class to <body> if machine is in high contrast mode) ////////////////// DEFERRED CONNECTS /////////////////// onClick: connectToDomNode, /*===== onClick: function(event){ // summary: // Connect to this function to receive notifications of mouse click events. // event: // mouse Event // tags: // callback }, =====*/ onDblClick: connectToDomNode, /*===== onDblClick: function(event){ // summary: // Connect to this function to receive notifications of mouse double click events. // event: // mouse Event // tags: // callback }, =====*/ onKeyDown: connectToDomNode, /*===== onKeyDown: function(event){ // summary: // Connect to this function to receive notifications of keys being pressed down. // event: // key Event // tags: // callback }, =====*/ onKeyPress: connectToDomNode, /*===== onKeyPress: function(event){ // summary: // Connect to this function to receive notifications of printable keys being typed. // event: // key Event // tags: // callback }, =====*/ onKeyUp: connectToDomNode, /*===== onKeyUp: function(event){ // summary: // Connect to this function to receive notifications of keys being released. // event: // key Event // tags: // callback }, =====*/ onMouseDown: connectToDomNode, /*===== onMouseDown: function(event){ // summary: // Connect to this function to receive notifications of when the mouse button is pressed down. // event: // mouse Event // tags: // callback }, =====*/ onMouseMove: connectToDomNode, /*===== onMouseMove: function(event){ // summary: // Connect to this function to receive notifications of when the mouse moves over nodes contained within this widget. // event: // mouse Event // tags: // callback }, =====*/ onMouseOut: connectToDomNode, /*===== onMouseOut: function(event){ // summary: // Connect to this function to receive notifications of when the mouse moves off of nodes contained within this widget. // event: // mouse Event // tags: // callback }, =====*/ onMouseOver: connectToDomNode, /*===== onMouseOver: function(event){ // summary: // Connect to this function to receive notifications of when the mouse moves onto nodes contained within this widget. // event: // mouse Event // tags: // callback }, =====*/ onMouseLeave: connectToDomNode, /*===== onMouseLeave: function(event){ // summary: // Connect to this function to receive notifications of when the mouse moves off of this widget. // event: // mouse Event // tags: // callback }, =====*/ onMouseEnter: connectToDomNode, /*===== onMouseEnter: function(event){ // summary: // Connect to this function to receive notifications of when the mouse moves onto this widget. // event: // mouse Event // tags: // callback }, =====*/ onMouseUp: connectToDomNode, /*===== onMouseUp: function(event){ // summary: // Connect to this function to receive notifications of when the mouse button is released. // event: // mouse Event // tags: // callback }, =====*/ constructor: function(params){ // extract parameters like onMouseMove that should connect directly to this.domNode this._toConnect = {}; for(var name in params){ if(this[name] === connectToDomNode){ this._toConnect[name.replace(/^on/, "").toLowerCase()] = params[name]; delete params[name]; } } }, postCreate: function(){ this.inherited(arguments); // perform connection from this.domNode to user specified handlers (ex: onMouseMove) for(var name in this._toConnect){ this.on(name, this._toConnect[name]); } delete this._toConnect; }, on: function(/*String*/ type, /*Function*/ func){ if(this[this._onMap(type)] === connectToDomNode){ // Use connect.connect() rather than on() to get handling for "onmouseenter" on non-IE, etc. // Also, need to specify context as "this" rather than the default context of the DOMNode return connect.connect(this.domNode, type.toLowerCase(), this, func); } return this.inherited(arguments); }, _setFocusedAttr: function(val){ // Remove this method in 2.0 (or sooner), just here to set _focused == focused, for back compat // (but since it's a private variable we aren't required to keep supporting it). this._focused = val; this._set("focused", val); }, ////////////////// DEPRECATED METHODS /////////////////// setAttribute: function(/*String*/ attr, /*anything*/ value){ // summary: // Deprecated. Use set() instead. // tags: // deprecated kernel.deprecated(this.declaredClass+"::setAttribute(attr, value) is deprecated. Use set() instead.", "", "2.0"); this.set(attr, value); }, attr: function(/*String|Object*/name, /*Object?*/value){ // summary: // Set or get properties on a widget instance. // name: // The property to get or set. If an object is passed here and not // a string, its keys are used as names of attributes to be set // and the value of the object as values to set in the widget. // value: // Optional. If provided, attr() operates as a setter. If omitted, // the current value of the named property is returned. // description: // This method is deprecated, use get() or set() directly. // Print deprecation warning but only once per calling function if(config.isDebug){ var alreadyCalledHash = arguments.callee._ach || (arguments.callee._ach = {}), caller = (arguments.callee.caller || "unknown caller").toString(); if(!alreadyCalledHash[caller]){ kernel.deprecated(this.declaredClass + "::attr() is deprecated. Use get() or set() instead, called from " + caller, "", "2.0"); alreadyCalledHash[caller] = true; } } var args = arguments.length; if(args >= 2 || typeof name === "object"){ // setter return this.set.apply(this, arguments); }else{ // getter return this.get(name); } }, getDescendants: function(){ // summary: // Returns all the widgets contained by this, i.e., all widgets underneath this.containerNode. // This method should generally be avoided as it returns widgets declared in templates, which are // supposed to be internal/hidden, but it's left here for back-compat reasons. kernel.deprecated(this.declaredClass+"::getDescendants() is deprecated. Use getChildren() instead.", "", "2.0"); return this.containerNode ? query('[widgetId]', this.containerNode).map(registry.byNode) : []; // dijit._Widget[] }, ////////////////// MISCELLANEOUS METHODS /////////////////// _onShow: function(){ // summary: // Internal method called when this widget is made visible. // See `onShow` for details. this.onShow(); }, onShow: function(){ // summary: // Called when this widget becomes the selected pane in a // `dijit.layout.TabContainer`, `dijit.layout.StackContainer`, // `dijit.layout.AccordionContainer`, etc. // // Also called to indicate display of a `dijit.Dialog`, `dijit.TooltipDialog`, or `dijit.TitlePane`. // tags: // callback }, onHide: function(){ // summary: // Called when another widget becomes the selected pane in a // `dijit.layout.TabContainer`, `dijit.layout.StackContainer`, // `dijit.layout.AccordionContainer`, etc. // // Also called to indicate hide of a `dijit.Dialog`, `dijit.TooltipDialog`, or `dijit.TitlePane`. // tags: // callback }, onClose: function(){ // summary: // Called when this widget is being displayed as a popup (ex: a Calendar popped // up from a DateTextBox), and it is hidden. // This is called from the dijit.popup code, and should not be called directly. // // Also used as a parameter for children of `dijit.layout.StackContainer` or subclasses. // Callback if a user tries to close the child. Child will be closed if this function returns true. // tags: // extension return true; // Boolean } }); // For back-compat, remove in 2.0. if(!kernel.isAsync){ ready(0, function(){ var requires = ["dijit/_base"]; require(requires); // use indirection so modules not rolled into a build }); } return _Widget; }); }, 'dojo/cache':function(){ define(["./_base/kernel", "./text"], function(dojo, text){ // module: // dojo/cache // summary: // The module defines dojo.cache by loading dojo/text. //dojo.cache is defined in dojo/text return dojo.cache; }); }, 'dijit/_FocusMixin':function(){ define([ "./focus", "./_WidgetBase", "dojo/_base/declare", // declare "dojo/_base/lang" // lang.extend ], function(focus, _WidgetBase, declare, lang){ /*===== var _WidgetBase = dijit._WidgetBase; =====*/ // module: // dijit/_FocusMixin // summary: // Mixin to widget to provide _onFocus() and _onBlur() methods that // fire when a widget or it's descendants get/lose focus // We don't know where _FocusMixin will occur in the inheritance chain, but we need the _onFocus()/_onBlur() below // to be last in the inheritance chain, so mixin to _WidgetBase. lang.extend(_WidgetBase, { // focused: [readonly] Boolean // This widget or a widget it contains has focus, or is "active" because // it was recently clicked. focused: false, onFocus: function(){ // summary: // Called when the widget becomes "active" because // it or a widget inside of it either has focus, or has recently // been clicked. // tags: // callback }, onBlur: function(){ // summary: // Called when the widget stops being "active" because // focus moved to something outside of it, or the user // clicked somewhere outside of it, or the widget was // hidden. // tags: // callback }, _onFocus: function(){ // summary: // This is where widgets do processing for when they are active, // such as changing CSS classes. See onFocus() for more details. // tags: // protected this.onFocus(); }, _onBlur: function(){ // summary: // This is where widgets do processing for when they stop being active, // such as changing CSS classes. See onBlur() for more details. // tags: // protected this.onBlur(); } }); return declare("dijit._FocusMixin", null, { // summary: // Mixin to widget to provide _onFocus() and _onBlur() methods that // fire when a widget or it's descendants get/lose focus // flag that I want _onFocus()/_onBlur() notifications from focus manager _focusManager: focus }); }); }, 'dijit/_OnDijitClickMixin':function(){ define("dijit/_OnDijitClickMixin", [ "dojo/on", "dojo/_base/array", // array.forEach "dojo/keys", // keys.ENTER keys.SPACE "dojo/_base/declare", // declare "dojo/_base/sniff", // has("ie") "dojo/_base/unload", // unload.addOnWindowUnload "dojo/_base/window" // win.doc.addEventListener win.doc.attachEvent win.doc.detachEvent ], function(on, array, keys, declare, has, unload, win){ // module: // dijit/_OnDijitClickMixin // summary: // Mixin so you can pass "ondijitclick" to this.connect() method, // as a way to handle clicks by mouse, or by keyboard (SPACE/ENTER key) // Keep track of where the last keydown event was, to help avoid generating // spurious ondijitclick events when: // 1. focus is on a <button> or <a> // 2. user presses then releases the ENTER key // 3. onclick handler fires and shifts focus to another node, with an ondijitclick handler // 4. onkeyup event fires, causing the ondijitclick handler to fire var lastKeyDownNode = null; if(has("ie")){ (function(){ var keydownCallback = function(evt){ lastKeyDownNode = evt.srcElement; }; win.doc.attachEvent('onkeydown', keydownCallback); unload.addOnWindowUnload(function(){ win.doc.detachEvent('onkeydown', keydownCallback); }); })(); }else{ win.doc.addEventListener('keydown', function(evt){ lastKeyDownNode = evt.target; }, true); } // Custom a11yclick (a.k.a. ondijitclick) event var a11yclick = function(node, listener){ if(/input|button/i.test(node.nodeName)){ // pass through, the browser already generates click event on SPACE/ENTER key return on(node, "click", listener); }else{ // Don't fire the click event unless both the keydown and keyup occur on this node. // Avoids problems where focus shifted to this node or away from the node on keydown, // either causing this node to process a stray keyup event, or causing another node // to get a stray keyup event. function clickKey(/*Event*/ e){ return (e.keyCode == keys.ENTER || e.keyCode == keys.SPACE) && !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey; } var handles = [ on(node, "keypress", function(e){ //console.log(this.id + ": onkeydown, e.target = ", e.target, ", lastKeyDownNode was ", lastKeyDownNode, ", equality is ", (e.target === lastKeyDownNode)); if(clickKey(e)){ // needed on IE for when focus changes between keydown and keyup - otherwise dropdown menus do not work lastKeyDownNode = e.target; // Prevent viewport scrolling on space key in IE<9. // (Reproducible on test_Button.html on any of the first dijit.form.Button examples) // Do this onkeypress rather than onkeydown because onkeydown.preventDefault() will // suppress the onkeypress event, breaking _HasDropDown e.preventDefault(); } }), on(node, "keyup", function(e){ //console.log(this.id + ": onkeyup, e.target = ", e.target, ", lastKeyDownNode was ", lastKeyDownNode, ", equality is ", (e.target === lastKeyDownNode)); if(clickKey(e) && e.target == lastKeyDownNode){ // === breaks greasemonkey //need reset here or have problems in FF when focus returns to trigger element after closing popup/alert lastKeyDownNode = null; listener.call(this, e); } }), on(node, "click", function(e){ // and connect for mouse clicks too (or touch-clicks on mobile) listener.call(this, e); }) ]; return { remove: function(){ array.forEach(handles, function(h){ h.remove(); }); } }; } }; return declare("dijit._OnDijitClickMixin", null, { connect: function( /*Object|null*/ obj, /*String|Function*/ event, /*String|Function*/ method){ // summary: // Connects specified obj/event to specified method of this object // and registers for disconnect() on widget destroy. // description: // Provide widget-specific analog to connect.connect, except with the // implicit use of this widget as the target object. // This version of connect also provides a special "ondijitclick" // event which triggers on a click or space or enter keyup. // Events connected with `this.connect` are disconnected upon // destruction. // returns: // A handle that can be passed to `disconnect` in order to disconnect before // the widget is destroyed. // example: // | var btn = new dijit.form.Button(); // | // when foo.bar() is called, call the listener we're going to // | // provide in the scope of btn // | btn.connect(foo, "bar", function(){ // | console.debug(this.toString()); // | }); // tags: // protected return this.inherited(arguments, [obj, event == "ondijitclick" ? a11yclick : event, method]); } }); }); }, 'dijit/focus':function(){ define("dijit/focus", [ "dojo/aspect", "dojo/_base/declare", // declare "dojo/dom", // domAttr.get dom.isDescendant "dojo/dom-attr", // domAttr.get dom.isDescendant "dojo/dom-construct", // connect to domConstruct.empty, domConstruct.destroy "dojo/Evented", "dojo/_base/lang", // lang.hitch "dojo/on", "dojo/ready", "dojo/_base/sniff", // has("ie") "dojo/Stateful", "dojo/_base/unload", // unload.addOnWindowUnload "dojo/_base/window", // win.body "dojo/window", // winUtils.get "./a11y", // a11y.isTabNavigable "./registry", // registry.byId "." // to set dijit.focus ], function(aspect, declare, dom, domAttr, domConstruct, Evented, lang, on, ready, has, Stateful, unload, win, winUtils, a11y, registry, dijit){ // module: // dijit/focus // summary: // Returns a singleton that tracks the currently focused node, and which widgets are currently "active". /*===== dijit.focus = { // summary: // Tracks the currently focused node, and which widgets are currently "active". // Access via require(["dijit/focus"], function(focus){ ... }). // // A widget is considered active if it or a descendant widget has focus, // or if a non-focusable node of this widget or a descendant was recently clicked. // // Call focus.watch("curNode", callback) to track the current focused DOMNode, // or focus.watch("activeStack", callback) to track the currently focused stack of widgets. // // Call focus.on("widget-blur", func) or focus.on("widget-focus", ...) to monitor when // when widgets become active/inactive // // Finally, focus(node) will focus a node, suppressing errors if the node doesn't exist. // curNode: DomNode // Currently focused item on screen curNode: null, // activeStack: dijit._Widget[] // List of currently active widgets (focused widget and it's ancestors) activeStack: [], registerIframe: function(iframe){ // summary: // Registers listeners on the specified iframe so that any click // or focus event on that iframe (or anything in it) is reported // as a focus/click event on the <iframe> itself. // description: // Currently only used by editor. // returns: // Handle with remove() method to deregister. }, registerWin: function(targetWindow, effectiveNode){ // summary: // Registers listeners on the specified window (either the main // window or an iframe's window) to detect when the user has clicked somewhere // or focused somewhere. // description: // Users should call registerIframe() instead of this method. // targetWindow: Window? // If specified this is the window associated with the iframe, // i.e. iframe.contentWindow. // effectiveNode: DOMNode? // If specified, report any focus events inside targetWindow as // an event on effectiveNode, rather than on evt.target. // returns: // Handle with remove() method to deregister. } }; =====*/ var FocusManager = declare([Stateful, Evented], { // curNode: DomNode // Currently focused item on screen curNode: null, // activeStack: dijit._Widget[] // List of currently active widgets (focused widget and it's ancestors) activeStack: [], constructor: function(){ // Don't leave curNode/prevNode pointing to bogus elements var check = lang.hitch(this, function(node){ if(dom.isDescendant(this.curNode, node)){ this.set("curNode", null); } if(dom.isDescendant(this.prevNode, node)){ this.set("prevNode", null); } }); aspect.before(domConstruct, "empty", check); aspect.before(domConstruct, "destroy", check); }, registerIframe: function(/*DomNode*/ iframe){ // summary: // Registers listeners on the specified iframe so that any click // or focus event on that iframe (or anything in it) is reported // as a focus/click event on the <iframe> itself. // description: // Currently only used by editor. // returns: // Handle with remove() method to deregister. return this.registerWin(iframe.contentWindow, iframe); }, registerWin: function(/*Window?*/targetWindow, /*DomNode?*/ effectiveNode){ // summary: // Registers listeners on the specified window (either the main // window or an iframe's window) to detect when the user has clicked somewhere // or focused somewhere. // description: // Users should call registerIframe() instead of this method. // targetWindow: // If specified this is the window associated with the iframe, // i.e. iframe.contentWindow. // effectiveNode: // If specified, report any focus events inside targetWindow as // an event on effectiveNode, rather than on evt.target. // returns: // Handle with remove() method to deregister. // TODO: make this function private in 2.0; Editor/users should call registerIframe(), var _this = this; var mousedownListener = function(evt){ _this._justMouseDowned = true; setTimeout(function(){ _this._justMouseDowned = false; }, 0); // workaround weird IE bug where the click is on an orphaned node // (first time clicking a Select/DropDownButton inside a TooltipDialog) if(has("ie") && evt && evt.srcElement && evt.srcElement.parentNode == null){ return; } _this._onTouchNode(effectiveNode || evt.target || evt.srcElement, "mouse"); }; // Listen for blur and focus events on targetWindow's document. // IIRC, I'm using attachEvent() rather than dojo.connect() because focus/blur events don't bubble // through dojo.connect(), and also maybe to catch the focus events early, before onfocus handlers // fire. // Connect to <html> (rather than document) on IE to avoid memory leaks, but document on other browsers because // (at least for FF) the focus event doesn't fire on <html> or <body>. var doc = has("ie") ? targetWindow.document.documentElement : targetWindow.document; if(doc){ if(has("ie")){ targetWindow.document.body.attachEvent('onmousedown', mousedownListener); var activateListener = function(evt){ // IE reports that nodes like <body> have gotten focus, even though they have tabIndex=-1, // ignore those events var tag = evt.srcElement.tagName.toLowerCase(); if(tag == "#document" || tag == "body"){ return; } // Previous code called _onTouchNode() for any activate event on a non-focusable node. Can // probably just ignore such an event as it will be handled by onmousedown handler above, but // leaving the code for now. if(a11y.isTabNavigable(evt.srcElement)){ _this._onFocusNode(effectiveNode || evt.srcElement); }else{ _this._onTouchNode(effectiveNode || evt.srcElement); } }; doc.attachEvent('onactivate', activateListener); var deactivateListener = function(evt){ _this._onBlurNode(effectiveNode || evt.srcElement); }; doc.attachEvent('ondeactivate', deactivateListener); return { remove: function(){ targetWindow.document.detachEvent('onmousedown', mousedownListener); doc.detachEvent('onactivate', activateListener); doc.detachEvent('ondeactivate', deactivateListener); doc = null; // prevent memory leak (apparent circular reference via closure) } }; }else{ doc.body.addEventListener('mousedown', mousedownListener, true); doc.body.addEventListener('touchstart', mousedownListener, true); var focusListener = function(evt){ _this._onFocusNode(effectiveNode || evt.target); }; doc.addEventListener('focus', focusListener, true); var blurListener = function(evt){ _this._onBlurNode(effectiveNode || evt.target); }; doc.addEventListener('blur', blurListener, true); return { remove: function(){ doc.body.removeEventListener('mousedown', mousedownListener, true); doc.body.removeEventListener('touchstart', mousedownListener, true); doc.removeEventListener('focus', focusListener, true); doc.removeEventListener('blur', blurListener, true); doc = null; // prevent memory leak (apparent circular reference via closure) } }; } } }, _onBlurNode: function(/*DomNode*/ /*===== node =====*/){ // summary: // Called when focus leaves a node. // Usually ignored, _unless_ it *isn't* followed by touching another node, // which indicates that we tabbed off the last field on the page, // in which case every widget is marked inactive this.set("prevNode", this.curNode); this.set("curNode", null); if(this._justMouseDowned){ // the mouse down caused a new widget to be marked as active; this blur event // is coming late, so ignore it. return; } // if the blur event isn't followed by a focus event then mark all widgets as inactive. if(this._clearActiveWidgetsTimer){ clearTimeout(this._clearActiveWidgetsTimer); } this._clearActiveWidgetsTimer = setTimeout(lang.hitch(this, function(){ delete this._clearActiveWidgetsTimer; this._setStack([]); this.prevNode = null; }), 100); }, _onTouchNode: function(/*DomNode*/ node, /*String*/ by){ // summary: // Callback when node is focused or mouse-downed // node: // The node that was touched. // by: // "mouse" if the focus/touch was caused by a mouse down event // ignore the recent blurNode event if(this._clearActiveWidgetsTimer){ clearTimeout(this._clearActiveWidgetsTimer); delete this._clearActiveWidgetsTimer; } // compute stack of active widgets (ex: ComboButton --> Menu --> MenuItem) var newStack=[]; try{ while(node){ var popupParent = domAttr.get(node, "dijitPopupParent"); if(popupParent){ node=registry.byId(popupParent).domNode; }else if(node.tagName && node.tagName.toLowerCase() == "body"){ // is this the root of the document or just the root of an iframe? if(node === win.body()){ // node is the root of the main document break; } // otherwise, find the iframe this node refers to (can't access it via parentNode, // need to do this trick instead). window.frameElement is supported in IE/FF/Webkit node=winUtils.get(node.ownerDocument).frameElement; }else{ // if this node is the root node of a widget, then add widget id to stack, // except ignore clicks on disabled widgets (actually focusing a disabled widget still works, // to support MenuItem) var id = node.getAttribute && node.getAttribute("widgetId"), widget = id && registry.byId(id); if(widget && !(by == "mouse" && widget.get("disabled"))){ newStack.unshift(id); } node=node.parentNode; } } }catch(e){ /* squelch */ } this._setStack(newStack, by); }, _onFocusNode: function(/*DomNode*/ node){ // summary: // Callback when node is focused if(!node){ return; } if(node.nodeType == 9){ // Ignore focus events on the document itself. This is here so that // (for example) clicking the up/down arrows of a spinner // (which don't get focus) won't cause that widget to blur. (FF issue) return; } this._onTouchNode(node); if(node == this.curNode){ return; } this.set("curNode", node); }, _setStack: function(/*String[]*/ newStack, /*String*/ by){ // summary: // The stack of active widgets has changed. Send out appropriate events and records new stack. // newStack: // array of widget id's, starting from the top (outermost) widget // by: // "mouse" if the focus/touch was caused by a mouse down event var oldStack = this.activeStack; this.set("activeStack", newStack); // compare old stack to new stack to see how many elements they have in common for(var nCommon=0; nCommon<Math.min(oldStack.length, newStack.length); nCommon++){ if(oldStack[nCommon] != newStack[nCommon]){ break; } } var widget; // for all elements that have gone out of focus, set focused=false for(var i=oldStack.length-1; i>=nCommon; i--){ widget = registry.byId(oldStack[i]); if(widget){ widget._hasBeenBlurred = true; // TODO: used by form widgets, should be moved there widget.set("focused", false); if(widget._focusManager == this){ widget._onBlur(by); } this.emit("widget-blur", widget, by); } } // for all element that have come into focus, set focused=true for(i=nCommon; i<newStack.length; i++){ widget = registry.byId(newStack[i]); if(widget){ widget.set("focused", true); if(widget._focusManager == this){ widget._onFocus(by); } this.emit("widget-focus", widget, by); } } }, focus: function(node){ // summary: // Focus the specified node, suppressing errors if they occur if(node){ try{ node.focus(); }catch(e){/*quiet*/} } } }); var singleton = new FocusManager(); // register top window and all the iframes it contains ready(function(){ var handle = singleton.registerWin(win.doc.parentWindow || win.doc.defaultView); if(has("ie")){ unload.addOnWindowUnload(function(){ handle.remove(); handle = null; }) } }); // Setup dijit.focus as a pointer to the singleton but also (for backwards compatibility) // as a function to set focus. dijit.focus = function(node){ singleton.focus(node); // indirection here allows dijit/_base/focus.js to override behavior }; for(var attr in singleton){ if(!/^_/.test(attr)){ dijit.focus[attr] = typeof singleton[attr] == "function" ? lang.hitch(singleton, attr) : singleton[attr]; } } singleton.watch(function(attr, oldVal, newVal){ dijit.focus[attr] = newVal; }); return singleton; }); }, 'dijit/_base/sniff':function(){ define("dijit/_base/sniff", [ "dojo/uacss" ], function(){ // module: // dijit/_base/sniff // summary: // Back compatibility module, new code should require dojo/uacss directly instead of this module. }); }, 'dijit/main':function(){ define("dijit/main", [ "dojo/_base/kernel" ], function(dojo){ // module: // dijit // summary: // The dijit package main module return dojo.dijit; }); }, 'dojo/date/stamp':function(){ define(["../_base/kernel", "../_base/lang", "../_base/array"], function(dojo, lang, array) { // module: // dojo/date/stamp // summary: // TODOC lang.getObject("date.stamp", true, dojo); // Methods to convert dates to or from a wire (string) format using well-known conventions dojo.date.stamp.fromISOString = function(/*String*/formattedString, /*Number?*/defaultTime){ // summary: // Returns a Date object given a string formatted according to a subset of the ISO-8601 standard. // // description: // Accepts a string formatted according to a profile of ISO8601 as defined by // [RFC3339](http://www.ietf.org/rfc/rfc3339.txt), except that partial input is allowed. // Can also process dates as specified [by the W3C](http://www.w3.org/TR/NOTE-datetime) // The following combinations are valid: // // * dates only // | * yyyy // | * yyyy-MM // | * yyyy-MM-dd // * times only, with an optional time zone appended // | * THH:mm // | * THH:mm:ss // | * THH:mm:ss.SSS // * and "datetimes" which could be any combination of the above // // timezones may be specified as Z (for UTC) or +/- followed by a time expression HH:mm // Assumes the local time zone if not specified. Does not validate. Improperly formatted // input may return null. Arguments which are out of bounds will be handled // by the Date constructor (e.g. January 32nd typically gets resolved to February 1st) // Only years between 100 and 9999 are supported. // // formattedString: // A string such as 2005-06-30T08:05:00-07:00 or 2005-06-30 or T08:05:00 // // defaultTime: // Used for defaults for fields omitted in the formattedString. // Uses 1970-01-01T00:00:00.0Z by default. if(!dojo.date.stamp._isoRegExp){ dojo.date.stamp._isoRegExp = //TODO: could be more restrictive and check for 00-59, etc. /^(?:(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(.\d+)?)?((?:[+-](\d{2}):(\d{2}))|Z)?)?$/; } var match = dojo.date.stamp._isoRegExp.exec(formattedString), result = null; if(match){ match.shift(); if(match[1]){match[1]--;} // Javascript Date months are 0-based if(match[6]){match[6] *= 1000;} // Javascript Date expects fractional seconds as milliseconds if(defaultTime){ // mix in defaultTime. Relatively expensive, so use || operators for the fast path of defaultTime === 0 defaultTime = new Date(defaultTime); array.forEach(array.map(["FullYear", "Month", "Date", "Hours", "Minutes", "Seconds", "Milliseconds"], function(prop){ return defaultTime["get" + prop](); }), function(value, index){ match[index] = match[index] || value; }); } result = new Date(match[0]||1970, match[1]||0, match[2]||1, match[3]||0, match[4]||0, match[5]||0, match[6]||0); //TODO: UTC defaults if(match[0] < 100){ result.setFullYear(match[0] || 1970); } var offset = 0, zoneSign = match[7] && match[7].charAt(0); if(zoneSign != 'Z'){ offset = ((match[8] || 0) * 60) + (Number(match[9]) || 0); if(zoneSign != '-'){ offset *= -1; } } if(zoneSign){ offset -= result.getTimezoneOffset(); } if(offset){ result.setTime(result.getTime() + offset * 60000); } } return result; // Date or null }; /*===== dojo.date.stamp.__Options = function(){ // selector: String // "date" or "time" for partial formatting of the Date object. // Both date and time will be formatted by default. // zulu: Boolean // if true, UTC/GMT is used for a timezone // milliseconds: Boolean // if true, output milliseconds this.selector = selector; this.zulu = zulu; this.milliseconds = milliseconds; } =====*/ dojo.date.stamp.toISOString = function(/*Date*/dateObject, /*dojo.date.stamp.__Options?*/options){ // summary: // Format a Date object as a string according a subset of the ISO-8601 standard // // description: // When options.selector is omitted, output follows [RFC3339](http://www.ietf.org/rfc/rfc3339.txt) // The local time zone is included as an offset from GMT, except when selector=='time' (time without a date) // Does not check bounds. Only years between 100 and 9999 are supported. // // dateObject: // A Date object var _ = function(n){ return (n < 10) ? "0" + n : n; }; options = options || {}; var formattedDate = [], getter = options.zulu ? "getUTC" : "get", date = ""; if(options.selector != "time"){ var year = dateObject[getter+"FullYear"](); date = ["0000".substr((year+"").length)+year, _(dateObject[getter+"Month"]()+1), _(dateObject[getter+"Date"]())].join('-'); } formattedDate.push(date); if(options.selector != "date"){ var time = [_(dateObject[getter+"Hours"]()), _(dateObject[getter+"Minutes"]()), _(dateObject[getter+"Seconds"]())].join(':'); var millis = dateObject[getter+"Milliseconds"](); if(options.milliseconds){ time += "."+ (millis < 100 ? "0" : "") + _(millis); } if(options.zulu){ time += "Z"; }else if(options.selector != "time"){ var timezoneOffset = dateObject.getTimezoneOffset(); var absOffset = Math.abs(timezoneOffset); time += (timezoneOffset > 0 ? "-" : "+") + _(Math.floor(absOffset/60)) + ":" + _(absOffset%60); } formattedDate.push(time); } return formattedDate.join('T'); // String }; return dojo.date.stamp; }); }, 'dijit/form/_FormWidget':function(){ define("dijit/form/_FormWidget", [ "dojo/_base/declare", // declare "dojo/_base/kernel", // kernel.deprecated "dojo/ready", "../_Widget", "../_CssStateMixin", "../_TemplatedMixin", "./_FormWidgetMixin" ], function(declare, kernel, ready, _Widget, _CssStateMixin, _TemplatedMixin, _FormWidgetMixin){ /*===== var _Widget = dijit._Widget; var _TemplatedMixin = dijit._TemplatedMixin; var _CssStateMixin = dijit._CssStateMixin; var _FormWidgetMixin = dijit.form._FormWidgetMixin; =====*/ // module: // dijit/form/_FormWidget // summary: // FormWidget // Back compat w/1.6, remove for 2.0 if(!kernel.isAsync){ ready(0, function(){ var requires = ["dijit/form/_FormValueWidget"]; require(requires); // use indirection so modules not rolled into a build }); } return declare("dijit.form._FormWidget", [_Widget, _TemplatedMixin, _CssStateMixin, _FormWidgetMixin], { // summary: // Base class for widgets corresponding to native HTML elements such as <checkbox> or <button>, // which can be children of a <form> node or a `dijit.form.Form` widget. // // description: // Represents a single HTML element. // All these widgets should have these attributes just like native HTML input elements. // You can set them during widget construction or afterwards, via `dijit._Widget.attr`. // // They also share some common methods. setDisabled: function(/*Boolean*/ disabled){ // summary: // Deprecated. Use set('disabled', ...) instead. kernel.deprecated("setDisabled("+disabled+") is deprecated. Use set('disabled',"+disabled+") instead.", "", "2.0"); this.set('disabled', disabled); }, setValue: function(/*String*/ value){ // summary: // Deprecated. Use set('value', ...) instead. kernel.deprecated("dijit.form._FormWidget:setValue("+value+") is deprecated. Use set('value',"+value+") instead.", "", "2.0"); this.set('value', value); }, getValue: function(){ // summary: // Deprecated. Use get('value') instead. kernel.deprecated(this.declaredClass+"::getValue() is deprecated. Use get('value') instead.", "", "2.0"); return this.get('value'); }, postMixInProperties: function(){ // Setup name=foo string to be referenced from the template (but only if a name has been specified) // Unfortunately we can't use _setNameAttr to set the name due to IE limitations, see #8484, #8660. // Regarding escaping, see heading "Attribute values" in // http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2 this.nameAttrSetting = this.name ? ('name="' + this.name.replace(/'/g, "&quot;") + '"') : ''; this.inherited(arguments); }, // Override automatic assigning type --> focusNode, it causes exception on IE. // Instead, type must be specified as ${type} in the template, as part of the original DOM _setTypeAttr: null }); }); }, 'dijit/_base/typematic':function(){ define(["../typematic"], function(){ // for back-compat, just loads top level module }); }, 'dijit/_base/popup':function(){ define("dijit/_base/popup", [ "dojo/dom-class", // domClass.contains "../popup", "../BackgroundIframe" // just loading for back-compat, in case client code is referencing it ], function(domClass, popup){ // module: // dijit/_base/popup // summary: // Old module for popups, new code should use dijit/popup directly // Hack support for old API passing in node instead of a widget (to various methods) var origCreateWrapper = popup._createWrapper; popup._createWrapper = function(widget){ if(!widget.declaredClass){ // make fake widget to pass to new API widget = { _popupWrapper: (widget.parentNode && domClass.contains(widget.parentNode, "dijitPopup")) ? widget.parentNode : null, domNode: widget, destroy: function(){} }; } return origCreateWrapper.call(this, widget); }; // Support old format of orient parameter var origOpen = popup.open; popup.open = function(/*dijit.popup.__OpenArgs*/ args){ // Convert old hash structure (ex: {"BL": "TL", ...}) of orient to format compatible w/new popup.open() API. // Don't do conversion for: // - null parameter (that means to use the default positioning) // - "R" or "L" strings used to indicate positioning for context menus (when there is no around node) // - new format, ex: ["below", "above"] // - return value from deprecated dijit.getPopupAroundAlignment() method, // ex: ["below", "above"] if(args.orient && typeof args.orient != "string" && !("length" in args.orient)){ var ary = []; for(var key in args.orient){ ary.push({aroundCorner: key, corner: args.orient[key]}); } args.orient = ary; } return origOpen.call(this, args); }; return popup; }); }, 'dijit/_TemplatedMixin':function(){ 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/_base/sniff", // has("ie") "dojo/_base/unload", // unload.addOnWindowUnload "dojo/_base/window" // win.doc ], function(lang, touch, _WidgetBase, string, cache, array, declare, domConstruct, has, unload, win) { /*===== var _WidgetBase = dijit._WidgetBase; =====*/ // module: // dijit/_TemplatedMixin // summary: // Mixin for widgets that are instantiated from a template 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(){ 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,"&quot;"); //TODO: add &amp? 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); var node; if(lang.isString(cached)){ node = domConstruct.toDom(this._stringRepl(cached)); 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<nodes.length; x++){ 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){ // 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 // 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 == win.doc){ // 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); 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.) lang.extend(_WidgetBase,{ dojoAttachEvent: "", dojoAttachPoint: "" }); return _TemplatedMixin; }); }, 'dijit/_base/wai':function(){ define("dijit/_base/wai", [ "dojo/dom-attr", // domAttr.attr "dojo/_base/lang", // lang.mixin "..", // export symbols to dijit "../hccss" // not using this module directly, but loading it sets CSS flag on <html> ], function(domAttr, lang, dijit){ // module: // dijit/_base/wai // summary: // Deprecated methods for setting/getting wai roles and states. // New code should call setAttribute()/getAttribute() directly. // // Also loads hccss to apply dijit_a11y class to root node if machine is in high-contrast mode. lang.mixin(dijit, { hasWaiRole: function(/*Element*/ elem, /*String?*/ role){ // summary: // Determines if an element has a particular role. // returns: // True if elem has the specific role attribute and false if not. // For backwards compatibility if role parameter not provided, // returns true if has a role var waiRole = this.getWaiRole(elem); return role ? (waiRole.indexOf(role) > -1) : (waiRole.length > 0); }, getWaiRole: function(/*Element*/ elem){ // summary: // Gets the role for an element (which should be a wai role). // returns: // The role of elem or an empty string if elem // does not have a role. return lang.trim((domAttr.get(elem, "role") || "").replace("wairole:","")); }, setWaiRole: function(/*Element*/ elem, /*String*/ role){ // summary: // Sets the role on an element. // description: // Replace existing role attribute with new role. domAttr.set(elem, "role", role); }, removeWaiRole: function(/*Element*/ elem, /*String*/ role){ // summary: // Removes the specified role from an element. // Removes role attribute if no specific role provided (for backwards compat.) var roleValue = domAttr.get(elem, "role"); if(!roleValue){ return; } if(role){ var t = lang.trim((" " + roleValue + " ").replace(" " + role + " ", " ")); domAttr.set(elem, "role", t); }else{ elem.removeAttribute("role"); } }, hasWaiState: function(/*Element*/ elem, /*String*/ state){ // summary: // Determines if an element has a given state. // description: // Checks for an attribute called "aria-"+state. // returns: // true if elem has a value for the given state and // false if it does not. return elem.hasAttribute ? elem.hasAttribute("aria-"+state) : !!elem.getAttribute("aria-"+state); }, getWaiState: function(/*Element*/ elem, /*String*/ state){ // summary: // Gets the value of a state on an element. // description: // Checks for an attribute called "aria-"+state. // returns: // The value of the requested state on elem // or an empty string if elem has no value for state. return elem.getAttribute("aria-"+state) || ""; }, setWaiState: function(/*Element*/ elem, /*String*/ state, /*String*/ value){ // summary: // Sets a state on an element. // description: // Sets an attribute called "aria-"+state. elem.setAttribute("aria-"+state, value); }, removeWaiState: function(/*Element*/ elem, /*String*/ state){ // summary: // Removes a state from an element. // description: // Sets an attribute called "aria-"+state. elem.removeAttribute("aria-"+state); } }); return dijit; }); }, 'dojo/window':function(){ define(["./_base/kernel", "./_base/lang", "./_base/sniff", "./_base/window", "./dom", "./dom-geometry", "./dom-style"], function(dojo, lang, has, baseWindow, dom, geom, style) { // module: // dojo/window // summary: // TODOC lang.getObject("window", true, dojo); dojo.window.getBox = function(){ // summary: // Returns the dimensions and scroll position of the viewable area of a browser window var scrollRoot = (baseWindow.doc.compatMode == 'BackCompat') ? baseWindow.body() : baseWindow.doc.documentElement; // get scroll position var scroll = geom.docScroll(); // scrollRoot.scrollTop/Left should work var uiWindow = baseWindow.doc.parentWindow || baseWindow.doc.defaultView; // use UI window, not dojo.global window // dojo.global.innerWidth||dojo.global.innerHeight is for mobile return { l: scroll.x, t: scroll.y, w: uiWindow.innerWidth || scrollRoot.clientWidth, h: uiWindow.innerHeight || scrollRoot.clientHeight }; }; dojo.window.get = function(doc){ // summary: // Get window object associated with document doc // In some IE versions (at least 6.0), document.parentWindow does not return a // reference to the real window object (maybe a copy), so we must fix it as well // We use IE specific execScript to attach the real window reference to // document._parentWindow for later use if(has("ie") && window !== document.parentWindow){ /* In IE 6, only the variable "window" can be used to connect events (others may be only copies). */ doc.parentWindow.execScript("document._parentWindow = window;", "Javascript"); //to prevent memory leak, unset it after use //another possibility is to add an onUnload handler which seems overkill to me (liucougar) var win = doc._parentWindow; doc._parentWindow = null; return win; // Window } return doc.parentWindow || doc.defaultView; // Window }; dojo.window.scrollIntoView = function(/*DomNode*/ node, /*Object?*/ pos){ // summary: // Scroll the passed node into view, if it is not already. // don't rely on node.scrollIntoView working just because the function is there try{ // catch unexpected/unrecreatable errors (#7808) since we can recover using a semi-acceptable native method node = dom.byId(node); var doc = node.ownerDocument || baseWindow.doc, body = doc.body || baseWindow.body(), html = doc.documentElement || body.parentNode, isIE = has("ie"), isWK = has("webkit"); // if an untested browser, then use the native method if((!(has("mozilla") || isIE || isWK || has("opera")) || node == body || node == html) && (typeof node.scrollIntoView != "undefined")){ node.scrollIntoView(false); // short-circuit to native if possible return; } var backCompat = doc.compatMode == 'BackCompat', clientAreaRoot = (isIE >= 9 && node.ownerDocument.parentWindow.frameElement) ? ((html.clientHeight > 0 && html.clientWidth > 0 && (body.clientHeight == 0 || body.clientWidth == 0 || body.clientHeight > html.clientHeight || body.clientWidth > html.clientWidth)) ? html : body) : (backCompat ? body : html), scrollRoot = isWK ? body : clientAreaRoot, rootWidth = clientAreaRoot.clientWidth, rootHeight = clientAreaRoot.clientHeight, rtl = !geom.isBodyLtr(), nodePos = pos || geom.position(node), el = node.parentNode, isFixed = function(el){ return ((isIE <= 6 || (isIE && backCompat))? false : (style.get(el, 'position').toLowerCase() == "fixed")); }; if(isFixed(node)){ return; } // nothing to do while(el){ if(el == body){ el = scrollRoot; } var elPos = geom.position(el), fixedPos = isFixed(el); if(el == scrollRoot){ elPos.w = rootWidth; elPos.h = rootHeight; if(scrollRoot == html && isIE && rtl){ elPos.x += scrollRoot.offsetWidth-elPos.w; } // IE workaround where scrollbar causes negative x if(elPos.x < 0 || !isIE){ elPos.x = 0; } // IE can have values > 0 if(elPos.y < 0 || !isIE){ elPos.y = 0; } }else{ var pb = geom.getPadBorderExtents(el); elPos.w -= pb.w; elPos.h -= pb.h; elPos.x += pb.l; elPos.y += pb.t; var clientSize = el.clientWidth, scrollBarSize = elPos.w - clientSize; if(clientSize > 0 && scrollBarSize > 0){ elPos.w = clientSize; elPos.x += (rtl && (isIE || el.clientLeft > pb.l/*Chrome*/)) ? scrollBarSize : 0; } clientSize = el.clientHeight; scrollBarSize = elPos.h - clientSize; if(clientSize > 0 && scrollBarSize > 0){ elPos.h = clientSize; } } if(fixedPos){ // bounded by viewport, not parents if(elPos.y < 0){ elPos.h += elPos.y; elPos.y = 0; } if(elPos.x < 0){ elPos.w += elPos.x; elPos.x = 0; } if(elPos.y + elPos.h > rootHeight){ elPos.h = rootHeight - elPos.y; } if(elPos.x + elPos.w > rootWidth){ elPos.w = rootWidth - elPos.x; } } // calculate overflow in all 4 directions var l = nodePos.x - elPos.x, // beyond left: < 0 t = nodePos.y - Math.max(elPos.y, 0), // beyond top: < 0 r = l + nodePos.w - elPos.w, // beyond right: > 0 bot = t + nodePos.h - elPos.h; // beyond bottom: > 0 if(r * l > 0){ var s = Math[l < 0? "max" : "min"](l, r); if(rtl && ((isIE == 8 && !backCompat) || isIE >= 9)){ s = -s; } nodePos.x += el.scrollLeft; el.scrollLeft += s; nodePos.x -= el.scrollLeft; } if(bot * t > 0){ nodePos.y += el.scrollTop; el.scrollTop += Math[t < 0? "max" : "min"](t, bot); nodePos.y -= el.scrollTop; } el = (el != scrollRoot) && !fixedPos && el.parentNode; } }catch(error){ console.error('scrollIntoView: ' + error); node.scrollIntoView(false); } }; return dojo.window; }); }, 'dijit/popup':function(){ define("dijit/popup", [ "dojo/_base/array", // array.forEach array.some "dojo/aspect", "dojo/_base/connect", // connect._keypress "dojo/_base/declare", // declare "dojo/dom", // dom.isDescendant "dojo/dom-attr", // domAttr.set "dojo/dom-construct", // domConstruct.create domConstruct.destroy "dojo/dom-geometry", // domGeometry.isBodyLtr "dojo/dom-style", // domStyle.set "dojo/_base/event", // event.stop "dojo/keys", "dojo/_base/lang", // lang.hitch "dojo/on", "dojo/_base/sniff", // has("ie") has("mozilla") "dojo/_base/window", // win.body "./place", "./BackgroundIframe", "." // dijit (defining dijit.popup to match API doc) ], function(array, aspect, connect, declare, dom, domAttr, domConstruct, domGeometry, domStyle, event, keys, lang, on, has, win, place, BackgroundIframe, dijit){ // module: // dijit/popup // summary: // Used to show drop downs (ex: the select list of a ComboBox) // or popups (ex: right-click context menus) /*===== dijit.popup.__OpenArgs = function(){ // popup: Widget // widget to display // parent: Widget // the button etc. that is displaying this popup // around: DomNode // DOM node (typically a button); place popup relative to this node. (Specify this *or* "x" and "y" parameters.) // x: Integer // Absolute horizontal position (in pixels) to place node at. (Specify this *or* "around" parameter.) // y: Integer // Absolute vertical position (in pixels) to place node at. (Specify this *or* "around" parameter.) // orient: Object|String // When the around parameter is specified, orient should be a list of positions to try, ex: // | [ "below", "above" ] // For backwards compatibility it can also be an (ordered) hash of tuples of the form // (around-node-corner, popup-node-corner), ex: // | { "BL": "TL", "TL": "BL" } // where BL means "bottom left" and "TL" means "top left", etc. // // dijit.popup.open() tries to position the popup according to each specified position, in order, // until the popup appears fully within the viewport. // // The default value is ["below", "above"] // // When an (x,y) position is specified rather than an around node, orient is either // "R" or "L". R (for right) means that it tries to put the popup to the right of the mouse, // specifically positioning the popup's top-right corner at the mouse position, and if that doesn't // fit in the viewport, then it tries, in order, the bottom-right corner, the top left corner, // and the top-right corner. // onCancel: Function // callback when user has canceled the popup by // 1. hitting ESC or // 2. by using the popup widget's proprietary cancel mechanism (like a cancel button in a dialog); // i.e. whenever popupWidget.onCancel() is called, args.onCancel is called // onClose: Function // callback whenever this popup is closed // onExecute: Function // callback when user "executed" on the popup/sub-popup by selecting a menu choice, etc. (top menu only) // padding: dijit.__Position // adding a buffer around the opening position. This is only useful when around is not set. this.popup = popup; this.parent = parent; this.around = around; this.x = x; this.y = y; this.orient = orient; this.onCancel = onCancel; this.onClose = onClose; this.onExecute = onExecute; this.padding = padding; } =====*/ /*===== dijit.popup = { // summary: // Used to show drop downs (ex: the select list of a ComboBox) // or popups (ex: right-click context menus). // // Access via require(["dijit/popup"], function(popup){ ... }). moveOffScreen: function(widget){ // summary: // Moves the popup widget off-screen. // Do not use this method to hide popups when not in use, because // that will create an accessibility issue: the offscreen popup is // still in the tabbing order. // widget: dijit._WidgetBase // The widget }, hide: function(widget){ // summary: // Hide this popup widget (until it is ready to be shown). // Initialization for widgets that will be used as popups // // Also puts widget inside a wrapper DIV (if not already in one) // // If popup widget needs to layout it should // do so when it is made visible, and popup._onShow() is called. // widget: dijit._WidgetBase // The widget }, open: function(args){ // summary: // Popup the widget at the specified position // example: // opening at the mouse position // | popup.open({popup: menuWidget, x: evt.pageX, y: evt.pageY}); // example: // opening the widget as a dropdown // | popup.open({parent: this, popup: menuWidget, around: this.domNode, onClose: function(){...}}); // // Note that whatever widget called dijit.popup.open() should also listen to its own _onBlur callback // (fired from _base/focus.js) to know that focus has moved somewhere else and thus the popup should be closed. // args: dijit.popup.__OpenArgs // Parameters return {}; // Object specifying which position was chosen }, close: function(popup){ // summary: // Close specified popup and any popups that it parented. // If no popup is specified, closes all popups. // widget: dijit._WidgetBase? // The widget, optional } }; =====*/ var PopupManager = declare(null, { // _stack: dijit._Widget[] // Stack of currently popped up widgets. // (someone opened _stack[0], and then it opened _stack[1], etc.) _stack: [], // _beginZIndex: Number // Z-index of the first popup. (If first popup opens other // popups they get a higher z-index.) _beginZIndex: 1000, _idGen: 1, _createWrapper: function(/*Widget*/ widget){ // summary: // Initialization for widgets that will be used as popups. // Puts widget inside a wrapper DIV (if not already in one), // and returns pointer to that wrapper DIV. var wrapper = widget._popupWrapper, node = widget.domNode; if(!wrapper){ // Create wrapper <div> for when this widget [in the future] will be used as a popup. // This is done early because of IE bugs where creating/moving DOM nodes causes focus // to go wonky, see tests/robot/Toolbar.html to reproduce wrapper = domConstruct.create("div",{ "class":"dijitPopup", style:{ display: "none"}, role: "presentation" }, win.body()); wrapper.appendChild(node); var s = node.style; s.display = ""; s.visibility = ""; s.position = ""; s.top = "0px"; widget._popupWrapper = wrapper; aspect.after(widget, "destroy", function(){ domConstruct.destroy(wrapper); delete widget._popupWrapper; }); } return wrapper; }, moveOffScreen: function(/*Widget*/ widget){ // summary: // Moves the popup widget off-screen. // Do not use this method to hide popups when not in use, because // that will create an accessibility issue: the offscreen popup is // still in the tabbing order. // Create wrapper if not already there var wrapper = this._createWrapper(widget); domStyle.set(wrapper, { visibility: "hidden", top: "-9999px", // prevent transient scrollbar causing misalign (#5776), and initial flash in upper left (#10111) display: "" }); }, hide: function(/*Widget*/ widget){ // summary: // Hide this popup widget (until it is ready to be shown). // Initialization for widgets that will be used as popups // // Also puts widget inside a wrapper DIV (if not already in one) // // If popup widget needs to layout it should // do so when it is made visible, and popup._onShow() is called. // Create wrapper if not already there var wrapper = this._createWrapper(widget); domStyle.set(wrapper, "display", "none"); }, getTopPopup: function(){ // summary: // Compute the closest ancestor popup that's *not* a child of another popup. // Ex: For a TooltipDialog with a button that spawns a tree of menus, find the popup of the button. var stack = this._stack; for(var pi=stack.length-1; pi > 0 && stack[pi].parent === stack[pi-1].widget; pi--){ /* do nothing, just trying to get right value for pi */ } return stack[pi]; }, open: function(/*dijit.popup.__OpenArgs*/ args){ // summary: // Popup the widget at the specified position // // example: // opening at the mouse position // | popup.open({popup: menuWidget, x: evt.pageX, y: evt.pageY}); // // example: // opening the widget as a dropdown // | popup.open({parent: this, popup: menuWidget, around: this.domNode, onClose: function(){...}}); // // Note that whatever widget called dijit.popup.open() should also listen to its own _onBlur callback // (fired from _base/focus.js) to know that focus has moved somewhere else and thus the popup should be closed. var stack = this._stack, widget = args.popup, orient = args.orient || ["below", "below-alt", "above", "above-alt"], ltr = args.parent ? args.parent.isLeftToRight() : domGeometry.isBodyLtr(), around = args.around, id = (args.around && args.around.id) ? (args.around.id+"_dropdown") : ("popup_"+this._idGen++); // If we are opening a new popup that isn't a child of a currently opened popup, then // close currently opened popup(s). This should happen automatically when the old popups // gets the _onBlur() event, except that the _onBlur() event isn't reliable on IE, see [22198]. while(stack.length && (!args.parent || !dom.isDescendant(args.parent.domNode, stack[stack.length-1].widget.domNode))){ this.close(stack[stack.length-1].widget); } // Get pointer to popup wrapper, and create wrapper if it doesn't exist var wrapper = this._createWrapper(widget); domAttr.set(wrapper, { id: id, style: { zIndex: this._beginZIndex + stack.length }, "class": "dijitPopup " + (widget.baseClass || widget["class"] || "").split(" ")[0] +"Popup", dijitPopupParent: args.parent ? args.parent.id : "" }); if(has("ie") || has("mozilla")){ if(!widget.bgIframe){ // setting widget.bgIframe triggers cleanup in _Widget.destroy() widget.bgIframe = new BackgroundIframe(wrapper); } } // position the wrapper node and make it visible var best = around ? place.around(wrapper, around, orient, ltr, widget.orient ? lang.hitch(widget, "orient") : null) : place.at(wrapper, args, orient == 'R' ? ['TR','BR','TL','BL'] : ['TL','BL','TR','BR'], args.padding); wrapper.style.display = ""; wrapper.style.visibility = "visible"; widget.domNode.style.visibility = "visible"; // counteract effects from _HasDropDown var handlers = []; // provide default escape and tab key handling // (this will work for any widget, not just menu) handlers.push(on(wrapper, connect._keypress, lang.hitch(this, function(evt){ if(evt.charOrCode == keys.ESCAPE && args.onCancel){ event.stop(evt); args.onCancel(); }else if(evt.charOrCode === keys.TAB){ event.stop(evt); var topPopup = this.getTopPopup(); if(topPopup && topPopup.onCancel){ topPopup.onCancel(); } } }))); // watch for cancel/execute events on the popup and notify the caller // (for a menu, "execute" means clicking an item) if(widget.onCancel && args.onCancel){ handlers.push(widget.on("cancel", args.onCancel)); } handlers.push(widget.on(widget.onExecute ? "execute" : "change", lang.hitch(this, function(){ var topPopup = this.getTopPopup(); if(topPopup && topPopup.onExecute){ topPopup.onExecute(); } }))); stack.push({ widget: widget, parent: args.parent, onExecute: args.onExecute, onCancel: args.onCancel, onClose: args.onClose, handlers: handlers }); if(widget.onOpen){ // TODO: in 2.0 standardize onShow() (used by StackContainer) and onOpen() (used here) widget.onOpen(best); } return best; }, close: function(/*Widget?*/ popup){ // summary: // Close specified popup and any popups that it parented. // If no popup is specified, closes all popups. var stack = this._stack; // Basically work backwards from the top of the stack closing popups // until we hit the specified popup, but IIRC there was some issue where closing // a popup would cause others to close too. Thus if we are trying to close B in [A,B,C] // closing C might close B indirectly and then the while() condition will run where stack==[A]... // so the while condition is constructed defensively. while((popup && array.some(stack, function(elem){return elem.widget == popup;})) || (!popup && stack.length)){ var top = stack.pop(), widget = top.widget, onClose = top.onClose; if(widget.onClose){ // TODO: in 2.0 standardize onHide() (used by StackContainer) and onClose() (used here) widget.onClose(); } var h; while(h = top.handlers.pop()){ h.remove(); } // Hide the widget and it's wrapper unless it has already been destroyed in above onClose() etc. if(widget && widget.domNode){ this.hide(widget); } if(onClose){ onClose(); } } } }); return (dijit.popup = new PopupManager()); }); }, 'dijit/_base/window':function(){ define("dijit/_base/window", [ "dojo/window", // windowUtils.get ".." // export symbol to dijit ], function(windowUtils, dijit){ // module: // dijit/_base/window // summary: // Back compatibility module, new code should use windowUtils directly instead of using this module. dijit.getDocumentWindow = function(doc){ return windowUtils.get(doc); }; }); }, 'dijit/_WidgetBase':function(){ define("dijit/_WidgetBase", [ "require", // require.toUrl "dojo/_base/array", // array.forEach array.map "dojo/aspect", "dojo/_base/config", // config.blankGif "dojo/_base/connect", // connect.connect "dojo/_base/declare", // declare "dojo/dom", // dom.byId "dojo/dom-attr", // domAttr.set domAttr.remove "dojo/dom-class", // domClass.add domClass.replace "dojo/dom-construct", // domConstruct.create domConstruct.destroy domConstruct.place "dojo/dom-geometry", // isBodyLtr "dojo/dom-style", // domStyle.set, domStyle.get "dojo/_base/kernel", "dojo/_base/lang", // mixin(), isArray(), etc. "dojo/on", "dojo/ready", "dojo/Stateful", // Stateful "dojo/topic", "dojo/_base/window", // win.doc.createTextNode "./registry" // registry.getUniqueId(), registry.findWidgets() ], function(require, array, aspect, config, connect, declare, dom, domAttr, domClass, domConstruct, domGeometry, domStyle, kernel, lang, on, ready, Stateful, topic, win, registry){ /*===== var Stateful = dojo.Stateful; =====*/ // module: // dijit/_WidgetBase // summary: // Future base class for all Dijit widgets. // For back-compat, remove in 2.0. if(!kernel.isAsync){ ready(0, function(){ var requires = ["dijit/_base/manager"]; require(requires); // use indirection so modules not rolled into a build }); } // Nested hash listing attributes for each tag, all strings in lowercase. // ex: {"div": {"style": true, "tabindex" true}, "form": { ... var tagAttrs = {}; function getAttrs(obj){ var ret = {}; for(var attr in obj){ ret[attr.toLowerCase()] = true; } return ret; } function nonEmptyAttrToDom(attr){ // summary: // Returns a setter function that copies the attribute to this.domNode, // or removes the attribute from this.domNode, depending on whether the // value is defined or not. return function(val){ domAttr[val ? "set" : "remove"](this.domNode, attr, val); this._set(attr, val); }; } return declare("dijit._WidgetBase", Stateful, { // summary: // Future base class for all Dijit widgets. // description: // Future base class for all Dijit widgets. // _Widget extends this class adding support for various features needed by desktop. // // Provides stubs for widget lifecycle methods for subclasses to extend, like postMixInProperties(), buildRendering(), // postCreate(), startup(), and destroy(), and also public API methods like set(), get(), and watch(). // // Widgets can provide custom setters/getters for widget attributes, which are called automatically by set(name, value). // For an attribute XXX, define methods _setXXXAttr() and/or _getXXXAttr(). // // _setXXXAttr can also be a string/hash/array mapping from a widget attribute XXX to the widget's DOMNodes: // // - DOM node attribute // | _setFocusAttr: {node: "focusNode", type: "attribute"} // | _setFocusAttr: "focusNode" (shorthand) // | _setFocusAttr: "" (shorthand, maps to this.domNode) // Maps this.focus to this.focusNode.focus, or (last example) this.domNode.focus // // - DOM node innerHTML // | _setTitleAttr: { node: "titleNode", type: "innerHTML" } // Maps this.title to this.titleNode.innerHTML // // - DOM node innerText // | _setTitleAttr: { node: "titleNode", type: "innerText" } // Maps this.title to this.titleNode.innerText // // - DOM node CSS class // | _setMyClassAttr: { node: "domNode", type: "class" } // Maps this.myClass to this.domNode.className // // If the value of _setXXXAttr is an array, then each element in the array matches one of the // formats of the above list. // // If the custom setter is null, no action is performed other than saving the new value // in the widget (in this). // // If no custom setter is defined for an attribute, then it will be copied // to this.focusNode (if the widget defines a focusNode), or this.domNode otherwise. // That's only done though for attributes that match DOMNode attributes (title, // alt, aria-labelledby, etc.) // id: [const] String // A unique, opaque ID string that can be assigned by users or by the // system. If the developer passes an ID which is known not to be // unique, the specified ID is ignored and the system-generated ID is // used instead. id: "", _setIdAttr: "domNode", // to copy to this.domNode even for auto-generated id's // lang: [const] String // Rarely used. Overrides the default Dojo locale used to render this widget, // as defined by the [HTML LANG](http://www.w3.org/TR/html401/struct/dirlang.html#adef-lang) attribute. // Value must be among the list of locales specified during by the Dojo bootstrap, // formatted according to [RFC 3066](http://www.ietf.org/rfc/rfc3066.txt) (like en-us). lang: "", // set on domNode even when there's a focus node. but don't set lang="", since that's invalid. _setLangAttr: nonEmptyAttrToDom("lang"), // dir: [const] String // Bi-directional support, as defined by the [HTML DIR](http://www.w3.org/TR/html401/struct/dirlang.html#adef-dir) // attribute. Either left-to-right "ltr" or right-to-left "rtl". If undefined, widgets renders in page's // default direction. dir: "", // set on domNode even when there's a focus node. but don't set dir="", since that's invalid. _setDirAttr: nonEmptyAttrToDom("dir"), // to set on domNode even when there's a focus node // textDir: String // Bi-directional support, the main variable which is responsible for the direction of the text. // The text direction can be different than the GUI direction by using this parameter in creation // of a widget. // Allowed values: // 1. "ltr" // 2. "rtl" // 3. "auto" - contextual the direction of a text defined by first strong letter. // By default is as the page direction. textDir: "", // class: String // HTML class attribute "class": "", _setClassAttr: { node: "domNode", type: "class" }, // style: String||Object // HTML style attributes as cssText string or name/value hash style: "", // title: String // HTML title attribute. // // For form widgets this specifies a tooltip to display when hovering over // the widget (just like the native HTML title attribute). // // For TitlePane or for when this widget is a child of a TabContainer, AccordionContainer, // etc., it's used to specify the tab label, accordion pane title, etc. title: "", // tooltip: String // When this widget's title attribute is used to for a tab label, accordion pane title, etc., // this specifies the tooltip to appear when the mouse is hovered over that text. tooltip: "", // baseClass: [protected] String // Root CSS class of the widget (ex: dijitTextBox), used to construct CSS classes to indicate // widget state. baseClass: "", // srcNodeRef: [readonly] DomNode // pointer to original DOM node srcNodeRef: null, // domNode: [readonly] DomNode // This is our visible representation of the widget! Other DOM // Nodes may by assigned to other properties, usually through the // template system's data-dojo-attach-point syntax, but the domNode // property is the canonical "top level" node in widget UI. domNode: null, // containerNode: [readonly] DomNode // Designates where children of the source DOM node will be placed. // "Children" in this case refers to both DOM nodes and widgets. // For example, for myWidget: // // | <div data-dojo-type=myWidget> // | <b> here's a plain DOM node // | <span data-dojo-type=subWidget>and a widget</span> // | <i> and another plain DOM node </i> // | </div> // // containerNode would point to: // // | <b> here's a plain DOM node // | <span data-dojo-type=subWidget>and a widget</span> // | <i> and another plain DOM node </i> // // In templated widgets, "containerNode" is set via a // data-dojo-attach-point assignment. // // containerNode must be defined for any widget that accepts innerHTML // (like ContentPane or BorderContainer or even Button), and conversely // is null for widgets that don't, like TextBox. containerNode: null, /*===== // _started: Boolean // startup() has completed. _started: false, =====*/ // attributeMap: [protected] Object // Deprecated. Instead of attributeMap, widget should have a _setXXXAttr attribute // for each XXX attribute to be mapped to the DOM. // // attributeMap sets up a "binding" between attributes (aka properties) // of the widget and the widget's DOM. // Changes to widget attributes listed in attributeMap will be // reflected into the DOM. // // For example, calling set('title', 'hello') // on a TitlePane will automatically cause the TitlePane's DOM to update // with the new title. // // attributeMap is a hash where the key is an attribute of the widget, // and the value reflects a binding to a: // // - DOM node attribute // | focus: {node: "focusNode", type: "attribute"} // Maps this.focus to this.focusNode.focus // // - DOM node innerHTML // | title: { node: "titleNode", type: "innerHTML" } // Maps this.title to this.titleNode.innerHTML // // - DOM node innerText // | title: { node: "titleNode", type: "innerText" } // Maps this.title to this.titleNode.innerText // // - DOM node CSS class // | myClass: { node: "domNode", type: "class" } // Maps this.myClass to this.domNode.className // // If the value is an array, then each element in the array matches one of the // formats of the above list. // // There are also some shorthands for backwards compatibility: // - string --> { node: string, type: "attribute" }, for example: // | "focusNode" ---> { node: "focusNode", type: "attribute" } // - "" --> { node: "domNode", type: "attribute" } attributeMap: {}, // _blankGif: [protected] String // Path to a blank 1x1 image. // Used by <img> nodes in templates that really get their image via CSS background-image. _blankGif: config.blankGif || require.toUrl("dojo/resources/blank.gif"), //////////// INITIALIZATION METHODS /////////////////////////////////////// postscript: function(/*Object?*/params, /*DomNode|String*/srcNodeRef){ // summary: // Kicks off widget instantiation. See create() for details. // tags: // private this.create(params, srcNodeRef); }, create: function(/*Object?*/params, /*DomNode|String?*/srcNodeRef){ // summary: // Kick off the life-cycle of a widget // params: // Hash of initialization parameters for widget, including // scalar values (like title, duration etc.) and functions, // typically callbacks like onClick. // srcNodeRef: // If a srcNodeRef (DOM node) is specified: // - use srcNodeRef.innerHTML as my contents // - if this is a behavioral widget then apply behavior // to that srcNodeRef // - otherwise, replace srcNodeRef with my generated DOM // tree // description: // Create calls a number of widget methods (postMixInProperties, buildRendering, postCreate, // etc.), some of which of you'll want to override. See http://dojotoolkit.org/reference-guide/dijit/_WidgetBase.html // for a discussion of the widget creation lifecycle. // // Of course, adventurous developers could override create entirely, but this should // only be done as a last resort. // tags: // private // store pointer to original DOM tree this.srcNodeRef = dom.byId(srcNodeRef); // For garbage collection. An array of listener handles returned by this.connect() / this.subscribe() this._connects = []; // For widgets internal to this widget, invisible to calling code this._supportingWidgets = []; // this is here for back-compat, remove in 2.0 (but check NodeList-instantiate.html test) if(this.srcNodeRef && (typeof this.srcNodeRef.id == "string")){ this.id = this.srcNodeRef.id; } // mix in our passed parameters if(params){ this.params = params; lang.mixin(this, params); } this.postMixInProperties(); // generate an id for the widget if one wasn't specified // (be sure to do this before buildRendering() because that function might // expect the id to be there.) if(!this.id){ this.id = registry.getUniqueId(this.declaredClass.replace(/\./g,"_")); } registry.add(this); this.buildRendering(); if(this.domNode){ // Copy attributes listed in attributeMap into the [newly created] DOM for the widget. // Also calls custom setters for all attributes with custom setters. this._applyAttributes(); // If srcNodeRef was specified, then swap out original srcNode for this widget's DOM tree. // For 2.0, move this after postCreate(). postCreate() shouldn't depend on the // widget being attached to the DOM since it isn't when a widget is created programmatically like // new MyWidget({}). See #11635. var source = this.srcNodeRef; if(source && source.parentNode && this.domNode !== source){ source.parentNode.replaceChild(this.domNode, source); } } if(this.domNode){ // Note: for 2.0 may want to rename widgetId to dojo._scopeName + "_widgetId", // assuming that dojo._scopeName even exists in 2.0 this.domNode.setAttribute("widgetId", this.id); } this.postCreate(); // If srcNodeRef has been processed and removed from the DOM (e.g. TemplatedWidget) then delete it to allow GC. if(this.srcNodeRef && !this.srcNodeRef.parentNode){ delete this.srcNodeRef; } this._created = true; }, _applyAttributes: function(){ // summary: // Step during widget creation to copy widget attributes to the // DOM according to attributeMap and _setXXXAttr objects, and also to call // custom _setXXXAttr() methods. // // Skips over blank/false attribute values, unless they were explicitly specified // as parameters to the widget, since those are the default anyway, // and setting tabIndex="" is different than not setting tabIndex at all. // // For backwards-compatibility reasons attributeMap overrides _setXXXAttr when // _setXXXAttr is a hash/string/array, but _setXXXAttr as a functions override attributeMap. // tags: // private // Get list of attributes where this.set(name, value) will do something beyond // setting this[name] = value. Specifically, attributes that have: // - associated _setXXXAttr() method/hash/string/array // - entries in attributeMap. var ctor = this.constructor, list = ctor._setterAttrs; if(!list){ list = (ctor._setterAttrs = []); for(var attr in this.attributeMap){ list.push(attr); } var proto = ctor.prototype; for(var fxName in proto){ if(fxName in this.attributeMap){ continue; } var setterName = "_set" + fxName.replace(/^[a-z]|-[a-zA-Z]/g, function(c){ return c.charAt(c.length-1).toUpperCase(); }) + "Attr"; if(setterName in proto){ list.push(fxName); } } } // Call this.set() for each attribute that was either specified as parameter to constructor, // or was found above and has a default non-null value. For correlated attributes like value and displayedValue, the one // specified as a parameter should take precedence, so apply attributes in this.params last. // Particularly important for new DateTextBox({displayedValue: ...}) since DateTextBox's default value is // NaN and thus is not ignored like a default value of "". array.forEach(list, function(attr){ if(this.params && attr in this.params){ // skip this one, do it below }else if(this[attr]){ this.set(attr, this[attr]); } }, this); for(var param in this.params){ this.set(param, this[param]); } }, postMixInProperties: function(){ // summary: // Called after the parameters to the widget have been read-in, // but before the widget template is instantiated. Especially // useful to set properties that are referenced in the widget // template. // tags: // protected }, buildRendering: function(){ // summary: // Construct the UI for this widget, setting this.domNode. // Most widgets will mixin `dijit._TemplatedMixin`, which implements this method. // tags: // protected if(!this.domNode){ // Create root node if it wasn't created by _Templated this.domNode = this.srcNodeRef || domConstruct.create('div'); } // baseClass is a single class name or occasionally a space-separated list of names. // Add those classes to the DOMNode. If RTL mode then also add with Rtl suffix. // TODO: make baseClass custom setter if(this.baseClass){ var classes = this.baseClass.split(" "); if(!this.isLeftToRight()){ classes = classes.concat( array.map(classes, function(name){ return name+"Rtl"; })); } domClass.add(this.domNode, classes); } }, postCreate: function(){ // summary: // Processing after the DOM fragment is created // description: // Called after the DOM fragment has been created, but not necessarily // added to the document. Do not include any operations which rely on // node dimensions or placement. // tags: // protected }, startup: function(){ // summary: // Processing after the DOM fragment is added to the document // description: // Called after a widget and its children have been created and added to the page, // and all related widgets have finished their create() cycle, up through postCreate(). // This is useful for composite widgets that need to control or layout sub-widgets. // Many layout widgets can use this as a wiring phase. if(this._started){ return; } this._started = true; array.forEach(this.getChildren(), function(obj){ if(!obj._started && !obj._destroyed && lang.isFunction(obj.startup)){ obj.startup(); obj._started = true; } }); }, //////////// DESTROY FUNCTIONS //////////////////////////////// destroyRecursive: function(/*Boolean?*/ preserveDom){ // summary: // Destroy this widget and its descendants // description: // This is the generic "destructor" function that all widget users // should call to cleanly discard with a widget. Once a widget is // destroyed, it is removed from the manager object. // preserveDom: // If true, this method will leave the original DOM structure // alone of descendant Widgets. Note: This will NOT work with // dijit._Templated widgets. this._beingDestroyed = true; this.destroyDescendants(preserveDom); this.destroy(preserveDom); }, destroy: function(/*Boolean*/ preserveDom){ // summary: // Destroy this widget, but not its descendants. // This method will, however, destroy internal widgets such as those used within a template. // preserveDom: Boolean // If true, this method will leave the original DOM structure alone. // Note: This will not yet work with _Templated widgets this._beingDestroyed = true; this.uninitialize(); // remove this.connect() and this.subscribe() listeners var c; while(c = this._connects.pop()){ c.remove(); } // destroy widgets created as part of template, etc. var w; while(w = this._supportingWidgets.pop()){ if(w.destroyRecursive){ w.destroyRecursive(); }else if(w.destroy){ w.destroy(); } } this.destroyRendering(preserveDom); registry.remove(this.id); this._destroyed = true; }, destroyRendering: function(/*Boolean?*/ preserveDom){ // summary: // Destroys the DOM nodes associated with this widget // preserveDom: // If true, this method will leave the original DOM structure alone // during tear-down. Note: this will not work with _Templated // widgets yet. // tags: // protected if(this.bgIframe){ this.bgIframe.destroy(preserveDom); delete this.bgIframe; } if(this.domNode){ if(preserveDom){ domAttr.remove(this.domNode, "widgetId"); }else{ domConstruct.destroy(this.domNode); } delete this.domNode; } if(this.srcNodeRef){ if(!preserveDom){ domConstruct.destroy(this.srcNodeRef); } delete this.srcNodeRef; } }, destroyDescendants: function(/*Boolean?*/ preserveDom){ // summary: // Recursively destroy the children of this widget and their // descendants. // preserveDom: // If true, the preserveDom attribute is passed to all descendant // widget's .destroy() method. Not for use with _Templated // widgets. // get all direct descendants and destroy them recursively array.forEach(this.getChildren(), function(widget){ if(widget.destroyRecursive){ widget.destroyRecursive(preserveDom); } }); }, uninitialize: function(){ // summary: // Stub function. Override to implement custom widget tear-down // behavior. // tags: // protected return false; }, ////////////////// GET/SET, CUSTOM SETTERS, ETC. /////////////////// _setStyleAttr: function(/*String||Object*/ value){ // summary: // Sets the style attribute of the widget according to value, // which is either a hash like {height: "5px", width: "3px"} // or a plain string // description: // Determines which node to set the style on based on style setting // in attributeMap. // tags: // protected var mapNode = this.domNode; // Note: technically we should revert any style setting made in a previous call // to his method, but that's difficult to keep track of. if(lang.isObject(value)){ domStyle.set(mapNode, value); }else{ if(mapNode.style.cssText){ mapNode.style.cssText += "; " + value; }else{ mapNode.style.cssText = value; } } this._set("style", value); }, _attrToDom: function(/*String*/ attr, /*String*/ value, /*Object?*/ commands){ // summary: // Reflect a widget attribute (title, tabIndex, duration etc.) to // the widget DOM, as specified by commands parameter. // If commands isn't specified then it's looked up from attributeMap. // Note some attributes like "type" // cannot be processed this way as they are not mutable. // // tags: // private commands = arguments.length >= 3 ? commands : this.attributeMap[attr]; array.forEach(lang.isArray(commands) ? commands : [commands], function(command){ // Get target node and what we are doing to that node var mapNode = this[command.node || command || "domNode"]; // DOM node var type = command.type || "attribute"; // class, innerHTML, innerText, or attribute switch(type){ case "attribute": if(lang.isFunction(value)){ // functions execute in the context of the widget value = lang.hitch(this, value); } // Get the name of the DOM node attribute; usually it's the same // as the name of the attribute in the widget (attr), but can be overridden. // Also maps handler names to lowercase, like onSubmit --> onsubmit var attrName = command.attribute ? command.attribute : (/^on[A-Z][a-zA-Z]*$/.test(attr) ? attr.toLowerCase() : attr); domAttr.set(mapNode, attrName, value); break; case "innerText": mapNode.innerHTML = ""; mapNode.appendChild(win.doc.createTextNode(value)); break; case "innerHTML": mapNode.innerHTML = value; break; case "class": domClass.replace(mapNode, value, this[attr]); break; } }, this); }, get: function(name){ // summary: // Get a property from a widget. // name: // The property to get. // description: // Get a named property from a widget. The property may // potentially be retrieved via a getter method. If no getter is defined, this // just retrieves the object's property. // // For example, if the widget has properties `foo` and `bar` // and a method named `_getFooAttr()`, calling: // `myWidget.get("foo")` would be equivalent to calling // `widget._getFooAttr()` and `myWidget.get("bar")` // would be equivalent to the expression // `widget.bar2` var names = this._getAttrNames(name); return this[names.g] ? this[names.g]() : this[name]; }, set: function(name, value){ // summary: // Set a property on a widget // name: // The property to set. // value: // The value to set in the property. // description: // Sets named properties on a widget which may potentially be handled by a // setter in the widget. // // For example, if the widget has properties `foo` and `bar` // and a method named `_setFooAttr()`, calling // `myWidget.set("foo", "Howdy!")` would be equivalent to calling // `widget._setFooAttr("Howdy!")` and `myWidget.set("bar", 3)` // would be equivalent to the statement `widget.bar = 3;` // // set() may also be called with a hash of name/value pairs, ex: // // | myWidget.set({ // | foo: "Howdy", // | bar: 3 // | }); // // This is equivalent to calling `set(foo, "Howdy")` and `set(bar, 3)` if(typeof name === "object"){ for(var x in name){ this.set(x, name[x]); } return this; } var names = this._getAttrNames(name), setter = this[names.s]; if(lang.isFunction(setter)){ // use the explicit setter var result = setter.apply(this, Array.prototype.slice.call(arguments, 1)); }else{ // Mapping from widget attribute to DOMNode attribute/value/etc. // Map according to: // 1. attributeMap setting, if one exists (TODO: attributeMap deprecated, remove in 2.0) // 2. _setFooAttr: {...} type attribute in the widget (if one exists) // 3. apply to focusNode or domNode if standard attribute name, excluding funcs like onClick. // Checks if an attribute is a "standard attribute" by whether the DOMNode JS object has a similar // attribute name (ex: accept-charset attribute matches jsObject.acceptCharset). // Note also that Tree.focusNode() is a function not a DOMNode, so test for that. var defaultNode = this.focusNode && !lang.isFunction(this.focusNode) ? "focusNode" : "domNode", tag = this[defaultNode].tagName, attrsForTag = tagAttrs[tag] || (tagAttrs[tag] = getAttrs(this[defaultNode])), map = name in this.attributeMap ? this.attributeMap[name] : names.s in this ? this[names.s] : ((names.l in attrsForTag && typeof value != "function") || /^aria-|^data-|^role$/.test(name)) ? defaultNode : null; if(map != null){ this._attrToDom(name, value, map); } this._set(name, value); } return result || this; }, _attrPairNames: {}, // shared between all widgets _getAttrNames: function(name){ // summary: // Helper function for get() and set(). // Caches attribute name values so we don't do the string ops every time. // tags: // private var apn = this._attrPairNames; if(apn[name]){ return apn[name]; } var uc = name.replace(/^[a-z]|-[a-zA-Z]/g, function(c){ return c.charAt(c.length-1).toUpperCase(); }); return (apn[name] = { n: name+"Node", s: "_set"+uc+"Attr", // converts dashes to camel case, ex: accept-charset --> _setAcceptCharsetAttr g: "_get"+uc+"Attr", l: uc.toLowerCase() // lowercase name w/out dashes, ex: acceptcharset }); }, _set: function(/*String*/ name, /*anything*/ value){ // summary: // Helper function to set new value for specified attribute, and call handlers // registered with watch() if the value has changed. var oldValue = this[name]; this[name] = value; if(this._watchCallbacks && this._created && value !== oldValue){ this._watchCallbacks(name, oldValue, value); } }, on: function(/*String*/ type, /*Function*/ func){ // summary: // Call specified function when event occurs, ex: myWidget.on("click", function(){ ... }). // description: // Call specified function when event `type` occurs, ex: `myWidget.on("click", function(){ ... })`. // Note that the function is not run in any particular scope, so if (for example) you want it to run in the // widget's scope you must do `myWidget.on("click", lang.hitch(myWidget, func))`. return aspect.after(this, this._onMap(type), func, true); }, _onMap: function(/*String*/ type){ // summary: // Maps on() type parameter (ex: "mousemove") to method name (ex: "onMouseMove") var ctor = this.constructor, map = ctor._onMap; if(!map){ map = (ctor._onMap = {}); for(var attr in ctor.prototype){ if(/^on/.test(attr)){ map[attr.replace(/^on/, "").toLowerCase()] = attr; } } } return map[type.toLowerCase()]; // String }, toString: function(){ // summary: // Returns a string that represents the widget // description: // When a widget is cast to a string, this method will be used to generate the // output. Currently, it does not implement any sort of reversible // serialization. return '[Widget ' + this.declaredClass + ', ' + (this.id || 'NO ID') + ']'; // String }, getChildren: function(){ // summary: // Returns all the widgets contained by this, i.e., all widgets underneath this.containerNode. // Does not return nested widgets, nor widgets that are part of this widget's template. return this.containerNode ? registry.findWidgets(this.containerNode) : []; // dijit._Widget[] }, getParent: function(){ // summary: // Returns the parent widget of this widget return registry.getEnclosingWidget(this.domNode.parentNode); }, connect: function( /*Object|null*/ obj, /*String|Function*/ event, /*String|Function*/ method){ // summary: // Connects specified obj/event to specified method of this object // and registers for disconnect() on widget destroy. // description: // Provide widget-specific analog to dojo.connect, except with the // implicit use of this widget as the target object. // Events connected with `this.connect` are disconnected upon // destruction. // returns: // A handle that can be passed to `disconnect` in order to disconnect before // the widget is destroyed. // example: // | var btn = new dijit.form.Button(); // | // when foo.bar() is called, call the listener we're going to // | // provide in the scope of btn // | btn.connect(foo, "bar", function(){ // | console.debug(this.toString()); // | }); // tags: // protected var handle = connect.connect(obj, event, this, method); this._connects.push(handle); return handle; // _Widget.Handle }, disconnect: function(handle){ // summary: // Disconnects handle created by `connect`. // Also removes handle from this widget's list of connects. // tags: // protected var i = array.indexOf(this._connects, handle); if(i != -1){ handle.remove(); this._connects.splice(i, 1); } }, subscribe: function(t, method){ // summary: // Subscribes to the specified topic and calls the specified method // of this object and registers for unsubscribe() on widget destroy. // description: // Provide widget-specific analog to dojo.subscribe, except with the // implicit use of this widget as the target object. // t: String // The topic // method: Function // The callback // example: // | var btn = new dijit.form.Button(); // | // when /my/topic is published, this button changes its label to // | // be the parameter of the topic. // | btn.subscribe("/my/topic", function(v){ // | this.set("label", v); // | }); // tags: // protected var handle = topic.subscribe(t, lang.hitch(this, method)); this._connects.push(handle); return handle; // _Widget.Handle }, unsubscribe: function(/*Object*/ handle){ // summary: // Unsubscribes handle created by this.subscribe. // Also removes handle from this widget's list of subscriptions // tags: // protected this.disconnect(handle); }, isLeftToRight: function(){ // summary: // Return this widget's explicit or implicit orientation (true for LTR, false for RTL) // tags: // protected return this.dir ? (this.dir == "ltr") : domGeometry.isBodyLtr(); //Boolean }, isFocusable: function(){ // summary: // Return true if this widget can currently be focused // and false if not return this.focus && (domStyle.get(this.domNode, "display") != "none"); }, placeAt: function(/* String|DomNode|_Widget */reference, /* String?|Int? */position){ // summary: // Place this widget's domNode reference somewhere in the DOM based // on standard domConstruct.place conventions, or passing a Widget reference that // contains and addChild member. // // description: // A convenience function provided in all _Widgets, providing a simple // shorthand mechanism to put an existing (or newly created) Widget // somewhere in the dom, and allow chaining. // // reference: // The String id of a domNode, a domNode reference, or a reference to a Widget possessing // an addChild method. // // position: // If passed a string or domNode reference, the position argument // accepts a string just as domConstruct.place does, one of: "first", "last", // "before", or "after". // // If passed a _Widget reference, and that widget reference has an ".addChild" method, // it will be called passing this widget instance into that method, supplying the optional // position index passed. // // returns: // dijit._Widget // Provides a useful return of the newly created dijit._Widget instance so you // can "chain" this function by instantiating, placing, then saving the return value // to a variable. // // example: // | // create a Button with no srcNodeRef, and place it in the body: // | var button = new dijit.form.Button({ label:"click" }).placeAt(win.body()); // | // now, 'button' is still the widget reference to the newly created button // | button.on("click", function(e){ console.log('click'); })); // // example: // | // create a button out of a node with id="src" and append it to id="wrapper": // | var button = new dijit.form.Button({},"src").placeAt("wrapper"); // // example: // | // place a new button as the first element of some div // | var button = new dijit.form.Button({ label:"click" }).placeAt("wrapper","first"); // // example: // | // create a contentpane and add it to a TabContainer // | var tc = dijit.byId("myTabs"); // | new dijit.layout.ContentPane({ href:"foo.html", title:"Wow!" }).placeAt(tc) if(reference.declaredClass && reference.addChild){ reference.addChild(this, position); }else{ domConstruct.place(this.domNode, reference, position); } return this; }, getTextDir: function(/*String*/ text,/*String*/ originalDir){ // summary: // Return direction of the text. // The function overridden in the _BidiSupport module, // its main purpose is to calculate the direction of the // text, if was defined by the programmer through textDir. // tags: // protected. return originalDir; }, applyTextDir: function(/*===== element, text =====*/){ // summary: // The function overridden in the _BidiSupport module, // originally used for setting element.dir according to this.textDir. // In this case does nothing. // element: DOMNode // text: String // tags: // protected. } }); }); }}}); define("dijit/dijit", [ ".", "./_base", "dojo/parser", "./_Widget", "./_TemplatedMixin", "./_Container", "./layout/_LayoutWidget", "./form/_FormWidget", "./form/_FormValueWidget" ], function(dijit){ // module: // dijit/dijit // summary: // A roll-up for common dijit methods // All the stuff in _base (these are the function that are guaranteed available without an explicit dojo.require) // And some other stuff that we tend to pull in all the time anyway return dijit; });