/* 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 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
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: // // |
// | here's a plain DOM node // | and a widget // | and another plain DOM node // |
// // containerNode would point to: // // | here's a plain DOM node // | and a widget // | and another plain DOM node // // 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 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 = '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
'; 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 // 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 // - '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; });