diff options
| author | Tristan Zur <tzur@web.web.ccwn.org> | 2014-03-27 22:27:47 +0100 |
|---|---|---|
| committer | Tristan Zur <tzur@web.web.ccwn.org> | 2014-03-27 22:27:47 +0100 |
| commit | b62676ca5d3d6f6ba3f019ea3f99722e165a98d8 (patch) | |
| tree | 86722cb80f07d4569f90088eeaea2fc2f6e2ef94 /js/dojo/dojox/mobile.js.uncompressed.js | |
Diffstat (limited to 'js/dojo/dojox/mobile.js.uncompressed.js')
| -rw-r--r-- | js/dojo/dojox/mobile.js.uncompressed.js | 4554 |
1 files changed, 4554 insertions, 0 deletions
diff --git a/js/dojo/dojox/mobile.js.uncompressed.js b/js/dojo/dojox/mobile.js.uncompressed.js new file mode 100644 index 0000000..9f12346 --- /dev/null +++ b/js/dojo/dojox/mobile.js.uncompressed.js @@ -0,0 +1,4554 @@ +/* + 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:{ +'dojox/mobile/ViewController':function(){ +define([ + "dojo/_base/kernel", + "dojo/_base/array", + "dojo/_base/connect", + "dojo/_base/declare", + "dojo/_base/lang", + "dojo/_base/window", + "dojo/dom", + "dojo/dom-class", + "dojo/dom-construct", +// "dojo/hash", // optionally prereq'ed + "dojo/on", + "dojo/ready", + "dijit/registry", // registry.byId + "./ProgressIndicator", + "./TransitionEvent" +], function(dojo, array, connect, declare, lang, win, dom, domClass, domConstruct, on, ready, registry, ProgressIndicator, TransitionEvent){ + + // module: + // dojox/mobile/ViewController + // summary: + // A singleton class that controlls view transition. + + var dm = lang.getObject("dojox.mobile", true); + + var Controller = declare("dojox.mobile.ViewController", null, { + // summary: + // A singleton class that controlls view transition. + // description: + // This class listens to the "startTransition" events and performs + // view transitions. If the transition destination is an external + // view specified with the url parameter, retrieves the view + // content and parses it to create a new target view. + + constructor: function(){ + this.viewMap={}; + this.currentView=null; + this.defaultView=null; + ready(lang.hitch(this, function(){ + on(win.body(), "startTransition", lang.hitch(this, "onStartTransition")); + })); + }, + + findCurrentView: function(moveTo,src){ + // summary: + // Searches for the currently showing view. + if(moveTo){ + var w = registry.byId(moveTo); + if(w && w.getShowingView){ return w.getShowingView(); } + } + if(dm.currentView){ + return dm.currentView; //TODO:1.8 may not return an expected result especially when views are nested + } + //TODO:1.8 probably never reaches here + w = src; + while(true){ + w = w.getParent(); + if(!w){ return null; } + if(domClass.contains(w.domNode, "mblView")){ break; } + } + return w; + }, + + onStartTransition: function(evt){ + // summary: + // A handler that performs view transition. + + evt.preventDefault(); + if(!evt.detail || (evt.detail && !evt.detail.moveTo && !evt.detail.href && !evt.detail.url && !evt.detail.scene)){ return; } + var w = this.findCurrentView(evt.detail.moveTo, (evt.target && evt.target.id)?registry.byId(evt.target.id):registry.byId(evt.target)); // the current view widget + if(!w || (evt.detail && evt.detail.moveTo && w === registry.byId(evt.detail.moveTo))){ return; } + if(evt.detail.href){ + var t = registry.byId(evt.target.id).hrefTarget; + if(t){ + dm.openWindow(evt.detail.href, t); + }else{ + w.performTransition(null, evt.detail.transitionDir, evt.detail.transition, evt.target, function(){location.href = evt.detail.href;}); + } + return; + } else if(evt.detail.scene){ + connect.publish("/dojox/mobile/app/pushScene", [evt.detail.scene]); + return; + } + var moveTo = evt.detail.moveTo; + if(evt.detail.url){ + var id; + if(dm._viewMap && dm._viewMap[evt.detail.url]){ + // external view has already been loaded + id = dm._viewMap[evt.detail.url]; + }else{ + // get the specified external view and append it to the <body> + var text = this._text; + if(!text){ + if(registry.byId(evt.target.id).sync){ + // We do not add explicit dependency on dojo/_base/xhr to this module + // to be able to create a build that does not contain dojo/_base/xhr. + // User applications that do sync loading here need to explicitly + // require dojo/_base/xhr up front. + dojo.xhrGet({url:evt.detail.url, sync:true, load:function(result){ + text = lang.trim(result); + }}); + }else{ + var s = "dojo/_base/xhr"; // assign to a variable so as not to be picked up by the build tool + require([s], lang.hitch(this, function(xhr){ + var prog = ProgressIndicator.getInstance(); + win.body().appendChild(prog.domNode); + prog.start(); + var obj = xhr.get({ + url: evt.detail.url, + handleAs: "text" + }); + obj.addCallback(lang.hitch(this, function(response, ioArgs){ + prog.stop(); + if(response){ + this._text = response; + new TransitionEvent(evt.target, { + transition: evt.detail.transition, + transitionDir: evt.detail.transitionDir, + moveTo: moveTo, + href: evt.detail.href, + url: evt.detail.url, + scene: evt.detail.scene}, + evt.detail) + .dispatch(); + } + })); + obj.addErrback(function(error){ + prog.stop(); + console.log("Failed to load "+evt.detail.url+"\n"+(error.description||error)); + }); + })); + return; + } + } + this._text = null; + id = this._parse(text, registry.byId(evt.target.id).urlTarget); + if(!dm._viewMap){ + dm._viewMap = []; + } + dm._viewMap[evt.detail.url] = id; + } + moveTo = id; + w = this.findCurrentView(moveTo,registry.byId(evt.target.id)) || w; // the current view widget + } + w.performTransition(moveTo, evt.detail.transitionDir, evt.detail.transition, null, null); + }, + + _parse: function(text, id){ + // summary: + // Parses the given view content. + // description: + // If the content is html fragment, constructs dom tree with it + // and runs the parser. If the content is json data, passes it + // to _instantiate(). + var container, view, i, j, len; + var currentView = this.findCurrentView(); + var target = registry.byId(id) && registry.byId(id).containerNode + || dom.byId(id) + || currentView && currentView.domNode.parentNode + || win.body(); + // if a fixed bottom bar exists, a new view should be placed before it. + var refNode = null; + for(j = target.childNodes.length - 1; j >= 0; j--){ + var c = target.childNodes[j]; + if(c.nodeType === 1){ + if(c.getAttribute("fixed") === "bottom"){ + refNode = c; + } + break; + } + } + if(text.charAt(0) === "<"){ // html markup + container = domConstruct.create("DIV", {innerHTML: text}); + for(i = 0; i < container.childNodes.length; i++){ + var n = container.childNodes[i]; + if(n.nodeType === 1){ + view = n; // expecting <div dojoType="dojox.mobile.View"> + break; + } + } + if(!view){ + console.log("dojox.mobile.ViewController#_parse: invalid view content"); + return; + } + view.style.visibility = "hidden"; + target.insertBefore(container, refNode); + var ws = dojo.parser.parse(container); + array.forEach(ws, function(w){ + if(w && !w._started && w.startup){ + w.startup(); + } + }); + + // allows multiple root nodes in the fragment, + // but transition will be performed to the 1st view. + for(i = 0, len = container.childNodes.length; i < len; i++){ + target.insertBefore(container.firstChild, refNode); // reparent + } + target.removeChild(container); + + registry.byNode(view)._visible = true; + }else if(text.charAt(0) === "{"){ // json + container = domConstruct.create("DIV"); + target.insertBefore(container, refNode); + this._ws = []; + view = this._instantiate(eval('('+text+')'), container); + for(i = 0; i < this._ws.length; i++){ + var w = this._ws[i]; + w.startup && !w._started && (!w.getParent || !w.getParent()) && w.startup(); + } + this._ws = null; + } + view.style.display = "none"; + view.style.visibility = "visible"; + return dojo.hash ? "#" + view.id : view.id; + }, + + _instantiate: function(/*Object*/obj, /*DomNode*/node, /*Widget*/parent){ + // summary: + // Given the evaluated json data, does the same thing as what + // the parser does. + var widget; + for(var key in obj){ + if(key.charAt(0) == "@"){ continue; } + var cls = lang.getObject(key); + if(!cls){ continue; } + var params = {}; + var proto = cls.prototype; + var objs = lang.isArray(obj[key]) ? obj[key] : [obj[key]]; + for(var i = 0; i < objs.length; i++){ + for(var prop in objs[i]){ + if(prop.charAt(0) == "@"){ + var val = objs[i][prop]; + prop = prop.substring(1); + if(typeof proto[prop] == "string"){ + params[prop] = val; + }else if(typeof proto[prop] == "number"){ + params[prop] = val - 0; + }else if(typeof proto[prop] == "boolean"){ + params[prop] = (val != "false"); + }else if(typeof proto[prop] == "object"){ + params[prop] = eval("(" + val + ")"); + } + } + } + widget = new cls(params, node); + if(node){ // to call View's startup() + widget._visible = true; + this._ws.push(widget); + } + if(parent && parent.addChild){ + parent.addChild(widget); + } + this._instantiate(objs[i], null, widget); + } + } + return widget && widget.domNode; + } + }); + new Controller(); // singleton + return Controller; +}); + + +}, +'dojox/mobile/RoundRect':function(){ +define([ + "dojo/_base/array", + "dojo/_base/declare", + "dojo/_base/window", + "dijit/_Contained", + "dijit/_Container", + "dijit/_WidgetBase" +], function(array, declare, win, Contained, Container, WidgetBase){ + +/*===== + var Contained = dijit._Contained; + var Container = dijit._Container; + var WidgetBase = dijit._WidgetBase; +=====*/ + + // module: + // dojox/mobile/RoundRect + // summary: + // A simple round rectangle container. + + return declare("dojox.mobile.RoundRect", [WidgetBase, Container, Contained], { + // summary: + // A simple round rectangle container. + // description: + // RoundRect is a simple round rectangle container for any HTML + // and/or widgets. You can achieve the same appearance by just + // applying the -webkit-border-radius style to a div tag. However, + // if you use RoundRect, you can get a round rectangle even on + // non-CSS3 browsers such as (older) IE. + + // shadow: Boolean + // If true, adds a shadow effect to the container element. + shadow: false, + + buildRendering: function(){ + this.domNode = this.containerNode = this.srcNodeRef || win.doc.createElement("DIV"); + this.domNode.className = this.shadow ? "mblRoundRect mblShadow" : "mblRoundRect"; + }, + + resize: function(){ + // summary: + // Calls resize() of each child widget. + array.forEach(this.getChildren(), function(child){ + if(child.resize){ child.resize(); } + }); + } + }); +}); + +}, +'dojox/mobile/RoundRectList':function(){ +define([ + "dojo/_base/array", + "dojo/_base/declare", + "dojo/_base/window", + "dijit/_Contained", + "dijit/_Container", + "dijit/_WidgetBase" +], function(array, declare, win, Contained, Container, WidgetBase){ + +/*===== + var Contained = dijit._Contained; + var Container = dijit._Container; + var WidgetBase = dijit._WidgetBase; +=====*/ + + // module: + // dojox/mobile/RoundRectList + // summary: + // A rounded rectangle list. + + return declare("dojox.mobile.RoundRectList", [WidgetBase, Container, Contained], { + // summary: + // A rounded rectangle list. + // description: + // RoundRectList is a rounded rectangle list, which can be used to + // display a group of items. Each item must be + // dojox.mobile.ListItem. + + // transition: String + // The default animated transition effect for child items. + transition: "slide", + + // iconBase: String + // The default icon path for child items. + iconBase: "", + + // iconPos: String + // The default icon position for child items. + iconPos: "", + + // select: String + // Selection mode of the list. The check mark is shown for the + // selected list item(s). The value can be "single", "multiple", or + // "". If "single", there can be only one selected item at a time. + // If "multiple", there can be multiple selected items at a time. + select: "", + + // stateful: String + // If true, the last selected item remains highlighted. + stateful: false, + + buildRendering: function(){ + this.domNode = this.containerNode = this.srcNodeRef || win.doc.createElement("UL"); + this.domNode.className = "mblRoundRectList"; + }, + + resize: function(){ + // summary: + // Calls resize() of each child widget. + array.forEach(this.getChildren(), function(child){ + if(child.resize){ child.resize(); } + }); + }, + + onCheckStateChanged: function(/*Widget*/listItem, /*String*/newState){ + // summary: + // Stub function to connect to from your application. + // description: + // Called when the check state has been changed. + }, + + _setStatefulAttr: function(stateful){ + this.stateful = stateful; + array.forEach(this.getChildren(), function(child){ + child.setArrow && child.setArrow(); + }); + }, + + deselectItem: function(/*ListItem*/item){ + // summary: + // Deselects the given item. + item.deselect(); + }, + + deselectAll: function(){ + // summary: + // Deselects all the items. + array.forEach(this.getChildren(), function(child){ + child.deselect && child.deselect(); + }); + }, + + selectItem: function(/*ListItem*/item){ + // summary: + // Selects the given item. + item.select(); + } + }); +}); + +}, +'dojox/mobile/sniff':function(){ +define([ + "dojo/_base/window", + "dojo/_base/sniff" +], function(win, has){ + + var ua = navigator.userAgent; + + // BlackBerry (OS 6 or later only) + has.add("bb", ua.indexOf("BlackBerry") >= 0 && parseFloat(ua.split("Version/")[1]) || undefined, undefined, true); + + // Android + has.add("android", parseFloat(ua.split("Android ")[1]) || undefined, undefined, true); + + // iPhone, iPod, or iPad + // If iPod or iPad is detected, in addition to has("ipod") or has("ipad"), + // has("iphone") will also have iOS version number. + if(ua.match(/(iPhone|iPod|iPad)/)){ + var p = RegExp.$1.replace(/P/, 'p'); + var v = ua.match(/OS ([\d_]+)/) ? RegExp.$1 : "1"; + var os = parseFloat(v.replace(/_/, '.').replace(/_/g, '')); + has.add(p, os, undefined, true); + has.add("iphone", os, undefined, true); + } + + if(has("webkit")){ + has.add("touch", (typeof win.doc.documentElement.ontouchstart != "undefined" && + navigator.appVersion.indexOf("Mobile") != -1) || !!has("android"), undefined, true); + } + + return has; +}); + +}, +'dojox/mobile/TransitionEvent':function(){ +define([ + "dojo/_base/declare", + "dojo/_base/Deferred", + "dojo/_base/lang", + "dojo/on", + "./transition" +], function(declare, Deferred, lang, on, transitDeferred){ + + return declare("dojox.mobile.TransitionEvent", null, { + constructor: function(target, transitionOptions, triggerEvent){ + this.transitionOptions=transitionOptions; + this.target = target; + this.triggerEvent=triggerEvent||null; + }, + + dispatch: function(){ + var opts = {bubbles:true, cancelable:true, detail: this.transitionOptions, triggerEvent: this.triggerEvent}; + //console.log("Target: ", this.target, " opts: ", opts); + + var evt = on.emit(this.target,"startTransition", opts); + //console.log('evt: ', evt); + if(evt){ + Deferred.when(transitDeferred, lang.hitch(this, function(transition){ + Deferred.when(transition.call(this, evt), lang.hitch(this, function(results){ + this.endTransition(results); + })); + })); + } + }, + + endTransition: function(results){ + on.emit(this.target, "endTransition" , {detail: results.transitionOptions}); + } + }); +}); + +}, +'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. + } +}); + +}); + +}, +'dojox/mobile/View':function(){ +define("dojox/mobile/View", [ + "dojo/_base/kernel", // to test dojo.hash + "dojo/_base/array", + "dojo/_base/config", + "dojo/_base/connect", + "dojo/_base/declare", + "dojo/_base/lang", + "dojo/_base/sniff", + "dojo/_base/window", + "dojo/_base/Deferred", + "dojo/dom", + "dojo/dom-class", + "dojo/dom-geometry", + "dojo/dom-style", +// "dojo/hash", // optionally prereq'ed + "dijit/registry", // registry.byNode + "dijit/_Contained", + "dijit/_Container", + "dijit/_WidgetBase", + "./ViewController", // to load ViewController for you (no direct references) + "./transition" +], function(dojo, array, config, connect, declare, lang, has, win, Deferred, dom, domClass, domGeometry, domStyle, registry, Contained, Container, WidgetBase, ViewController, transitDeferred){ + +/*===== + var Contained = dijit._Contained; + var Container = dijit._Container; + var WidgetBase = dijit._WidgetBase; + var ViewController = dojox.mobile.ViewController; +=====*/ + + // module: + // dojox/mobile/View + // summary: + // A widget that represents a view that occupies the full screen + + var dm = lang.getObject("dojox.mobile", true); + + return declare("dojox.mobile.View", [WidgetBase, Container, Contained], { + // summary: + // A widget that represents a view that occupies the full screen + // description: + // View acts as a container for any HTML and/or widgets. An entire + // HTML page can have multiple View widgets and the user can + // navigate through the views back and forth without page + // transitions. + + // selected: Boolean + // If true, the view is displayed at startup time. + selected: false, + + // keepScrollPos: Boolean + // If true, the scroll position is kept between views. + keepScrollPos: true, + + constructor: function(params, node){ + if(node){ + dom.byId(node).style.visibility = "hidden"; + } + this._aw = has("android") >= 2.2 && has("android") < 3; // flag for android animation workaround + }, + + buildRendering: function(){ + this.domNode = this.containerNode = this.srcNodeRef || win.doc.createElement("DIV"); + this.domNode.className = "mblView"; + this.connect(this.domNode, "webkitAnimationEnd", "onAnimationEnd"); + this.connect(this.domNode, "webkitAnimationStart", "onAnimationStart"); + if(!config['mblCSS3Transition']){ + this.connect(this.domNode, "webkitTransitionEnd", "onAnimationEnd"); + } + var id = location.href.match(/#(\w+)([^\w=]|$)/) ? RegExp.$1 : null; + + this._visible = this.selected && !id || this.id == id; + + if(this.selected){ + dm._defaultView = this; + } + }, + + startup: function(){ + if(this._started){ return; } + var siblings = []; + var children = this.domNode.parentNode.childNodes; + var visible = false; + // check if a visible view exists + for(var i = 0; i < children.length; i++){ + var c = children[i]; + if(c.nodeType === 1 && domClass.contains(c, "mblView")){ + siblings.push(c); + visible = visible || registry.byNode(c)._visible; + } + } + var _visible = this._visible; + // if no visible view exists, make the first view visible + if(siblings.length === 1 || (!visible && siblings[0] === this.domNode)){ + _visible = true; + } + var _this = this; + setTimeout(function(){ // necessary to render the view correctly + if(!_visible){ + _this.domNode.style.display = "none"; + }else{ + dm.currentView = _this; //TODO:1.8 reconsider this. currentView may not have a currently showing view when views are nested. + _this.onStartView(); + connect.publish("/dojox/mobile/startView", [_this]); + } + if(_this.domNode.style.visibility != "visible"){ // this check is to avoid screen flickers + _this.domNode.style.visibility = "visible"; + } + var parent = _this.getParent && _this.getParent(); + if(!parent || !parent.resize){ // top level widget + _this.resize(); + } + }, has("ie") ? 100 : 0); // give IE a little time to complete drawing + this.inherited(arguments); + }, + + resize: function(){ + // summary: + // Calls resize() of each child widget. + array.forEach(this.getChildren(), function(child){ + if(child.resize){ child.resize(); } + }); + }, + + onStartView: function(){ + // summary: + // Stub function to connect to from your application. + // description: + // Called only when this view is shown at startup time. + }, + + onBeforeTransitionIn: function(moveTo, dir, transition, context, method){ + // summary: + // Stub function to connect to from your application. + // description: + // Called before the arriving transition occurs. + }, + + onAfterTransitionIn: function(moveTo, dir, transition, context, method){ + // summary: + // Stub function to connect to from your application. + // description: + // Called after the arriving transition occurs. + }, + + onBeforeTransitionOut: function(moveTo, dir, transition, context, method){ + // summary: + // Stub function to connect to from your application. + // description: + // Called before the leaving transition occurs. + }, + + onAfterTransitionOut: function(moveTo, dir, transition, context, method){ + // summary: + // Stub function to connect to from your application. + // description: + // Called after the leaving transition occurs. + }, + + _saveState: function(moveTo, dir, transition, context, method){ + this._context = context; + this._method = method; + if(transition == "none"){ + transition = null; + } + this._moveTo = moveTo; + this._dir = dir; + this._transition = transition; + this._arguments = lang._toArray(arguments); + this._args = []; + if(context || method){ + for(var i = 5; i < arguments.length; i++){ + this._args.push(arguments[i]); + } + } + }, + + _fixViewState: function(/*DomNode*/toNode){ + // summary: + // Sanity check for view transition states. + // description: + // Sometimes uninitialization of Views fails after making view transition, + // and that results in failure of subsequent view transitions. + // This function does the uninitialization for all the sibling views. + var nodes = this.domNode.parentNode.childNodes; + for(var i = 0; i < nodes.length; i++){ + var n = nodes[i]; + if(n.nodeType === 1 && domClass.contains(n, "mblView")){ + n.className = "mblView"; //TODO: Should remove classes one by one. This would clear user defined classes or even mblScrollableView. + } + } + toNode.className = "mblView"; // just in case toNode is a sibling of an ancestor. + }, + + convertToId: function(moveTo){ + if(typeof(moveTo) == "string"){ + // removes a leading hash mark (#) and params if exists + // ex. "#bar&myParam=0003" -> "bar" + moveTo.match(/^#?([^&?]+)/); + return RegExp.$1; + } + return moveTo; + }, + + performTransition: function(/*String*/moveTo, /*Number*/dir, /*String*/transition, + /*Object|null*/context, /*String|Function*/method /*optional args*/){ + // summary: + // Function to perform the various types of view transitions, such as fade, slide, and flip. + // moveTo: String + // The id of the transition destination view which resides in + // the current page. + // If the value has a hash sign ('#') before the id + // (e.g. #view1) and the dojo.hash module is loaded by the user + // application, the view transition updates the hash in the + // browser URL so that the user can bookmark the destination + // view. In this case, the user can also use the browser's + // back/forward button to navigate through the views in the + // browser history. + // If null, transitions to a blank view. + // If '#', returns immediately without transition. + // dir: Number + // The transition direction. If 1, transition forward. If -1, transition backward. + // For example, the slide transition slides the view from right to left when dir == 1, + // and from left to right when dir == -1. + // transition: String + // A type of animated transition effect. You can choose from + // the standard transition types, "slide", "fade", "flip", or + // from the extended transition types, "cover", "coverv", + // "dissolve", "reveal", "revealv", "scaleIn", + // "scaleOut", "slidev", "swirl", "zoomIn", "zoomOut". If + // "none" is specified, transition occurs immediately without + // animation. + // context: Object + // The object that the callback function will receive as "this". + // method: String|Function + // A callback function that is called when the transition has been finished. + // A function reference, or name of a function in context. + // tags: + // public + // + // example: + // Transition backward to a view whose id is "foo" with the slide animation. + // | performTransition("foo", -1, "slide"); + // + // example: + // Transition forward to a blank view, and then open another page. + // | performTransition(null, 1, "slide", null, function(){location.href = href;}); + if(moveTo === "#"){ return; } + if(dojo.hash){ + if(typeof(moveTo) == "string" && moveTo.charAt(0) == '#' && !dm._params){ + dm._params = []; + for(var i = 0; i < arguments.length; i++){ + dm._params.push(arguments[i]); + } + dojo.hash(moveTo); + return; + } + } + this._saveState.apply(this, arguments); + var toNode; + if(moveTo){ + toNode = this.convertToId(moveTo); + }else{ + if(!this._dummyNode){ + this._dummyNode = win.doc.createElement("DIV"); + win.body().appendChild(this._dummyNode); + } + toNode = this._dummyNode; + } + var fromNode = this.domNode; + var fromTop = fromNode.offsetTop; + toNode = this.toNode = dom.byId(toNode); + if(!toNode){ console.log("dojox.mobile.View#performTransition: destination view not found: "+moveTo); return; } + toNode.style.visibility = this._aw ? "visible" : "hidden"; + toNode.style.display = ""; + this._fixViewState(toNode); + var toWidget = registry.byNode(toNode); + if(toWidget){ + // Now that the target view became visible, it's time to run resize() + if(config["mblAlwaysResizeOnTransition"] || !toWidget._resized){ + dm.resizeAll(null, toWidget); + toWidget._resized = true; + } + + if(transition && transition != "none"){ + // Temporarily add padding to align with the fromNode while transition + toWidget.containerNode.style.paddingTop = fromTop + "px"; + } + + toWidget.movedFrom = fromNode.id; + } + + this.onBeforeTransitionOut.apply(this, arguments); + connect.publish("/dojox/mobile/beforeTransitionOut", [this].concat(lang._toArray(arguments))); + if(toWidget){ + // perform view transition keeping the scroll position + if(this.keepScrollPos && !this.getParent()){ + var scrollTop = win.body().scrollTop || win.doc.documentElement.scrollTop || win.global.pageYOffset || 0; + fromNode._scrollTop = scrollTop; + var toTop = (dir == 1) ? 0 : (toNode._scrollTop || 0); + toNode.style.top = "0px"; + if(scrollTop > 1 || toTop !== 0){ + fromNode.style.top = toTop - scrollTop + "px"; + if(config["mblHideAddressBar"] !== false){ + setTimeout(function(){ // iPhone needs setTimeout + win.global.scrollTo(0, (toTop || 1)); + }, 0); + } + } + }else{ + toNode.style.top = "0px"; + } + toWidget.onBeforeTransitionIn.apply(toWidget, arguments); + connect.publish("/dojox/mobile/beforeTransitionIn", [toWidget].concat(lang._toArray(arguments))); + } + if(!this._aw){ + toNode.style.display = "none"; + toNode.style.visibility = "visible"; + } + + if(dm._iw && dm.scrollable){ // Workaround for iPhone flicker issue (only when scrollable.js is loaded) + var ss = dm.getScreenSize(); + // Show cover behind the view. + // cover's z-index is set to -10000, lower than z-index value specified in transition css. + win.body().appendChild(dm._iwBgCover); + domStyle.set(dm._iwBgCover, { + position: "absolute", + top: "0px", + left: "0px", + height: (ss.h + 1) + "px", // "+1" means the height of scrollTo(0,1) + width: ss.w + "px", + backgroundColor: domStyle.get(win.body(), "background-color"), + zIndex: -10000, + display: "" + }); + // Show toNode behind the cover. + domStyle.set(toNode, { + position: "absolute", + zIndex: -10001, + visibility: "visible", + display: "" + }); + // setTimeout seems to be necessary to avoid flicker. + // Also the duration of setTimeout should be long enough to avoid flicker. + // 0 is not effective. 50 sometimes causes flicker. + setTimeout(lang.hitch(this, function(){ + this._doTransition(fromNode, toNode, transition, dir); + }), 80); + }else{ + this._doTransition(fromNode, toNode, transition, dir); + } + }, + _toCls: function(s){ + // convert from transition name to corresponding class name + // ex. "slide" -> "mblSlide" + return "mbl"+s.charAt(0).toUpperCase() + s.substring(1); + }, + + _doTransition: function(fromNode, toNode, transition, dir){ + var rev = (dir == -1) ? " mblReverse" : ""; + if(dm._iw && dm.scrollable){ // Workaround for iPhone flicker issue (only when scrollable.js is loaded) + // Show toNode after flicker ends + domStyle.set(toNode, { + position: "", + zIndex: "" + }); + // Remove cover + win.body().removeChild(dm._iwBgCover); + }else if(!this._aw){ + toNode.style.display = ""; + } + if(!transition || transition == "none"){ + this.domNode.style.display = "none"; + this.invokeCallback(); + }else if(config['mblCSS3Transition']){ + //get dojox/css3/transit first + Deferred.when(transitDeferred, lang.hitch(this, function(transit){ + //follow the style of .mblView.mblIn in View.css + //need to set the toNode to absolute position + var toPosition = domStyle.get(toNode, "position"); + domStyle.set(toNode, "position", "absolute"); + Deferred.when(transit(fromNode, toNode, {transition: transition, reverse: (dir===-1)?true:false}),lang.hitch(this,function(){ + domStyle.set(toNode, "position", toPosition); + this.invokeCallback(); + })); + })); + }else{ + var s = this._toCls(transition); + domClass.add(fromNode, s + " mblOut" + rev); + domClass.add(toNode, s + " mblIn" + rev); + setTimeout(function(){ + domClass.add(fromNode, "mblTransition"); + domClass.add(toNode, "mblTransition"); + }, 100); + // set transform origin + var fromOrigin = "50% 50%"; + var toOrigin = "50% 50%"; + var scrollTop, posX, posY; + if(transition.indexOf("swirl") != -1 || transition.indexOf("zoom") != -1){ + if(this.keepScrollPos && !this.getParent()){ + scrollTop = win.body().scrollTop || win.doc.documentElement.scrollTop || win.global.pageYOffset || 0; + }else{ + scrollTop = -domGeometry.position(fromNode, true).y; + } + posY = win.global.innerHeight / 2 + scrollTop; + fromOrigin = "50% " + posY + "px"; + toOrigin = "50% " + posY + "px"; + }else if(transition.indexOf("scale") != -1){ + var viewPos = domGeometry.position(fromNode, true); + posX = ((this.clickedPosX !== undefined) ? this.clickedPosX : win.global.innerWidth / 2) - viewPos.x; + if(this.keepScrollPos && !this.getParent()){ + scrollTop = win.body().scrollTop || win.doc.documentElement.scrollTop || win.global.pageYOffset || 0; + }else{ + scrollTop = -viewPos.y; + } + posY = ((this.clickedPosY !== undefined) ? this.clickedPosY : win.global.innerHeight / 2) + scrollTop; + fromOrigin = posX + "px " + posY + "px"; + toOrigin = posX + "px " + posY + "px"; + } + domStyle.set(fromNode, {webkitTransformOrigin:fromOrigin}); + domStyle.set(toNode, {webkitTransformOrigin:toOrigin}); + } + dm.currentView = registry.byNode(toNode); + }, + + onAnimationStart: function(e){ + }, + + + onAnimationEnd: function(e){ + var name = e.animationName || e.target.className; + if(name.indexOf("Out") === -1 && + name.indexOf("In") === -1 && + name.indexOf("Shrink") === -1){ return; } + var isOut = false; + if(domClass.contains(this.domNode, "mblOut")){ + isOut = true; + this.domNode.style.display = "none"; + domClass.remove(this.domNode, [this._toCls(this._transition), "mblIn", "mblOut", "mblReverse"]); + }else{ + // Reset the temporary padding + this.containerNode.style.paddingTop = ""; + } + domStyle.set(this.domNode, {webkitTransformOrigin:""}); + if(name.indexOf("Shrink") !== -1){ + var li = e.target; + li.style.display = "none"; + domClass.remove(li, "mblCloseContent"); + } + if(isOut){ + this.invokeCallback(); + } + // this.domNode may be destroyed as a result of invoking the callback, + // so check for that before accessing it. + this.domNode && (this.domNode.className = "mblView"); + + // clear the clicked position + this.clickedPosX = this.clickedPosY = undefined; + }, + + invokeCallback: function(){ + this.onAfterTransitionOut.apply(this, this._arguments); + connect.publish("/dojox/mobile/afterTransitionOut", [this].concat(this._arguments)); + var toWidget = registry.byNode(this.toNode); + if(toWidget){ + toWidget.onAfterTransitionIn.apply(toWidget, this._arguments); + connect.publish("/dojox/mobile/afterTransitionIn", [toWidget].concat(this._arguments)); + toWidget.movedFrom = undefined; + } + + var c = this._context, m = this._method; + if(!c && !m){ return; } + if(!m){ + m = c; + c = null; + } + c = c || win.global; + if(typeof(m) == "string"){ + c[m].apply(c, this._args); + }else{ + m.apply(c, this._args); + } + }, + + getShowingView: function(){ + // summary: + // Find the currently showing view from my sibling views. + // description: + // Note that dojox.mobile.currentView is the last shown view. + // If the page consists of a splitter, there are multiple showing views. + var nodes = this.domNode.parentNode.childNodes; + for(var i = 0; i < nodes.length; i++){ + var n = nodes[i]; + if(n.nodeType === 1 && domClass.contains(n, "mblView") && domStyle.get(n, "display") !== "none"){ + return registry.byNode(n); + } + } + return null; + }, + + show: function(){ + // summary: + // Shows this view without a transition animation. + var view = this.getShowingView(); + if(view){ + view.domNode.style.display = "none"; // from-style + } + this.domNode.style.display = ""; // to-style + dm.currentView = this; + } + }); +}); + +}, +'dojox/main':function(){ +define(["dojo/_base/kernel"], function(dojo) { + // module: + // dojox/main + // summary: + // The dojox package main module; dojox package is somewhat unusual in that the main module currently just provides an empty object. + + return dojo.dojox; +}); +}, +'dojox/mobile/transition':function(){ +define([ + "dojo/_base/Deferred", + "dojo/_base/config" +], function(Deferred, config){ + /* summary: this is the wrapper module which load + * dojox/css3/transit conditionally. If mblCSS3Transition + * is set to 'dojox/css3/transit', it will be loaded as + * the module to conduct the view transition. + */ + if(config['mblCSS3Transition']){ + //require dojox/css3/transit and resolve it as the result of transitDeferred. + var transitDeferred = new Deferred(); + require([config['mblCSS3Transition']], function(transit){ + transitDeferred.resolve(transit); + }); + return transitDeferred; + } + return null; +}); + +}, +'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 + } + +}); + +}); + +}, +'dojox/mobile/Heading':function(){ +define([ + "dojo/_base/array", + "dojo/_base/connect", + "dojo/_base/declare", + "dojo/_base/lang", + "dojo/_base/window", + "dojo/dom-class", + "dojo/dom-construct", + "dojo/dom-style", + "dijit/registry", // registry.byId + "dijit/_Contained", + "dijit/_Container", + "dijit/_WidgetBase", + "./View" +], function(array, connect, declare, lang, win, domClass, domConstruct, domStyle, registry, Contained, Container, WidgetBase, View){ + + var dm = lang.getObject("dojox.mobile", true); + +/*===== + var Contained = dijit._Contained; + var Container = dijit._Container; + var WidgetBase = dijit._WidgetBase; +=====*/ + + // module: + // dojox/mobile/Heading + // summary: + // A widget that represents a navigation bar. + + return declare("dojox.mobile.Heading", [WidgetBase, Container, Contained],{ + // summary: + // A widget that represents a navigation bar. + // description: + // Heading is a widget that represents a navigation bar, which + // usually appears at the top of an application. It usually + // displays the title of the current view and can contain a + // navigational control. If you use it with + // dojox.mobile.ScrollableView, it can also be used as a fixed + // header bar or a fixed footer bar. In such cases, specify the + // fixed="top" attribute to be a fixed header bar or the + // fixed="bottom" attribute to be a fixed footer bar. Heading can + // have one or more ToolBarButton widgets as its children. + + // back: String + // A label for the navigational control to return to the previous + // View. + back: "", + + // href: String + // A URL to open when the navigational control is pressed. + href: "", + + // moveTo: String + // The id of the transition destination view which resides in the + // current page. + // + // If the value has a hash sign ('#') before the id (e.g. #view1) + // and the dojo.hash module is loaded by the user application, the + // view transition updates the hash in the browser URL so that the + // user can bookmark the destination view. In this case, the user + // can also use the browser's back/forward button to navigate + // through the views in the browser history. + // + // If null, transitions to a blank view. + // If '#', returns immediately without transition. + moveTo: "", + + // transition: String + // A type of animated transition effect. You can choose from the + // standard transition types, "slide", "fade", "flip", or from the + // extended transition types, "cover", "coverv", "dissolve", + // "reveal", "revealv", "scaleIn", "scaleOut", "slidev", + // "swirl", "zoomIn", "zoomOut". If "none" is specified, transition + // occurs immediately without animation. + transition: "slide", + + // label: String + // A title text of the heading. If the label is not specified, the + // innerHTML of the node is used as a label. + label: "", + + // iconBase: String + // The default icon path for child items. + iconBase: "", + + // backProp: Object + // Properties for the back button. + backProp: {className: "mblArrowButton"}, + + // tag: String + // A name of html tag to create as domNode. + tag: "H1", + + buildRendering: function(){ + this.domNode = this.containerNode = this.srcNodeRef || win.doc.createElement(this.tag); + this.domNode.className = "mblHeading"; + if(!this.label){ + array.forEach(this.domNode.childNodes, function(n){ + if(n.nodeType == 3){ + var v = lang.trim(n.nodeValue); + if(v){ + this.label = v; + this.labelNode = domConstruct.create("SPAN", {innerHTML:v}, n, "replace"); + } + } + }, this); + } + if(!this.labelNode){ + this.labelNode = domConstruct.create("SPAN", null, this.domNode); + } + this.labelNode.className = "mblHeadingSpanTitle"; + this.labelDivNode = domConstruct.create("DIV", { + className: "mblHeadingDivTitle", + innerHTML: this.labelNode.innerHTML + }, this.domNode); + }, + + startup: function(){ + if(this._started){ return; } + var parent = this.getParent && this.getParent(); + if(!parent || !parent.resize){ // top level widget + var _this = this; + setTimeout(function(){ // necessary to render correctly + _this.resize(); + }, 0); + } + this.inherited(arguments); + }, + + resize: function(){ + if(this._btn){ + this._btn.style.width = this._body.offsetWidth + this._head.offsetWidth + "px"; + } + if(this.labelNode){ + // find the rightmost left button (B), and leftmost right button (C) + // +-----------------------------+ + // | |A| |B| |C| |D| | + // +-----------------------------+ + var leftBtn, rightBtn; + var children = this.containerNode.childNodes; + for(var i = children.length - 1; i >= 0; i--){ + var c = children[i]; + if(c.nodeType === 1){ + if(!rightBtn && domClass.contains(c, "mblToolBarButton") && domStyle.get(c, "float") === "right"){ + rightBtn = c; + } + if(!leftBtn && (domClass.contains(c, "mblToolBarButton") && domStyle.get(c, "float") === "left" || c === this._btn)){ + leftBtn = c; + } + } + } + + if(!this.labelNodeLen && this.label){ + this.labelNode.style.display = "inline"; + this.labelNodeLen = this.labelNode.offsetWidth; + this.labelNode.style.display = ""; + } + + var bw = this.domNode.offsetWidth; // bar width + var rw = rightBtn ? bw - rightBtn.offsetLeft + 5 : 0; // rightBtn width + var lw = leftBtn ? leftBtn.offsetLeft + leftBtn.offsetWidth + 5 : 0; // leftBtn width + var tw = this.labelNodeLen || 0; // title width + domClass[bw - Math.max(rw,lw)*2 > tw ? "add" : "remove"](this.domNode, "mblHeadingCenterTitle"); + } + array.forEach(this.getChildren(), function(child){ + if(child.resize){ child.resize(); } + }); + }, + + _setBackAttr: function(/*String*/back){ + if (!back){ + domConstruct.destroy(this._btn); + this._btn = null; + this.back = ""; + }else{ + if(!this._btn){ + var btn = domConstruct.create("DIV", this.backProp, this.domNode, "first"); + var head = domConstruct.create("DIV", {className:"mblArrowButtonHead"}, btn); + var body = domConstruct.create("DIV", {className:"mblArrowButtonBody mblArrowButtonText"}, btn); + + this._body = body; + this._head = head; + this._btn = btn; + this.backBtnNode = btn; + this.connect(body, "onclick", "onClick"); + } + this.back = back; + this._body.innerHTML = this._cv ? this._cv(this.back) : this.back; + } + this.resize(); + }, + + _setLabelAttr: function(/*String*/label){ + this.label = label; + this.labelNode.innerHTML = this.labelDivNode.innerHTML = this._cv ? this._cv(label) : label; + }, + + findCurrentView: function(){ + // summary: + // Search for the view widget that contains this widget. + var w = this; + while(true){ + w = w.getParent(); + if(!w){ return null; } + if(w instanceof View){ break; } + } + return w; + }, + + onClick: function(e){ + var h1 = this.domNode; + domClass.add(h1, "mblArrowButtonSelected"); + setTimeout(function(){ + domClass.remove(h1, "mblArrowButtonSelected"); + }, 1000); + + if(this.back && !this.moveTo && !this.href && history){ + history.back(); + return; + } + + // keep the clicked position for transition animations + var view = this.findCurrentView(); + if(view){ + view.clickedPosX = e.clientX; + view.clickedPosY = e.clientY; + } + this.goTo(this.moveTo, this.href); + }, + + goTo: function(moveTo, href){ + // summary: + // Given the destination, makes a view transition. + var view = this.findCurrentView(); + if(!view){ return; } + if(href){ + view.performTransition(null, -1, this.transition, this, function(){location.href = href;}); + }else{ + if(dm.app && dm.app.STAGE_CONTROLLER_ACTIVE){ + // If in a full mobile app, then use its mechanisms to move back a scene + connect.publish("/dojox/mobile/app/goback"); + }else{ + // Basically transition should be performed between two + // siblings that share the same parent. + // However, when views are nested and transition occurs from + // an inner view, search for an ancestor view that is a sibling + // of the target view, and use it as a source view. + var node = registry.byId(view.convertToId(moveTo)); + if(node){ + var parent = node.getParent(); + while(view){ + var myParent = view.getParent(); + if(parent === myParent){ + break; + } + view = myParent; + } + } + if(view){ + view.performTransition(moveTo, -1, this.transition); + } + } + } + } + }); +}); + +}, +'dojox/mobile/Switch':function(){ +define([ + "dojo/_base/array", + "dojo/_base/connect", + "dojo/_base/declare", + "dojo/_base/event", + "dojo/_base/window", + "dojo/dom-class", + "dijit/_Contained", + "dijit/_WidgetBase", + "./sniff" +], function(array, connect, declare, event, win, domClass, Contained, WidgetBase, has){ + +/*===== + Contained = dijit._Contained; + WidgetBase = dijit._WidgetBase; +=====*/ + + // module: + // dojox/mobile/Switch + // summary: + // A toggle switch with a sliding knob. + + return declare("dojox.mobile.Switch", [WidgetBase, Contained],{ + // summary: + // A toggle switch with a sliding knob. + // description: + // Switch is a toggle switch with a sliding knob. You can either + // tap or slide the knob to toggle the switch. The onStateChanged + // handler is called when the switch is manipulated. + + // value: String + // The initial state of the switch. "on" or "off". The default + // value is "on". + value: "on", + + // name: String + // A name for a hidden input field, which holds the current value. + name: "", + + // leftLabel: String + // The left-side label of the switch. + leftLabel: "ON", + + // rightLabel: String + // The right-side label of the switch. + rightLabel: "OFF", + + /* internal properties */ + _width: 53, + + buildRendering: function(){ + this.domNode = win.doc.createElement("DIV"); + var c = (this.srcNodeRef && this.srcNodeRef.className) || this.className || this["class"]; + this._swClass = (c || "").replace(/ .*/,""); + this.domNode.className = "mblSwitch"; + var nameAttr = this.name ? " name=\"" + this.name + "\"" : ""; + this.domNode.innerHTML = + '<div class="mblSwitchInner">' + + '<div class="mblSwitchBg mblSwitchBgLeft">' + + '<div class="mblSwitchText mblSwitchTextLeft"></div>' + + '</div>' + + '<div class="mblSwitchBg mblSwitchBgRight">' + + '<div class="mblSwitchText mblSwitchTextRight"></div>' + + '</div>' + + '<div class="mblSwitchKnob"></div>' + + '<input type="hidden"'+nameAttr+'></div>' + + '</div>'; + var n = this.inner = this.domNode.firstChild; + this.left = n.childNodes[0]; + this.right = n.childNodes[1]; + this.knob = n.childNodes[2]; + this.input = n.childNodes[3]; + }, + + postCreate: function(){ + this.connect(this.domNode, "onclick", "onClick"); + this.connect(this.domNode, has("touch") ? "touchstart" : "onmousedown", "onTouchStart"); + this._initialValue = this.value; // for reset() + }, + + _changeState: function(/*String*/state, /*Boolean*/anim){ + var on = (state === "on"); + this.left.style.display = ""; + this.right.style.display = ""; + this.inner.style.left = ""; + if(anim){ + domClass.add(this.domNode, "mblSwitchAnimation"); + } + domClass.remove(this.domNode, on ? "mblSwitchOff" : "mblSwitchOn"); + domClass.add(this.domNode, on ? "mblSwitchOn" : "mblSwitchOff"); + + var _this = this; + setTimeout(function(){ + _this.left.style.display = on ? "" : "none"; + _this.right.style.display = !on ? "" : "none"; + domClass.remove(_this.domNode, "mblSwitchAnimation"); + }, anim ? 300 : 0); + }, + + startup: function(){ + if(this._swClass.indexOf("Round") != -1){ + var r = Math.round(this.domNode.offsetHeight / 2); + this.createRoundMask(this._swClass, r, this.domNode.offsetWidth); + } + }, + + createRoundMask: function(className, r, w){ + if(!has("webkit") || !className){ return; } + if(!this._createdMasks){ this._createdMasks = []; } + if(this._createdMasks[className]){ return; } + this._createdMasks[className] = 1; + + var ctx = win.doc.getCSSCanvasContext("2d", className+"Mask", w, 100); + ctx.fillStyle = "#000000"; + ctx.beginPath(); + ctx.moveTo(r, 0); + ctx.arcTo(0, 0, 0, 2*r, r); + ctx.arcTo(0, 2*r, r, 2*r, r); + ctx.lineTo(w - r, 2*r); + ctx.arcTo(w, 2*r, w, r, r); + ctx.arcTo(w, 0, w - r, 0, r); + ctx.closePath(); + ctx.fill(); + }, + + onClick: function(e){ + if(this._moved){ return; } + this.value = this.input.value = (this.value == "on") ? "off" : "on"; + this._changeState(this.value, true); + this.onStateChanged(this.value); + }, + + onTouchStart: function(e){ + // summary: + // Internal function to handle touchStart events. + this._moved = false; + this.innerStartX = this.inner.offsetLeft; + if(!this._conn){ + this._conn = []; + this._conn.push(connect.connect(this.inner, has("touch") ? "touchmove" : "onmousemove", this, "onTouchMove")); + this._conn.push(connect.connect(this.inner, has("touch") ? "touchend" : "onmouseup", this, "onTouchEnd")); + } + this.touchStartX = e.touches ? e.touches[0].pageX : e.clientX; + this.left.style.display = ""; + this.right.style.display = ""; + event.stop(e); + }, + + onTouchMove: function(e){ + // summary: + // Internal function to handle touchMove events. + e.preventDefault(); + var dx; + if(e.targetTouches){ + if(e.targetTouches.length != 1){ return false; } + dx = e.targetTouches[0].clientX - this.touchStartX; + }else{ + dx = e.clientX - this.touchStartX; + } + var pos = this.innerStartX + dx; + var d = 10; + if(pos <= -(this._width-d)){ pos = -this._width; } + if(pos >= -d){ pos = 0; } + this.inner.style.left = pos + "px"; + if(Math.abs(dx) > d){ + this._moved = true; + } + }, + + onTouchEnd: function(e){ + // summary: + // Internal function to handle touchEnd events. + array.forEach(this._conn, connect.disconnect); + this._conn = null; + if(this.innerStartX == this.inner.offsetLeft){ + if(has("touch")){ + var ev = win.doc.createEvent("MouseEvents"); + ev.initEvent("click", true, true); + this.inner.dispatchEvent(ev); + } + return; + } + var newState = (this.inner.offsetLeft < -(this._width/2)) ? "off" : "on"; + this._changeState(newState, true); + if(newState != this.value){ + this.value = this.input.value = newState; + this.onStateChanged(newState); + } + }, + + onStateChanged: function(/*String*/newState){ + // summary: + // Stub function to connect to from your application. + // description: + // Called when the state has been changed. + }, + + _setValueAttr: function(/*String*/value){ + this._changeState(value, false); + if(this.value != value){ + this.onStateChanged(value); + } + this.value = this.input.value = value; + }, + + _setLeftLabelAttr: function(/*String*/label){ + this.leftLabel = label; + this.left.firstChild.innerHTML = this._cv ? this._cv(label) : label; + }, + + _setRightLabelAttr: function(/*String*/label){ + this.rightLabel = label; + this.right.firstChild.innerHTML = this._cv ? this._cv(label) : label; + }, + + reset: function(){ + // summary: + // Reset the widget's value to what it was at initialization time + this.set("value", this._initialValue); + } + }); +}); + +}, +'dojox/mobile/ListItem':function(){ +define("dojox/mobile/ListItem", [ + "dojo/_base/array", + "dojo/_base/connect", + "dojo/_base/declare", + "dojo/_base/lang", + "dojo/dom-class", + "dojo/dom-construct", + "dojo/has", + "./common", + "./_ItemBase", + "./TransitionEvent" +], function(array, connect, declare, lang, domClass, domConstruct, has, common, ItemBase, TransitionEvent){ + +/*===== + var ItemBase = dojox.mobile._ItemBase; +=====*/ + + // module: + // dojox/mobile/ListItem + // summary: + // An item of either RoundRectList or EdgeToEdgeList. + + return declare("dojox.mobile.ListItem", ItemBase, { + // summary: + // An item of either RoundRectList or EdgeToEdgeList. + // description: + // ListItem represents an item of either RoundRectList or + // EdgeToEdgeList. There are three ways to move to a different + // view, moveTo, href, and url. You can choose only one of them. + + // rightText: String + // A right-aligned text to display on the item. + rightText: "", + + // rightIcon: String + // An icon to display at the right hand side of the item. The value + // can be either a path for an image file or a class name of a DOM + // button. + rightIcon: "", + + // rightIcon2: String + // An icon to display at the left of the rightIcon. The value can + // be either a path for an image file or a class name of a DOM + // button. + rightIcon2: "", + + + // anchorLabel: Boolean + // If true, the label text becomes a clickable anchor text. When + // the user clicks on the text, the onAnchorLabelClicked handler is + // called. You can override or connect to the handler and implement + // any action. The handler has no default action. + anchorLabel: false, + + // noArrow: Boolean + // If true, the right hand side arrow is not displayed. + noArrow: false, + + // selected: Boolean + // If true, the item is highlighted to indicate it is selected. + selected: false, + + // checked: Boolean + // If true, a check mark is displayed at the right of the item. + checked: false, + + // arrowClass: String + // An icon to display as an arrow. The value can be either a path + // for an image file or a class name of a DOM button. + arrowClass: "mblDomButtonArrow", + + // checkClass: String + // An icon to display as a check mark. The value can be either a + // path for an image file or a class name of a DOM button. + checkClass: "mblDomButtonCheck", + + // variableHeight: Boolean + // If true, the height of the item varies according to its + // content. In dojo 1.6 or older, the "mblVariableHeight" class was + // used for this purpose. In dojo 1.7, adding the mblVariableHeight + // class still works for backward compatibility. + variableHeight: false, + + + // rightIconTitle: String + // An alt text for the right icon. + rightIconTitle: "", + + // rightIcon2Title: String + // An alt text for the right icon2. + rightIcon2Title: "", + + + // btnClass: String + // Deprecated. For backward compatibility. + btnClass: "", + + // btnClass2: String + // Deprecated. For backward compatibility. + btnClass2: "", + + // tag: String + // A name of html tag to create as domNode. + tag: "li", + + postMixInProperties: function(){ + // for backward compatibility + if(this.btnClass){ + this.rightIcon = this.btnClass; + } + this._setBtnClassAttr = this._setRightIconAttr; + this._setBtnClass2Attr = this._setRightIcon2Attr; + }, + + buildRendering: function(){ + this.domNode = this.srcNodeRef || domConstruct.create(this.tag); + this.inherited(arguments); + this.domNode.className = "mblListItem" + (this.selected ? " mblItemSelected" : ""); + + // label + var box = this.box = domConstruct.create("DIV"); + box.className = "mblListItemTextBox"; + if(this.anchorLabel){ + box.style.cursor = "pointer"; + } + var r = this.srcNodeRef; + if(r && !this.label){ + this.label = ""; + for(var i = 0, len = r.childNodes.length; i < len; i++){ + var n = r.firstChild; + if(n.nodeType === 3 && lang.trim(n.nodeValue) !== ""){ + n.nodeValue = this._cv ? this._cv(n.nodeValue) : n.nodeValue; + this.labelNode = domConstruct.create("SPAN", {className:"mblListItemLabel"}); + this.labelNode.appendChild(n); + n = this.labelNode; + } + box.appendChild(n); + } + } + if(!this.labelNode){ + this.labelNode = domConstruct.create("SPAN", {className:"mblListItemLabel"}, box); + } + if(this.anchorLabel){ + box.style.display = "inline"; // to narrow the text region + } + + var a = this.anchorNode = domConstruct.create("A"); + a.className = "mblListItemAnchor"; + this.domNode.appendChild(a); + a.appendChild(box); + }, + + startup: function(){ + if(this._started){ return; } + this.inheritParams(); + var parent = this.getParent(); + if(this.moveTo || this.href || this.url || this.clickable || (parent && parent.select)){ + this._onClickHandle = this.connect(this.anchorNode, "onclick", "onClick"); + } + this.setArrow(); + + if(domClass.contains(this.domNode, "mblVariableHeight")){ + this.variableHeight = true; + } + if(this.variableHeight){ + domClass.add(this.domNode, "mblVariableHeight"); + setTimeout(lang.hitch(this, "layoutVariableHeight")); + } + + this.set("icon", this.icon); // _setIconAttr may be called twice but this is necessary for offline instantiation + if(!this.checked && this.checkClass.indexOf(',') !== -1){ + this.set("checked", this.checked); + } + this.inherited(arguments); + }, + + resize: function(){ + if(this.variableHeight){ + this.layoutVariableHeight(); + } + }, + + onClick: function(e){ + var a = e.currentTarget; + var li = a.parentNode; + if(domClass.contains(li, "mblItemSelected")){ return; } // already selected + if(this.anchorLabel){ + for(var p = e.target; p.tagName !== this.tag.toUpperCase(); p = p.parentNode){ + if(p.className == "mblListItemTextBox"){ + domClass.add(p, "mblListItemTextBoxSelected"); + setTimeout(function(){ + domClass.remove(p, "mblListItemTextBoxSelected"); + }, has("android") ? 300 : 1000); + this.onAnchorLabelClicked(e); + return; + } + } + } + var parent = this.getParent(); + if(parent.select){ + if(parent.select === "single"){ + if(!this.checked){ + this.set("checked", true); + } + }else if(parent.select === "multiple"){ + this.set("checked", !this.checked); + } + } + this.select(); + + if (this.href && this.hrefTarget) { + common.openWindow(this.href, this.hrefTarget); + return; + } + var transOpts; + if(this.moveTo || this.href || this.url || this.scene){ + transOpts = {moveTo: this.moveTo, href: this.href, url: this.url, scene: this.scene, transition: this.transition, transitionDir: this.transitionDir}; + }else if(this.transitionOptions){ + transOpts = this.transitionOptions; + } + + if(transOpts){ + this.setTransitionPos(e); + return new TransitionEvent(this.domNode,transOpts,e).dispatch(); + } + }, + + select: function(){ + // summary: + // Makes this widget in the selected state. + var parent = this.getParent(); + if(parent.stateful){ + parent.deselectAll(); + }else{ + var _this = this; + setTimeout(function(){ + _this.deselect(); + }, has("android") ? 300 : 1000); + } + domClass.add(this.domNode, "mblItemSelected"); + }, + + deselect: function(){ + // summary: + // Makes this widget in the deselected state. + domClass.remove(this.domNode, "mblItemSelected"); + }, + + onAnchorLabelClicked: function(e){ + // summary: + // Stub function to connect to from your application. + }, + + layoutVariableHeight: function(){ + var h = this.anchorNode.offsetHeight; + if(h === this.anchorNodeHeight){ return; } + this.anchorNodeHeight = h; + array.forEach([ + this.rightTextNode, + this.rightIcon2Node, + this.rightIconNode, + this.iconNode + ], function(n){ + if(n){ + var t = Math.round((h - n.offsetHeight) / 2); + n.style.marginTop = t + "px"; + } + }); + }, + + setArrow: function(){ + // summary: + // Sets the arrow icon if necessary. + if(this.checked){ return; } + var c = ""; + var parent = this.getParent(); + if(this.moveTo || this.href || this.url || this.clickable){ + if(!this.noArrow && !(parent && parent.stateful)){ + c = this.arrowClass; + } + } + if(c){ + this._setRightIconAttr(c); + } + }, + + _setIconAttr: function(icon){ + if(!this.getParent()){ return; } // icon may be invalid because inheritParams is not called yet + this.icon = icon; + var a = this.anchorNode; + if(!this.iconNode){ + if(icon){ + var ref = this.rightIconNode || this.rightIcon2Node || this.rightTextNode || this.box; + this.iconNode = domConstruct.create("DIV", {className:"mblListItemIcon"}, ref, "before"); + } + }else{ + domConstruct.empty(this.iconNode); + } + if(icon && icon !== "none"){ + common.createIcon(icon, this.iconPos, null, this.alt, this.iconNode); + if(this.iconPos){ + domClass.add(this.iconNode.firstChild, "mblListItemSpriteIcon"); + } + domClass.remove(a, "mblListItemAnchorNoIcon"); + }else{ + domClass.add(a, "mblListItemAnchorNoIcon"); + } + }, + + _setCheckedAttr: function(/*Boolean*/checked){ + var parent = this.getParent(); + if(parent && parent.select === "single" && checked){ + array.forEach(parent.getChildren(), function(child){ + child.set("checked", false); + }); + } + this._setRightIconAttr(this.checkClass); + + var icons = this.rightIconNode.childNodes; + if(icons.length === 1){ + this.rightIconNode.style.display = checked ? "" : "none"; + }else{ + icons[0].style.display = checked ? "" : "none"; + icons[1].style.display = !checked ? "" : "none"; + } + + domClass.toggle(this.domNode, "mblListItemChecked", checked); + if(parent && this.checked !== checked){ + parent.onCheckStateChanged(this, checked); + } + this.checked = checked; + }, + + _setRightTextAttr: function(/*String*/text){ + if(!this.rightTextNode){ + this.rightTextNode = domConstruct.create("DIV", {className:"mblListItemRightText"}, this.box, "before"); + } + this.rightText = text; + this.rightTextNode.innerHTML = this._cv ? this._cv(text) : text; + }, + + _setRightIconAttr: function(/*String*/icon){ + if(!this.rightIconNode){ + var ref = this.rightIcon2Node || this.rightTextNode || this.box; + this.rightIconNode = domConstruct.create("DIV", {className:"mblListItemRightIcon"}, ref, "before"); + }else{ + domConstruct.empty(this.rightIconNode); + } + this.rightIcon = icon; + var arr = (icon || "").split(/,/); + if(arr.length === 1){ + common.createIcon(icon, null, null, this.rightIconTitle, this.rightIconNode); + }else{ + common.createIcon(arr[0], null, null, this.rightIconTitle, this.rightIconNode); + common.createIcon(arr[1], null, null, this.rightIconTitle, this.rightIconNode); + } + }, + + _setRightIcon2Attr: function(/*String*/icon){ + if(!this.rightIcon2Node){ + var ref = this.rightTextNode || this.box; + this.rightIcon2Node = domConstruct.create("DIV", {className:"mblListItemRightIcon2"}, ref, "before"); + }else{ + domConstruct.empty(this.rightIcon2Node); + } + this.rightIcon2 = icon; + common.createIcon(icon, null, null, this.rightIcon2Title, this.rightIcon2Node); + }, + + _setLabelAttr: function(/*String*/text){ + this.label = text; + this.labelNode.innerHTML = this._cv ? this._cv(text) : text; + } + }); +}); + +}, +'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; +}); + +}, +'dojox/mobile/common':function(){ +define([ + "dojo/_base/kernel", // to test dojo.hash + "dojo/_base/array", + "dojo/_base/config", + "dojo/_base/connect", + "dojo/_base/lang", + "dojo/_base/window", + "dojo/dom-class", + "dojo/dom-construct", + "dojo/dom-style", +// "dojo/hash", // optionally prereq'ed + "dojo/ready", + "dijit/registry", // registry.toArray + "./sniff", + "./uacss" +], function(dojo, array, config, connect, lang, win, domClass, domConstruct, domStyle, ready, registry, has, uacss){ + + var dm = lang.getObject("dojox.mobile", true); +/*===== + var dm = dojox.mobile; +=====*/ + + // module: + // dojox/mobile/common + // summary: + // A common module for dojox.mobile. + // description: + // This module includes common utility functions that are used by + // dojox.mobile widgets. Also, it provides functions that are commonly + // necessary for mobile web applications, such as the hide address bar + // function. + + dm.getScreenSize = function(){ + // summary: + // Returns the dimensions of the browser window. + return { + h: win.global.innerHeight || win.doc.documentElement.clientHeight, + w: win.global.innerWidth || win.doc.documentElement.clientWidth + }; + }; + + dm.updateOrient = function(){ + // summary: + // Updates the orientation specific css classes, 'dj_portrait' and + // 'dj_landscape'. + var dim = dm.getScreenSize(); + domClass.replace(win.doc.documentElement, + dim.h > dim.w ? "dj_portrait" : "dj_landscape", + dim.h > dim.w ? "dj_landscape" : "dj_portrait"); + }; + dm.updateOrient(); + + dm.tabletSize = 500; + dm.detectScreenSize = function(/*Boolean?*/force){ + // summary: + // Detects the screen size and determines if the screen is like + // phone or like tablet. If the result is changed, + // it sets either of the following css class to <html> + // - 'dj_phone' + // - 'dj_tablet' + // and it publishes either of the following events. + // - '/dojox/mobile/screenSize/phone' + // - '/dojox/mobile/screenSize/tablet' + var dim = dm.getScreenSize(); + var sz = Math.min(dim.w, dim.h); + var from, to; + if(sz >= dm.tabletSize && (force || (!this._sz || this._sz < dm.tabletSize))){ + from = "phone"; + to = "tablet"; + }else if(sz < dm.tabletSize && (force || (!this._sz || this._sz >= dm.tabletSize))){ + from = "tablet"; + to = "phone"; + } + if(to){ + domClass.replace(win.doc.documentElement, "dj_"+to, "dj_"+from); + connect.publish("/dojox/mobile/screenSize/"+to, [dim]); + } + this._sz = sz; + }; + dm.detectScreenSize(); + + dm.setupIcon = function(/*DomNode*/iconNode, /*String*/iconPos){ + // summary: + // Sets up CSS sprite for a foreground image. + if(iconNode && iconPos){ + var arr = array.map(iconPos.split(/[ ,]/),function(item){return item-0}); + var t = arr[0]; // top + var r = arr[1] + arr[2]; // right + var b = arr[0] + arr[3]; // bottom + var l = arr[1]; // left + domStyle.set(iconNode, { + clip: "rect("+t+"px "+r+"px "+b+"px "+l+"px)", + top: (iconNode.parentNode ? domStyle.get(iconNode, "top") : 0) - t + "px", + left: -l + "px" + }); + } + }; + + // dojox.mobile.hideAddressBarWait: Number + // The time in milliseconds to wait before the fail-safe hiding address + // bar runs. The value must be larger than 800. + dm.hideAddressBarWait = typeof(config["mblHideAddressBarWait"]) === "number" ? + config["mblHideAddressBarWait"] : 1500; + + dm.hide_1 = function(force){ + // summary: + // Internal function to hide the address bar. + scrollTo(0, 1); + var h = dm.getScreenSize().h + "px"; + if(has("android")){ + if(force){ + win.body().style.minHeight = h; + } + dm.resizeAll(); + }else{ + if(force || dm._h === h && h !== win.body().style.minHeight){ + win.body().style.minHeight = h; + dm.resizeAll(); + } + } + dm._h = h; + }; + + dm.hide_fs = function(){ + // summary: + // Internal function to hide the address bar for fail-safe. + // description: + // Resets the height of the body, performs hiding the address + // bar, and calls resizeAll(). + // This is for fail-safe, in case of failure to complete the + // address bar hiding in time. + var t = win.body().style.minHeight; + win.body().style.minHeight = (dm.getScreenSize().h * 2) + "px"; // to ensure enough height for scrollTo to work + scrollTo(0, 1); + setTimeout(function(){ + dm.hide_1(1); + dm._hiding = false; + }, 1000); + }; + dm.hideAddressBar = function(/*Event?*/evt){ + // summary: + // Hides the address bar. + // description: + // Tries hiding of the address bar a couple of times to do it as + // quick as possible while ensuring resize is done after the hiding + // finishes. + if(dm.disableHideAddressBar || dm._hiding){ return; } + dm._hiding = true; + dm._h = 0; + win.body().style.minHeight = (dm.getScreenSize().h * 2) + "px"; // to ensure enough height for scrollTo to work + setTimeout(dm.hide_1, 0); + setTimeout(dm.hide_1, 200); + setTimeout(dm.hide_1, 800); + setTimeout(dm.hide_fs, dm.hideAddressBarWait); + }; + + dm.resizeAll = function(/*Event?*/evt, /*Widget?*/root){ + // summary: + // Call the resize() method of all the top level resizable widgets. + // description: + // Find all widgets that do not have a parent or the parent does not + // have the resize() method, and call resize() for them. + // If a widget has a parent that has resize(), call of the widget's + // resize() is its parent's responsibility. + // evt: + // Native event object + // root: + // If specified, search the specified widget recursively for top level + // resizable widgets. + // root.resize() is always called regardless of whether root is a + // top level widget or not. + // If omitted, search the entire page. + if(dm.disableResizeAll){ return; } + connect.publish("/dojox/mobile/resizeAll", [evt, root]); + dm.updateOrient(); + dm.detectScreenSize(); + var isTopLevel = function(w){ + var parent = w.getParent && w.getParent(); + return !!((!parent || !parent.resize) && w.resize); + }; + var resizeRecursively = function(w){ + array.forEach(w.getChildren(), function(child){ + if(isTopLevel(child)){ child.resize(); } + resizeRecursively(child); + }); + }; + if(root){ + if(root.resize){ root.resize(); } + resizeRecursively(root); + }else{ + array.forEach(array.filter(registry.toArray(), isTopLevel), + function(w){ w.resize(); }); + } + }; + + dm.openWindow = function(url, target){ + // summary: + // Opens a new browser window with the given url. + win.global.open(url, target || "_blank"); + }; + + dm.createDomButton = function(/*DomNode*/refNode, /*Object?*/style, /*DomNode?*/toNode){ + // summary: + // Creates a DOM button. + // description: + // DOM button is a simple graphical object that consists of one or + // more nested DIV elements with some CSS styling. It can be used + // in place of an icon image on ListItem, IconItem, and so on. + // The kind of DOM button to create is given as a class name of + // refNode. The number of DIVs to create is searched from the style + // sheets in the page. However, if the class name has a suffix that + // starts with an underscore, like mblDomButtonGoldStar_5, then the + // suffixed number is used instead. A class name for DOM button + // must starts with 'mblDomButton'. + // refNode: + // A node that has a DOM button class name. + // style: + // A hash object to set styles to the node. + // toNode: + // A root node to create a DOM button. If omitted, refNode is used. + + if(!dm._domButtons){ + if(has("webkit")){ + var findDomButtons = function(sheet, dic){ + // summary: + // Searches the style sheets for DOM buttons. + // description: + // Returns a key-value pair object whose keys are DOM + // button class names and values are the number of DOM + // elements they need. + var i, j; + if(!sheet){ + var dic = {}; + var ss = dojo.doc.styleSheets; + for (i = 0; i < ss.length; i++){ + ss[i] && findDomButtons(ss[i], dic); + } + return dic; + } + var rules = sheet.cssRules || []; + for (i = 0; i < rules.length; i++){ + var rule = rules[i]; + if(rule.href && rule.styleSheet){ + findDomButtons(rule.styleSheet, dic); + }else if(rule.selectorText){ + var sels = rule.selectorText.split(/,/); + for (j = 0; j < sels.length; j++){ + var sel = sels[j]; + var n = sel.split(/>/).length - 1; + if(sel.match(/(mblDomButton\w+)/)){ + var cls = RegExp.$1; + if(!dic[cls] || n > dic[cls]){ + dic[cls] = n; + } + } + } + } + } + } + dm._domButtons = findDomButtons(); + }else{ + dm._domButtons = {}; + } + } + + var s = refNode.className; + var node = toNode || refNode; + if(s.match(/(mblDomButton\w+)/) && s.indexOf("/") === -1){ + var btnClass = RegExp.$1; + var nDiv = 4; + if(s.match(/(mblDomButton\w+_(\d+))/)){ + nDiv = RegExp.$2 - 0; + }else if(dm._domButtons[btnClass] !== undefined){ + nDiv = dm._domButtons[btnClass]; + } + var props = null; + if(has("bb") && config["mblBBBoxShadowWorkaround"] !== false){ + // Removes box-shadow because BlackBerry incorrectly renders it. + props = {style:"-webkit-box-shadow:none"}; + } + for(var i = 0, p = node; i < nDiv; i++){ + p = p.firstChild || domConstruct.create("DIV", props, p); + } + if(toNode){ + setTimeout(function(){ + domClass.remove(refNode, btnClass); + }, 0); + domClass.add(toNode, btnClass); + } + }else if(s.indexOf(".") !== -1){ // file name + domConstruct.create("IMG", {src:s}, node); + }else{ + return null; + } + domClass.add(node, "mblDomButton"); + if(config["mblAndroidWorkaround"] !== false && has("android") >= 2.2){ + // Android workaround for the issue that domButtons' -webkit-transform styles sometimes invalidated + // by applying -webkit-transform:translated3d(x,y,z) style programmatically to non-ancestor elements, + // which results in breaking domButtons. + domStyle.set(node, "webkitTransform", "translate3d(0,0,0)"); + } + !!style && domStyle.set(node, style); + return node; + }; + + dm.createIcon = function(/*String*/icon, /*String*/iconPos, /*DomNode*/node, /*String?*/title, /*DomNode?*/parent){ + // summary: + // Creates or updates an icon node + // description: + // If node exists, updates the existing node. Otherwise, creates a new one. + // icon: + // Path for an image, or DOM button class name. + if(icon && icon.indexOf("mblDomButton") === 0){ + // DOM button + if(node && node.className.match(/(mblDomButton\w+)/)){ + domClass.remove(node, RegExp.$1); + }else{ + node = domConstruct.create("DIV"); + } + node.title = title; + domClass.add(node, icon); + dm.createDomButton(node); + }else if(icon && icon !== "none"){ + // Image + if(!node || node.nodeName !== "IMG"){ + node = domConstruct.create("IMG", { + alt: title + }); + } + node.src = (icon || "").replace("${theme}", dm.currentTheme); + dm.setupIcon(node, iconPos); + if(parent && iconPos){ + var arr = iconPos.split(/[ ,]/); + domStyle.set(parent, { + width: arr[2] + "px", + height: arr[3] + "px" + }); + } + } + if(parent){ + parent.appendChild(node); + } + return node; + }; + + // flag for iphone flicker workaround + dm._iw = config["mblIosWorkaround"] !== false && has("iphone"); + if(dm._iw){ + dm._iwBgCover = domConstruct.create("div"); // Cover to hide flicker in the background + } + + if(config.parseOnLoad){ + ready(90, function(){ + // avoid use of query + /* + var list = query('[lazy=true] [dojoType]', null); + list.forEach(function(node, index, nodeList){ + node.setAttribute("__dojoType", node.getAttribute("dojoType")); + node.removeAttribute("dojoType"); + }); + */ + + var nodes = win.body().getElementsByTagName("*"); + var i, len, s; + len = nodes.length; + for(i = 0; i < len; i++){ + s = nodes[i].getAttribute("dojoType"); + if(s){ + if(nodes[i].parentNode.getAttribute("lazy") == "true"){ + nodes[i].setAttribute("__dojoType", s); + nodes[i].removeAttribute("dojoType"); + } + } + } + }); + } + + ready(function(){ + dm.detectScreenSize(true); + if(config["mblApplyPageStyles"] !== false){ + domClass.add(win.doc.documentElement, "mobile"); + } + if(has("chrome")){ + // dojox.mobile does not load uacss (only _compat does), but we need dj_chrome. + domClass.add(win.doc.documentElement, "dj_chrome"); + } + + if(config["mblAndroidWorkaround"] !== false && has("android") >= 2.2){ // workaround for android screen flicker problem + if(config["mblAndroidWorkaroundButtonStyle"] !== false){ + // workaround to avoid buttons disappear due to the side-effect of the webkitTransform workaroud below + domConstruct.create("style", {innerHTML:"BUTTON,INPUT[type='button'],INPUT[type='submit'],INPUT[type='reset'],INPUT[type='file']::-webkit-file-upload-button{-webkit-appearance:none;}"}, win.doc.head, "first"); + } + if(has("android") < 3){ // for Android 2.2.x and 2.3.x + domStyle.set(win.doc.documentElement, "webkitTransform", "translate3d(0,0,0)"); + // workaround for auto-scroll issue when focusing input fields + connect.connect(null, "onfocus", null, function(e){ + domStyle.set(win.doc.documentElement, "webkitTransform", ""); + }); + connect.connect(null, "onblur", null, function(e){ + domStyle.set(win.doc.documentElement, "webkitTransform", "translate3d(0,0,0)"); + }); + }else{ // for Android 3.x + if(config["mblAndroid3Workaround"] !== false){ + domStyle.set(win.doc.documentElement, { + webkitBackfaceVisibility: "hidden", + webkitPerspective: 8000 + }); + } + } + } + + // You can disable hiding the address bar with the following djConfig. + // var djConfig = { mblHideAddressBar: false }; + var f = dm.resizeAll; + if(config["mblHideAddressBar"] !== false && + navigator.appVersion.indexOf("Mobile") != -1 || + config["mblForceHideAddressBar"] === true){ + dm.hideAddressBar(); + if(config["mblAlwaysHideAddressBar"] === true){ + f = dm.hideAddressBar; + } + } + connect.connect(null, (win.global.onorientationchange !== undefined && !has("android")) + ? "onorientationchange" : "onresize", null, f); + + // avoid use of query + /* + var list = query('[__dojoType]', null); + list.forEach(function(node, index, nodeList){ + node.setAttribute("dojoType", node.getAttribute("__dojoType")); + node.removeAttribute("__dojoType"); + }); + */ + + var nodes = win.body().getElementsByTagName("*"); + var i, len = nodes.length, s; + for(i = 0; i < len; i++){ + s = nodes[i].getAttribute("__dojoType"); + if(s){ + nodes[i].setAttribute("dojoType", s); + nodes[i].removeAttribute("__dojoType"); + } + } + + if(dojo.hash){ + // find widgets under root recursively + var findWidgets = function(root){ + if(!root){ return []; } + var arr = registry.findWidgets(root); + var widgets = arr; + for(var i = 0; i < widgets.length; i++){ + arr = arr.concat(findWidgets(widgets[i].containerNode)); + } + return arr; + }; + connect.subscribe("/dojo/hashchange", null, function(value){ + var view = dm.currentView; + if(!view){ return; } + var params = dm._params; + if(!params){ // browser back/forward button was pressed + var moveTo = value ? value : dm._defaultView.id; + var widgets = findWidgets(view.domNode); + var dir = 1, transition = "slide"; + for(i = 0; i < widgets.length; i++){ + var w = widgets[i]; + if("#"+moveTo == w.moveTo){ + // found a widget that has the given moveTo + transition = w.transition; + dir = (w instanceof dm.Heading) ? -1 : 1; + break; + } + } + params = [ moveTo, dir, transition ]; + } + view.performTransition.apply(view, params); + dm._params = null; + }); + } + + win.body().style.visibility = "visible"; + }); + + // To search _parentNode first. TODO:1.8 reconsider this redefinition. + registry.getEnclosingWidget = function(node){ + while(node){ + var id = node.getAttribute && node.getAttribute("widgetId"); + if(id){ + return registry.byId(id); + } + node = node._parentNode || node.parentNode; + } + return null; + }; + + return dm; +}); + +}, +'dojox/mobile/uacss':function(){ +define("dojox/mobile/uacss", [ + "dojo/_base/kernel", + "dojo/_base/lang", + "dojo/_base/window", + "dojox/mobile/sniff" +], function(dojo, lang, win, has){ + win.doc.documentElement.className += lang.trim([ + has("bb") ? "dj_bb" : "", + has("android") ? "dj_android" : "", + has("iphone") ? "dj_iphone" : "", + has("ipod") ? "dj_ipod" : "", + has("ipad") ? "dj_ipad" : "" + ].join(" ").replace(/ +/g," ")); + return dojo; +}); + +}, +'dojox/mobile/RoundRectCategory':function(){ +define([ + "dojo/_base/declare", + "dojo/_base/window", + "dijit/_Contained", + "dijit/_WidgetBase" +], function(declare, win, Contained, WidgetBase){ + +/*===== + var Contained = dijit._Contained; + var WidgetBase = dijit._WidgetBase; +=====*/ + + // module: + // dojox/mobile/RoundRectCategory + // summary: + // A category header for a rounded rectangle list. + + return declare("dojox.mobile.RoundRectCategory", [WidgetBase, Contained],{ + // summary: + // A category header for a rounded rectangle list. + + // label: String + // A label text for the widget. + label: "", + + buildRendering: function(){ + this.domNode = this.containerNode = this.srcNodeRef || win.doc.createElement("H2"); + this.domNode.className = "mblRoundRectCategory"; + if(!this.label){ + this.label = this.domNode.innerHTML; + } + }, + + _setLabelAttr: function(/*String*/label){ + this.label = label; + this.domNode.innerHTML = this._cv ? this._cv(label) : label; + } + }); + +}); + +}, +'dojox/mobile/ProgressIndicator':function(){ +define([ + "dojo/_base/config", + "dojo/_base/declare", + "dojo/dom-construct", + "dojo/dom-style", + "dojo/has" +], function(config, declare, domConstruct, domStyle, has){ + + // module: + // dojox/mobile/ProgressIndicator + // summary: + // A progress indication widget. + + var cls = declare("dojox.mobile.ProgressIndicator", null, { + // summary: + // A progress indication widget. + // description: + // ProgressIndicator is a round spinning graphical representation + // that indicates the current task is on-going. + + // interval: Number + // The time interval in milliseconds for updating the spinning + // indicator. + interval: 100, + + // colors: Array + // An array of indicator colors. + colors: [ + "#C0C0C0", "#C0C0C0", "#C0C0C0", "#C0C0C0", + "#C0C0C0", "#C0C0C0", "#B8B9B8", "#AEAFAE", + "#A4A5A4", "#9A9A9A", "#8E8E8E", "#838383" + ], + + constructor: function(){ + this._bars = []; + this.domNode = domConstruct.create("DIV"); + this.domNode.className = "mblProgContainer"; + if(config["mblAndroidWorkaround"] !== false && has("android") >= 2.2 && has("android") < 3){ + // workaround to avoid the side effects of the fixes for android screen flicker problem + domStyle.set(this.domNode, "webkitTransform", "translate3d(0,0,0)"); + } + this.spinnerNode = domConstruct.create("DIV", null, this.domNode); + for(var i = 0; i < this.colors.length; i++){ + var div = domConstruct.create("DIV", {className:"mblProg mblProg"+i}, this.spinnerNode); + this._bars.push(div); + } + }, + + start: function(){ + // summary: + // Starts the ProgressIndicator spinning. + if(this.imageNode){ + var img = this.imageNode; + var l = Math.round((this.domNode.offsetWidth - img.offsetWidth) / 2); + var t = Math.round((this.domNode.offsetHeight - img.offsetHeight) / 2); + img.style.margin = t+"px "+l+"px"; + return; + } + var cntr = 0; + var _this = this; + var n = this.colors.length; + this.timer = setInterval(function(){ + cntr--; + cntr = cntr < 0 ? n - 1 : cntr; + var c = _this.colors; + for(var i = 0; i < n; i++){ + var idx = (cntr + i) % n; + _this._bars[i].style.backgroundColor = c[idx]; + } + }, this.interval); + }, + + stop: function(){ + // summary: + // Stops the ProgressIndicator spinning. + if(this.timer){ + clearInterval(this.timer); + } + this.timer = null; + if(this.domNode.parentNode){ + this.domNode.parentNode.removeChild(this.domNode); + } + }, + + setImage: function(/*String*/file){ + // summary: + // Sets an indicator icon image file (typically animated GIF). + // If null is specified, restores the default spinner. + if(file){ + this.imageNode = domConstruct.create("IMG", {src:file}, this.domNode); + this.spinnerNode.style.display = "none"; + }else{ + if(this.imageNode){ + this.domNode.removeChild(this.imageNode); + this.imageNode = null; + } + this.spinnerNode.style.display = ""; + } + } + }); + + cls._instance = null; + cls.getInstance = function(){ + if(!cls._instance){ + cls._instance = new cls(); + } + return cls._instance; + }; + + return cls; +}); + +}, +'dojox/mobile/EdgeToEdgeList':function(){ +define([ + "dojo/_base/declare", + "./RoundRectList" +], function(declare, RoundRectList){ + +/*===== + var RoundRectList = dojox.mobile.RoundRectList; +=====*/ + + // module: + // dojox/mobile/EdgeToEdgeCategory + // summary: + // An edge-to-edge layout list. + + return declare("dojox.mobile.EdgeToEdgeList", RoundRectList, { + // summary: + // An edge-to-edge layout list. + // description: + // EdgeToEdgeList is an edge-to-edge layout list, which displays + // all items in equally sized rows. Each item must be + // dojox.mobile.ListItem. + + buildRendering: function(){ + this.inherited(arguments); + this.domNode.className = "mblEdgeToEdgeList"; + } + }); +}); + +}, +'dojox/mobile/EdgeToEdgeCategory':function(){ +define([ + "dojo/_base/declare", + "./RoundRectCategory" +], function(declare, RoundRectCategory){ + +/*===== + var RoundRectCategory = dojox.mobile.RoundRectCategory; +=====*/ + + // module: + // dojox/mobile/EdgeToEdgeCategory + // summary: + // A category header for an edge-to-edge list. + + return declare("dojox.mobile.EdgeToEdgeCategory", RoundRectCategory, { + // summary: + // A category header for an edge-to-edge list. + buildRendering: function(){ + this.inherited(arguments); + this.domNode.className = "mblEdgeToEdgeCategory"; + } + }); +}); + +}, +'dojox/mobile/ToolBarButton':function(){ +define([ + "dojo/_base/declare", + "dojo/_base/window", + "dojo/dom-class", + "dojo/dom-construct", + "dojo/dom-style", + "./common", + "./_ItemBase" +], function(declare, win, domClass, domConstruct, domStyle, common, ItemBase){ +/*===== + var ItemBase = dojox.mobile._ItemBase; +=====*/ + + // module: + // dojox/mobile/ToolBarButton + // summary: + // A button widget that is placed in the Heading widget. + + return declare("dojox.mobile.ToolBarButton", ItemBase, { + // summary: + // A button widget that is placed in the Heading widget. + // description: + // ToolBarButton is a button that is placed in the Heading + // widget. It is a subclass of dojox.mobile._ItemBase just like + // ListItem or IconItem. So, unlike Button, it has basically the + // same capability as ListItem or IconItem, such as icon support, + // transition, etc. + + // selected: Boolean + // If true, the button is in the selected status. + selected: false, + + // btnClass: String + // Deprecated. + btnClass: "", + + /* internal properties */ + _defaultColor: "mblColorDefault", + _selColor: "mblColorDefaultSel", + + buildRendering: function(){ + this.domNode = this.containerNode = this.srcNodeRef || win.doc.createElement("div"); + this.inheritParams(); + domClass.add(this.domNode, "mblToolBarButton mblArrowButtonText"); + var color; + if(this.selected){ + color = this._selColor; + }else if(this.domNode.className.indexOf("mblColor") == -1){ + color = this._defaultColor; + } + domClass.add(this.domNode, color); + + if(!this.label){ + this.label = this.domNode.innerHTML; + } + + if(this.icon && this.icon != "none"){ + this.iconNode = domConstruct.create("div", {className:"mblToolBarButtonIcon"}, this.domNode); + common.createIcon(this.icon, this.iconPos, null, this.alt, this.iconNode); + if(this.iconPos){ + domClass.add(this.iconNode.firstChild, "mblToolBarButtonSpriteIcon"); + } + }else{ + if(common.createDomButton(this.domNode)){ + domClass.add(this.domNode, "mblToolBarButtonDomButton"); + }else{ + domClass.add(this.domNode, "mblToolBarButtonText"); + } + } + this.connect(this.domNode, "onclick", "onClick"); + }, + + select: function(){ + // summary: + // Makes this widget in the selected state. + domClass.toggle(this.domNode, this._selColor, !arguments[0]); + this.selected = !arguments[0]; + }, + + deselect: function(){ + // summary: + // Makes this widget in the deselected state. + this.select(true); + }, + + onClick: function(e){ + this.setTransitionPos(e); + this.defaultClickAction(); + }, + + _setBtnClassAttr: function(/*String*/btnClass){ + var node = this.domNode; + if(node.className.match(/(mblDomButton\w+)/)){ + domClass.remove(node, RegExp.$1); + } + domClass.add(node, btnClass); + if(common.createDomButton(this.domNode)){ + domClass.add(this.domNode, "mblToolBarButtonDomButton"); + } + }, + + _setLabelAttr: function(/*String*/text){ + this.label = text; + this.domNode.innerHTML = this._cv ? this._cv(text) : text; + } + }); +}); + +}, +'dojox/mobile/_ItemBase':function(){ +define("dojox/mobile/_ItemBase", [ + "dojo/_base/kernel", + "dojo/_base/config", + "dojo/_base/declare", + "dijit/registry", // registry.getEnclosingWidget + "dijit/_Contained", + "dijit/_Container", + "dijit/_WidgetBase", + "./TransitionEvent", + "./View" +], function(kernel, config, declare, registry, Contained, Container, WidgetBase, TransitionEvent, View){ + +/*===== + var Contained = dijit._Contained; + var Container = dijit._Container; + var WidgetBase = dijit._WidgetBase; + var TransitionEvent = dojox.mobile.TransitionEvent; + var View = dojox.mobile.View; +=====*/ + + // module: + // dojox/mobile/_ItemBase + // summary: + // A base class for item classes (e.g. ListItem, IconItem, etc.) + + return declare("dojox.mobile._ItemBase", [WidgetBase, Container, Contained],{ + // summary: + // A base class for item classes (e.g. ListItem, IconItem, etc.) + // description: + // _ItemBase is a base class for widgets that have capability to + // make a view transition when clicked. + + // icon: String + // An icon image to display. The value can be either a path for an + // image file or a class name of a DOM button. If icon is not + // specified, the iconBase parameter of the parent widget is used. + icon: "", + + // iconPos: String + // The position of an aggregated icon. IconPos is comma separated + // values like top,left,width,height (ex. "0,0,29,29"). If iconPos + // is not specified, the iconPos parameter of the parent widget is + // used. + iconPos: "", // top,left,width,height (ex. "0,0,29,29") + + // alt: String + // An alt text for the icon image. + alt: "", + + // href: String + // A URL of another web page to go to. + href: "", + + // hrefTarget: String + // A target that specifies where to open a page specified by + // href. The value will be passed to the 2nd argument of + // window.open(). + hrefTarget: "", + + // moveTo: String + // The id of the transition destination view which resides in the + // current page. + // + // If the value has a hash sign ('#') before the id (e.g. #view1) + // and the dojo.hash module is loaded by the user application, the + // view transition updates the hash in the browser URL so that the + // user can bookmark the destination view. In this case, the user + // can also use the browser's back/forward button to navigate + // through the views in the browser history. + // + // If null, transitions to a blank view. + // If '#', returns immediately without transition. + moveTo: "", + + // scene: String + // The name of a scene. Used from dojox.mobile.app. + scene: "", + + // clickable: Boolean + // If true, this item becomes clickable even if a transition + // destination (moveTo, etc.) is not specified. + clickable: false, + + // url: String + // A URL of an html fragment page or JSON data that represents a + // new view content. The view content is loaded with XHR and + // inserted in the current page. Then a view transition occurs to + // the newly created view. The view is cached so that subsequent + // requests would not load the content again. + url: "", + + // urlTarget: String + // Node id under which a new view will be created according to the + // url parameter. If not specified, The new view will be created as + // a sibling of the current view. + urlTarget: "", + + // transition: String + // A type of animated transition effect. You can choose from the + // standard transition types, "slide", "fade", "flip", or from the + // extended transition types, "cover", "coverv", "dissolve", + // "reveal", "revealv", "scaleIn", "scaleOut", "slidev", + // "swirl", "zoomIn", "zoomOut". If "none" is specified, transition + // occurs immediately without animation. + transition: "", + + // transitionDir: Number + // The transition direction. If 1, transition forward. If -1, + // transition backward. For example, the slide transition slides + // the view from right to left when dir == 1, and from left to + // right when dir == -1. + transitionDir: 1, + + // transitionOptions: Object + // A hash object that holds transition options. + transitionOptions: null, + + // callback: Function|String + // A callback function that is called when the transition has been + // finished. A function reference, or name of a function in + // context. + callback: null, + + // sync: Boolean + // If true, XHR for the view content specified with the url + // parameter is performed synchronously. If false, it is done + // asynchronously and the progress indicator is displayed while + // loading the content. This parameter is effective only when the + // url parameter is used. + sync: true, + + // label: String + // A label of the item. If the label is not specified, innerHTML is + // used as a label. + label: "", + + // toggle: Boolean + // If true, the item acts like a toggle button. + toggle: false, + + // _duration: Number + // Duration of selection, milliseconds. + _duration: 800, + + + inheritParams: function(){ + var parent = this.getParent(); + if(parent){ + if(!this.transition){ this.transition = parent.transition; } + if(this.icon && parent.iconBase && + parent.iconBase.charAt(parent.iconBase.length - 1) === '/'){ + this.icon = parent.iconBase + this.icon; + } + if(!this.icon){ this.icon = parent.iconBase; } + if(!this.iconPos){ this.iconPos = parent.iconPos; } + } + }, + + select: function(){ + // summary: + // Makes this widget in the selected state. + // description: + // Subclass must implement. + }, + + deselect: function(){ + // summary: + // Makes this widget in the deselected state. + // description: + // Subclass must implement. + }, + + defaultClickAction: function(e){ + if(this.toggle){ + if(this.selected){ + this.deselect(); + }else{ + this.select(); + } + }else if(!this.selected){ + this.select(); + if(!this.selectOne){ + var _this = this; + setTimeout(function(){ + _this.deselect(); + }, this._duration); + } + var transOpts; + if(this.moveTo || this.href || this.url || this.scene){ + transOpts = {moveTo: this.moveTo, href: this.href, url: this.url, scene: this.scene, transition: this.transition, transitionDir: this.transitionDir}; + }else if(this.transitionOptions){ + transOpts = this.transitionOptions; + } + if(transOpts){ + return new TransitionEvent(this.domNode,transOpts,e).dispatch(); + } + } + }, + + getParent: function(){ + // summary: + // Gets the parent widget. + // description: + // Almost equivalent to _Contained#getParent, but this method + // does not cause a script error even if this widget has no + // parent yet. + var ref = this.srcNodeRef || this.domNode; + return ref && ref.parentNode ? registry.getEnclosingWidget(ref.parentNode) : null; + }, + + setTransitionPos: function(e){ + // summary: + // Stores the clicked position for later use. + // description: + // Some of the transition animations (e.g. ScaleIn) needs the + // clicked position. + var w = this; + while(true){ + w = w.getParent(); + if(!w || w instanceof View){ break; } + } + if(w){ + w.clickedPosX = e.clientX; + w.clickedPosY = e.clientY; + } + }, + + transitionTo: function(moveTo, href, url, scene){ + // summary: + // Performs a view transition. + // description: + // Given a transition destination, this method performs a view + // transition. This method is typically called when this item + // is clicked. + 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 + "::transitionTo() is deprecated." + + caller, "", "2.0"); + alreadyCalledHash[caller] = true; + } + } + new TransitionEvent(this.domNode, {moveTo: moveTo, href: href, url: url, scene: scene, + transition: this.transition, transitionDir: this.transitionDir}).dispatch(); + } + }); +}); + +}, +'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 + } + }); +}); + +}, +'dojox/mobile/_base':function(){ +define([ + "./common", + "./View", + "./Heading", + "./RoundRect", + "./RoundRectCategory", + "./EdgeToEdgeCategory", + "./RoundRectList", + "./EdgeToEdgeList", + "./ListItem", + "./Switch", + "./ToolBarButton", + "./ProgressIndicator" +], function(common, View, Heading, RoundRect, RoundRectCategory, EdgeToEdgeCategory, RoundRectList, EdgeToEdgeList, ListItem, Switch, ToolBarButton, ProgressIndicator){ + // module: + // dojox/mobile/_base + // summary: + // Includes the basic dojox.mobile modules + + return common; +}); + +}, +'dijit/main':function(){ +define("dijit/main", [ + "dojo/_base/kernel" +], function(dojo){ + // module: + // dijit + // summary: + // The dijit package main module + + return dojo.dijit; +}); + +}, +'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 + } + }); +}); + +}}}); + +require(["dojo/i18n"], function(i18n){ +i18n._preloadLocalizations("dojox/nls/mobile", []); +}); +define("dojox/mobile", [ + ".", + "dojo/_base/lang", + "dojox/mobile/_base" +], function(dojox, lang, base){ + lang.getObject("mobile", true, dojox); + return dojox.mobile; +}); |
