summaryrefslogtreecommitdiff
path: root/js/dojo-1.6/dojox/mobile/app
diff options
context:
space:
mode:
Diffstat (limited to 'js/dojo-1.6/dojox/mobile/app')
-rw-r--r--js/dojo-1.6/dojox/mobile/app/AlertDialog.js193
-rw-r--r--js/dojo-1.6/dojox/mobile/app/AlertDialog.xd.js198
-rw-r--r--js/dojo-1.6/dojox/mobile/app/ImageThumbView.js400
-rw-r--r--js/dojo-1.6/dojox/mobile/app/ImageThumbView.xd.js406
-rw-r--r--js/dojo-1.6/dojox/mobile/app/ImageView.js727
-rw-r--r--js/dojo-1.6/dojox/mobile/app/ImageView.xd.js733
-rw-r--r--js/dojo-1.6/dojox/mobile/app/List.js656
-rw-r--r--js/dojo-1.6/dojox/mobile/app/List.xd.js662
-rw-r--r--js/dojo-1.6/dojox/mobile/app/ListSelector.js229
-rw-r--r--js/dojo-1.6/dojox/mobile/app/ListSelector.xd.js235
-rw-r--r--js/dojo-1.6/dojox/mobile/app/SceneAssistant.js67
-rw-r--r--js/dojo-1.6/dojox/mobile/app/SceneAssistant.xd.js71
-rw-r--r--js/dojo-1.6/dojox/mobile/app/SceneController.js181
-rw-r--r--js/dojo-1.6/dojox/mobile/app/SceneController.xd.js186
-rw-r--r--js/dojo-1.6/dojox/mobile/app/StageController.js143
-rw-r--r--js/dojo-1.6/dojox/mobile/app/StageController.xd.js148
-rw-r--r--js/dojo-1.6/dojox/mobile/app/TextBox.js330
-rw-r--r--js/dojo-1.6/dojox/mobile/app/TextBox.xd.js336
-rw-r--r--js/dojo-1.6/dojox/mobile/app/_FormWidget.js298
-rw-r--r--js/dojo-1.6/dojox/mobile/app/_FormWidget.xd.js304
-rw-r--r--js/dojo-1.6/dojox/mobile/app/_Widget.js41
-rw-r--r--js/dojo-1.6/dojox/mobile/app/_Widget.xd.js46
-rw-r--r--js/dojo-1.6/dojox/mobile/app/_base.js248
-rw-r--r--js/dojo-1.6/dojox/mobile/app/_base.xd.js267
-rw-r--r--js/dojo-1.6/dojox/mobile/app/_event.js131
-rw-r--r--js/dojo-1.6/dojox/mobile/app/_event.xd.js135
-rw-r--r--js/dojo-1.6/dojox/mobile/app/compat.js14
-rw-r--r--js/dojo-1.6/dojox/mobile/app/compat.js.uncompressed.js1700
-rw-r--r--js/dojo-1.6/dojox/mobile/app/compat.xd.js14
-rw-r--r--js/dojo-1.6/dojox/mobile/app/compat.xd.js.uncompressed.js1710
30 files changed, 10809 insertions, 0 deletions
diff --git a/js/dojo-1.6/dojox/mobile/app/AlertDialog.js b/js/dojo-1.6/dojox/mobile/app/AlertDialog.js
new file mode 100644
index 0000000..c1516cc
--- /dev/null
+++ b/js/dojo-1.6/dojox/mobile/app/AlertDialog.js
@@ -0,0 +1,193 @@
+/*
+ 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
+*/
+
+
+if(!dojo._hasResource["dojox.mobile.app.AlertDialog"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.mobile.app.AlertDialog"] = true;
+dojo.provide("dojox.mobile.app.AlertDialog");
+dojo.experimental("dojox.mobile.app.AlertDialog");
+dojo.require("dijit._WidgetBase");
+
+dojo.declare("dojox.mobile.app.AlertDialog", dijit._WidgetBase, {
+
+ // title: String
+ // The title of the AlertDialog
+ title: "",
+
+ // text: String
+ // The text message displayed in the AlertDialog
+ text: "",
+
+ // controller: Object
+ // The SceneController for the currently active scene
+ controller: null,
+
+ // buttons: Array
+ buttons: null,
+
+ defaultButtonLabel: "OK",
+
+ // onChoose: Function
+ // The callback function that is invoked when a button is tapped.
+ // If the dialog is cancelled, no parameter is passed to this function.
+ onChoose: null,
+
+ constructor: function(){
+ this.onClick = dojo.hitch(this, this.onClick);
+ this._handleSelect = dojo.hitch(this, this._handleSelect);
+ },
+
+ buildRendering: function(){
+ this.domNode = dojo.create("div",{
+ "class": "alertDialog"
+ });
+
+ // Create the outer dialog body
+ var dlgBody = dojo.create("div", {"class": "alertDialogBody"}, this.domNode);
+
+ // Create the title
+ dojo.create("div", {"class": "alertTitle", innerHTML: this.title || ""}, dlgBody);
+
+ // Create the text
+ dojo.create("div", {"class": "alertText", innerHTML: this.text || ""}, dlgBody);
+
+ // Create the node that encapsulates all the buttons
+ var btnContainer = dojo.create("div", {"class": "alertBtns"}, dlgBody);
+
+ // If no buttons have been defined, default to a single button saying OK
+ if(!this.buttons || this.buttons.length == 0){
+ this.buttons = [{
+ label: this.defaultButtonLabel,
+ value: "ok",
+ "class": "affirmative"
+ }];
+ }
+
+ var _this = this;
+
+ // Create each of the buttons
+ dojo.forEach(this.buttons, function(btnInfo){
+ var btn = new dojox.mobile.Button({
+ btnClass: btnInfo["class"] || "",
+ label: btnInfo.label
+ });
+ btn._dialogValue = btnInfo.value;
+ dojo.place(btn.domNode, btnContainer);
+ _this.connect(btn, "onClick", _this._handleSelect);
+ });
+
+ var viewportSize = this.controller.getWindowSize();
+
+ // Create the mask that blocks out the rest of the screen
+ this.mask = dojo.create("div", {"class": "dialogUnderlayWrapper",
+ innerHTML: "<div class=\"dialogUnderlay\"></div>",
+ style: {
+ width: viewportSize.w + "px",
+ height: viewportSize.h + "px"
+ }
+ }, this.controller.assistant.domNode);
+
+ this.connect(this.mask, "onclick", function(){
+ _this.onChoose && _this.onChoose();
+ _this.hide();
+ });
+ },
+
+ postCreate: function(){
+ this.subscribe("/dojox/mobile/app/goback", this._handleSelect);
+ },
+
+ _handleSelect: function(event){
+ // summary:
+ // Handle the selection of a value
+ var node;
+ console.log("handleSelect");
+ if(event && event.target){
+ node = event.target;
+
+ // Find the widget that was tapped.
+ while(!dijit.byNode(node)){
+ node - node.parentNode;
+ }
+ }
+
+ // If an onChoose function was provided, tell it what button
+ // value was chosen
+ if(this.onChoose){
+ this.onChoose(node ? dijit.byNode(node)._dialogValue: undefined);
+ }
+ // Hide the dialog
+ this.hide();
+ },
+
+ show: function(){
+ // summary:
+ // Show the dialog
+ this._doTransition(1);
+ },
+
+ hide: function(){
+ // summary:
+ // Hide the dialog
+ this._doTransition(-1);
+ },
+
+ _doTransition: function(dir){
+ // summary:
+ // Either shows or hides the dialog.
+ // dir:
+ // An integer. If positive, the dialog is shown. If negative,
+ // the dialog is hidden.
+
+ // TODO: replace this with CSS transitions
+
+ var anim;
+ var h = dojo.marginBox(this.domNode.firstChild).h;
+
+
+ var bodyHeight = this.controller.getWindowSize().h;
+ console.log("dialog height = " + h, " body height = " + bodyHeight);
+
+ var high = bodyHeight - h;
+ var low = bodyHeight;
+
+ var anim1 = dojo.fx.slideTo({
+ node: this.domNode,
+ duration: 400,
+ top: {start: dir < 0 ? high : low, end: dir < 0 ? low: high}
+ });
+
+ var anim2 = dojo[dir < 0 ? "fadeOut" : "fadeIn"]({
+ node: this.mask,
+ duration: 400
+ });
+
+ var anim = dojo.fx.combine([anim1, anim2]);
+
+ var _this = this;
+
+ dojo.connect(anim, "onEnd", this, function(){
+ if(dir < 0){
+ _this.domNode.style.display = "none";
+ dojo.destroy(_this.domNode);
+ dojo.destroy(_this.mask);
+ }
+ });
+ anim.play();
+ },
+
+ destroy: function(){
+ this.inherited(arguments);
+ dojo.destroy(this.mask);
+ },
+
+
+ onClick: function(){
+
+ }
+});
+
+}
diff --git a/js/dojo-1.6/dojox/mobile/app/AlertDialog.xd.js b/js/dojo-1.6/dojox/mobile/app/AlertDialog.xd.js
new file mode 100644
index 0000000..4cf183f
--- /dev/null
+++ b/js/dojo-1.6/dojox/mobile/app/AlertDialog.xd.js
@@ -0,0 +1,198 @@
+/*
+ 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
+*/
+
+
+dojo._xdResourceLoaded(function(dojo, dijit, dojox){
+return {depends: [["provide", "dojox.mobile.app.AlertDialog"],
+["require", "dijit._WidgetBase"]],
+defineResource: function(dojo, dijit, dojox){if(!dojo._hasResource["dojox.mobile.app.AlertDialog"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.mobile.app.AlertDialog"] = true;
+dojo.provide("dojox.mobile.app.AlertDialog");
+dojo.experimental("dojox.mobile.app.AlertDialog");
+dojo.require("dijit._WidgetBase");
+
+dojo.declare("dojox.mobile.app.AlertDialog", dijit._WidgetBase, {
+
+ // title: String
+ // The title of the AlertDialog
+ title: "",
+
+ // text: String
+ // The text message displayed in the AlertDialog
+ text: "",
+
+ // controller: Object
+ // The SceneController for the currently active scene
+ controller: null,
+
+ // buttons: Array
+ buttons: null,
+
+ defaultButtonLabel: "OK",
+
+ // onChoose: Function
+ // The callback function that is invoked when a button is tapped.
+ // If the dialog is cancelled, no parameter is passed to this function.
+ onChoose: null,
+
+ constructor: function(){
+ this.onClick = dojo.hitch(this, this.onClick);
+ this._handleSelect = dojo.hitch(this, this._handleSelect);
+ },
+
+ buildRendering: function(){
+ this.domNode = dojo.create("div",{
+ "class": "alertDialog"
+ });
+
+ // Create the outer dialog body
+ var dlgBody = dojo.create("div", {"class": "alertDialogBody"}, this.domNode);
+
+ // Create the title
+ dojo.create("div", {"class": "alertTitle", innerHTML: this.title || ""}, dlgBody);
+
+ // Create the text
+ dojo.create("div", {"class": "alertText", innerHTML: this.text || ""}, dlgBody);
+
+ // Create the node that encapsulates all the buttons
+ var btnContainer = dojo.create("div", {"class": "alertBtns"}, dlgBody);
+
+ // If no buttons have been defined, default to a single button saying OK
+ if(!this.buttons || this.buttons.length == 0){
+ this.buttons = [{
+ label: this.defaultButtonLabel,
+ value: "ok",
+ "class": "affirmative"
+ }];
+ }
+
+ var _this = this;
+
+ // Create each of the buttons
+ dojo.forEach(this.buttons, function(btnInfo){
+ var btn = new dojox.mobile.Button({
+ btnClass: btnInfo["class"] || "",
+ label: btnInfo.label
+ });
+ btn._dialogValue = btnInfo.value;
+ dojo.place(btn.domNode, btnContainer);
+ _this.connect(btn, "onClick", _this._handleSelect);
+ });
+
+ var viewportSize = this.controller.getWindowSize();
+
+ // Create the mask that blocks out the rest of the screen
+ this.mask = dojo.create("div", {"class": "dialogUnderlayWrapper",
+ innerHTML: "<div class=\"dialogUnderlay\"></div>",
+ style: {
+ width: viewportSize.w + "px",
+ height: viewportSize.h + "px"
+ }
+ }, this.controller.assistant.domNode);
+
+ this.connect(this.mask, "onclick", function(){
+ _this.onChoose && _this.onChoose();
+ _this.hide();
+ });
+ },
+
+ postCreate: function(){
+ this.subscribe("/dojox/mobile/app/goback", this._handleSelect);
+ },
+
+ _handleSelect: function(event){
+ // summary:
+ // Handle the selection of a value
+ var node;
+ console.log("handleSelect");
+ if(event && event.target){
+ node = event.target;
+
+ // Find the widget that was tapped.
+ while(!dijit.byNode(node)){
+ node - node.parentNode;
+ }
+ }
+
+ // If an onChoose function was provided, tell it what button
+ // value was chosen
+ if(this.onChoose){
+ this.onChoose(node ? dijit.byNode(node)._dialogValue: undefined);
+ }
+ // Hide the dialog
+ this.hide();
+ },
+
+ show: function(){
+ // summary:
+ // Show the dialog
+ this._doTransition(1);
+ },
+
+ hide: function(){
+ // summary:
+ // Hide the dialog
+ this._doTransition(-1);
+ },
+
+ _doTransition: function(dir){
+ // summary:
+ // Either shows or hides the dialog.
+ // dir:
+ // An integer. If positive, the dialog is shown. If negative,
+ // the dialog is hidden.
+
+ // TODO: replace this with CSS transitions
+
+ var anim;
+ var h = dojo.marginBox(this.domNode.firstChild).h;
+
+
+ var bodyHeight = this.controller.getWindowSize().h;
+ console.log("dialog height = " + h, " body height = " + bodyHeight);
+
+ var high = bodyHeight - h;
+ var low = bodyHeight;
+
+ var anim1 = dojo.fx.slideTo({
+ node: this.domNode,
+ duration: 400,
+ top: {start: dir < 0 ? high : low, end: dir < 0 ? low: high}
+ });
+
+ var anim2 = dojo[dir < 0 ? "fadeOut" : "fadeIn"]({
+ node: this.mask,
+ duration: 400
+ });
+
+ var anim = dojo.fx.combine([anim1, anim2]);
+
+ var _this = this;
+
+ dojo.connect(anim, "onEnd", this, function(){
+ if(dir < 0){
+ _this.domNode.style.display = "none";
+ dojo.destroy(_this.domNode);
+ dojo.destroy(_this.mask);
+ }
+ });
+ anim.play();
+ },
+
+ destroy: function(){
+ this.inherited(arguments);
+ dojo.destroy(this.mask);
+ },
+
+
+ onClick: function(){
+
+ }
+});
+
+}
+
+}};});
diff --git a/js/dojo-1.6/dojox/mobile/app/ImageThumbView.js b/js/dojo-1.6/dojox/mobile/app/ImageThumbView.js
new file mode 100644
index 0000000..c80d2b5
--- /dev/null
+++ b/js/dojo-1.6/dojox/mobile/app/ImageThumbView.js
@@ -0,0 +1,400 @@
+/*
+ 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
+*/
+
+
+if(!dojo._hasResource["dojox.mobile.app.ImageThumbView"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.mobile.app.ImageThumbView"] = true;
+dojo.provide("dojox.mobile.app.ImageThumbView");
+dojo.experimental("dojox.mobile.app.ImageThumbView");
+
+dojo.require("dijit._WidgetBase");
+dojo.require("dojo.string");
+
+dojo.declare("dojox.mobile.app.ImageThumbView", dijit._WidgetBase, {
+ // summary:
+ // An image thumbnail gallery
+
+ // items: Array
+ // The data items from which the image urls are retrieved.
+ // If an item is a string, it is expected to be a URL. Otherwise
+ // by default it is expected to have a 'url' member. This can
+ // be configured using the 'urlParam' attribute on this widget.
+ items: [],
+
+ // urlParam: String
+ // The paramter name used to retrieve an image url from a JSON object
+ urlParam: "url",
+
+ labelParam: null,
+
+ itemTemplate: '<div class="mblThumbInner">' +
+ '<div class="mblThumbOverlay"></div>' +
+ '<div class="mblThumbMask">' +
+ '<div class="mblThumbSrc" style="background-image:url(${url})"></div>' +
+ '</div>' +
+ '</div>',
+
+ minPadding: 4,
+
+ maxPerRow: 3,
+
+ maxRows: -1,
+
+ baseClass: "mblImageThumbView",
+
+ thumbSize: "medium",
+
+ animationEnabled: true,
+
+ selectedIndex: -1,
+
+ cache: null,
+
+ cacheMustMatch: false,
+
+ clickEvent: "onclick",
+
+ cacheBust: false,
+
+ disableHide: false,
+
+ constructor: function(params, node){
+ },
+
+ postCreate: function(){
+
+ this.inherited(arguments);
+ var _this = this;
+
+ var hoverCls = "mblThumbHover";
+
+ this.addThumb = dojo.hitch(this, this.addThumb);
+ this.handleImgLoad = dojo.hitch(this, this.handleImgLoad);
+ this.hideCached = dojo.hitch(this, this.hideCached);
+
+ this._onLoadImages = {};
+
+ this.cache = [];
+ this.visibleImages = [];
+
+ this._cacheCounter = 0;
+
+ this.connect(this.domNode, this.clickEvent, function(event){
+ var itemNode = _this._getItemNodeFromEvent(event);
+
+ if(itemNode && !itemNode._cached){
+ _this.onSelect(itemNode._item, itemNode._index, _this.items);
+ dojo.query(".selected", this.domNode).removeClass("selected");
+ dojo.addClass(itemNode, "selected");
+ }
+ });
+
+ dojo.addClass(this.domNode, this.thumbSize);
+
+ this.resize();
+ this.render();
+ },
+
+ onSelect: function(item, index, items){
+ // summary:
+ // Dummy function that is triggered when an image is selected.
+ },
+
+ _setAnimationEnabledAttr: function(value){
+ this.animationEnabled = value;
+ dojo[value ? "addClass" : "removeClass"](this.domNode, "animated");
+ },
+
+ _setItemsAttr: function(items){
+ this.items = items || [];
+
+ var urls = {};
+ var i;
+ for(i = 0; i < this.items.length; i++){
+ urls[this.items[i][this.urlParam]] = 1;
+ }
+
+ var clearedUrls = [];
+ for(var url in this._onLoadImages){
+ if(!urls[url] && this._onLoadImages[url]._conn){
+ dojo.disconnect(this._onLoadImages[url]._conn);
+ this._onLoadImages[url].src = null;
+ clearedUrls.push(url);
+ }
+ }
+
+ for(i = 0; i < clearedUrls.length; i++){
+ delete this._onLoadImages[url];
+ }
+
+ this.render();
+ },
+
+ _getItemNode: function(node){
+ while(node && !dojo.hasClass(node, "mblThumb") && node != this.domNode){
+ node = node.parentNode;
+ }
+
+ return (node == this.domNode) ? null : node;
+ },
+
+ _getItemNodeFromEvent: function(event){
+ if(event.touches && event.touches.length > 0){
+ event = event.touches[0];
+ }
+ return this._getItemNode(event.target);
+ },
+
+ resize: function(){
+ this._thumbSize = null;
+
+ this._size = dojo.contentBox(this.domNode);
+
+ this.disableHide = true;
+ this.render();
+ this.disableHide = false;
+ },
+
+ hideCached: function(){
+ // summary:
+ // Hides all cached nodes, so that they're no invisible and overlaying
+ // other screen elements.
+ for(var i = 0; i < this.cache.length; i++){
+ if (this.cache[i]) {
+ dojo.style(this.cache[i], "display", "none");
+ }
+ }
+ },
+
+ render: function(){
+ var i;
+ var url;
+ var item;
+
+ var thumb;
+ while(this.visibleImages && this.visibleImages.length > 0){
+ thumb = this.visibleImages.pop();
+ this.cache.push(thumb);
+
+ if (!this.disableHide) {
+ dojo.addClass(thumb, "hidden");
+ }
+ thumb._cached = true;
+ }
+
+ if(this.cache && this.cache.length > 0){
+ setTimeout(this.hideCached, 1000);
+ }
+
+ if(!this.items || this.items.length == 0){
+ return;
+ }
+
+ for(i = 0; i < this.items.length; i++){
+ item = this.items[i];
+ url = (dojo.isString(item) ? item : item[this.urlParam]);
+
+ this.addThumb(item, url, i);
+
+ if(this.maxRows > 0 && (i + 1) / this.maxPerRow >= this.maxRows){
+ break;
+ }
+ }
+
+ if(!this._thumbSize){
+ return;
+ }
+
+ var column = 0;
+ var row = -1;
+
+ var totalThumbWidth = this._thumbSize.w + (this.padding * 2);
+ var totalThumbHeight = this._thumbSize.h + (this.padding * 2);
+
+ var nodes = this.thumbNodes =
+ dojo.query(".mblThumb", this.domNode);
+
+ var pos = 0;
+ nodes = this.visibleImages;
+ for(i = 0; i < nodes.length; i++){
+ if(nodes[i]._cached){
+ continue;
+ }
+
+ if(pos % this.maxPerRow == 0){
+ row ++;
+ }
+ column = pos % this.maxPerRow;
+
+ this.place(
+ nodes[i],
+ (column * totalThumbWidth) + this.padding, // x position
+ (row * totalThumbHeight) + this.padding // y position
+ );
+
+ if(!nodes[i]._loading){
+ dojo.removeClass(nodes[i], "hidden");
+ }
+
+ if(pos == this.selectedIndex){
+ dojo[pos == this.selectedIndex ? "addClass" : "removeClass"]
+ (nodes[i], "selected");
+ }
+ pos++;
+ }
+
+ var numRows = Math.ceil(pos / this.maxPerRow);
+
+ this._numRows = numRows;
+
+ this.setContainerHeight((numRows * (this._thumbSize.h + this.padding * 2)));
+ },
+
+ setContainerHeight: function(amount){
+ dojo.style(this.domNode, "height", amount + "px");
+ },
+
+ addThumb: function(item, url, index){
+
+ var thumbDiv;
+ var cacheHit = false;
+ if(this.cache.length > 0){
+ // Reuse a previously created node if possible
+ var found = false;
+ // Search for an image with the same url first
+ for(var i = 0; i < this.cache.length; i++){
+ if(this.cache[i]._url == url){
+ thumbDiv = this.cache.splice(i, 1)[0];
+ found = true;
+ break
+ }
+ }
+
+ // if no image with the same url is found, just take the last one
+ if(!thumbDiv && !this.cacheMustMatch){
+ thumbDiv = this.cache.pop();
+ dojo.removeClass(thumbDiv, "selected");
+ } else {
+ cacheHit = true;
+ }
+ }
+
+ if(!thumbDiv){
+
+ // Create a new thumb
+ thumbDiv = dojo.create("div", {
+ "class": "mblThumb hidden",
+ innerHTML: dojo.string.substitute(this.itemTemplate, {
+ url: url
+ }, null, this)
+ }, this.domNode);
+ }
+
+ if(this.labelParam) {
+ var labelNode = dojo.query(".mblThumbLabel", thumbDiv)[0];
+ if(!labelNode) {
+ labelNode = dojo.create("div", {
+ "class": "mblThumbLabel"
+ }, thumbDiv);
+ }
+ labelNode.innerHTML = item[this.labelParam] || "";
+ }
+
+ dojo.style(thumbDiv, "display", "");
+ if (!this.disableHide) {
+ dojo.addClass(thumbDiv, "hidden");
+ }
+
+ if (!cacheHit) {
+ var loader = dojo.create("img", {});
+ loader._thumbDiv = thumbDiv;
+ loader._conn = dojo.connect(loader, "onload", this.handleImgLoad);
+ loader._url = url;
+ thumbDiv._loading = true;
+
+ this._onLoadImages[url] = loader;
+ if (loader) {
+ loader.src = url;
+ }
+ }
+ this.visibleImages.push(thumbDiv);
+
+ thumbDiv._index = index;
+ thumbDiv._item = item;
+ thumbDiv._url = url;
+ thumbDiv._cached = false;
+
+ if(!this._thumbSize){
+ this._thumbSize = dojo.marginBox(thumbDiv);
+
+ if(this._thumbSize.h == 0){
+ this._thumbSize.h = 100;
+ this._thumbSize.w = 100;
+ }
+
+ if(this.labelParam){
+ this._thumbSize.h += 8;
+ }
+
+ this.calcPadding();
+ }
+ },
+
+ handleImgLoad: function(event){
+ var img = event.target;
+ dojo.disconnect(img._conn);
+ dojo.removeClass(img._thumbDiv, "hidden");
+ img._thumbDiv._loading = false;
+ img._conn = null;
+
+ var url = img._url;
+ if(this.cacheBust){
+ url += (url.indexOf("?") > -1 ? "&" : "?")
+ + "cacheBust=" + (new Date()).getTime() + "_" + (this._cacheCounter++);
+ }
+
+ dojo.query(".mblThumbSrc", img._thumbDiv)
+ .style("backgroundImage", "url(" + url + ")");
+
+ delete this._onLoadImages[img._url];
+ },
+
+ calcPadding: function(){
+ var width = this._size.w;
+
+ var thumbWidth = this._thumbSize.w;
+
+ var imgBounds = thumbWidth + this.minPadding;
+
+ this.maxPerRow = Math.floor(width / imgBounds);
+
+ this.padding = Math.floor((width - (thumbWidth * this.maxPerRow)) / (this.maxPerRow * 2));
+ },
+
+ place: function(node, x, y){
+ dojo.style(node, {
+ "-webkit-transform" :"translate(" + x + "px," + y + "px)"
+ });
+ },
+
+ destroy: function(){
+ // Stop the loading of any more images
+
+ var img;
+ var counter = 0;
+ for (var url in this._onLoadImages){
+ img = this._onLoadImages[url];
+ if (img) {
+ img.src = null;
+ counter++;
+ }
+ }
+
+ this.inherited(arguments);
+ }
+});
+
+}
diff --git a/js/dojo-1.6/dojox/mobile/app/ImageThumbView.xd.js b/js/dojo-1.6/dojox/mobile/app/ImageThumbView.xd.js
new file mode 100644
index 0000000..4553154
--- /dev/null
+++ b/js/dojo-1.6/dojox/mobile/app/ImageThumbView.xd.js
@@ -0,0 +1,406 @@
+/*
+ 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
+*/
+
+
+dojo._xdResourceLoaded(function(dojo, dijit, dojox){
+return {depends: [["provide", "dojox.mobile.app.ImageThumbView"],
+["require", "dijit._WidgetBase"],
+["require", "dojo.string"]],
+defineResource: function(dojo, dijit, dojox){if(!dojo._hasResource["dojox.mobile.app.ImageThumbView"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.mobile.app.ImageThumbView"] = true;
+dojo.provide("dojox.mobile.app.ImageThumbView");
+dojo.experimental("dojox.mobile.app.ImageThumbView");
+
+dojo.require("dijit._WidgetBase");
+dojo.require("dojo.string");
+
+dojo.declare("dojox.mobile.app.ImageThumbView", dijit._WidgetBase, {
+ // summary:
+ // An image thumbnail gallery
+
+ // items: Array
+ // The data items from which the image urls are retrieved.
+ // If an item is a string, it is expected to be a URL. Otherwise
+ // by default it is expected to have a 'url' member. This can
+ // be configured using the 'urlParam' attribute on this widget.
+ items: [],
+
+ // urlParam: String
+ // The paramter name used to retrieve an image url from a JSON object
+ urlParam: "url",
+
+ labelParam: null,
+
+ itemTemplate: '<div class="mblThumbInner">' +
+ '<div class="mblThumbOverlay"></div>' +
+ '<div class="mblThumbMask">' +
+ '<div class="mblThumbSrc" style="background-image:url(${url})"></div>' +
+ '</div>' +
+ '</div>',
+
+ minPadding: 4,
+
+ maxPerRow: 3,
+
+ maxRows: -1,
+
+ baseClass: "mblImageThumbView",
+
+ thumbSize: "medium",
+
+ animationEnabled: true,
+
+ selectedIndex: -1,
+
+ cache: null,
+
+ cacheMustMatch: false,
+
+ clickEvent: "onclick",
+
+ cacheBust: false,
+
+ disableHide: false,
+
+ constructor: function(params, node){
+ },
+
+ postCreate: function(){
+
+ this.inherited(arguments);
+ var _this = this;
+
+ var hoverCls = "mblThumbHover";
+
+ this.addThumb = dojo.hitch(this, this.addThumb);
+ this.handleImgLoad = dojo.hitch(this, this.handleImgLoad);
+ this.hideCached = dojo.hitch(this, this.hideCached);
+
+ this._onLoadImages = {};
+
+ this.cache = [];
+ this.visibleImages = [];
+
+ this._cacheCounter = 0;
+
+ this.connect(this.domNode, this.clickEvent, function(event){
+ var itemNode = _this._getItemNodeFromEvent(event);
+
+ if(itemNode && !itemNode._cached){
+ _this.onSelect(itemNode._item, itemNode._index, _this.items);
+ dojo.query(".selected", this.domNode).removeClass("selected");
+ dojo.addClass(itemNode, "selected");
+ }
+ });
+
+ dojo.addClass(this.domNode, this.thumbSize);
+
+ this.resize();
+ this.render();
+ },
+
+ onSelect: function(item, index, items){
+ // summary:
+ // Dummy function that is triggered when an image is selected.
+ },
+
+ _setAnimationEnabledAttr: function(value){
+ this.animationEnabled = value;
+ dojo[value ? "addClass" : "removeClass"](this.domNode, "animated");
+ },
+
+ _setItemsAttr: function(items){
+ this.items = items || [];
+
+ var urls = {};
+ var i;
+ for(i = 0; i < this.items.length; i++){
+ urls[this.items[i][this.urlParam]] = 1;
+ }
+
+ var clearedUrls = [];
+ for(var url in this._onLoadImages){
+ if(!urls[url] && this._onLoadImages[url]._conn){
+ dojo.disconnect(this._onLoadImages[url]._conn);
+ this._onLoadImages[url].src = null;
+ clearedUrls.push(url);
+ }
+ }
+
+ for(i = 0; i < clearedUrls.length; i++){
+ delete this._onLoadImages[url];
+ }
+
+ this.render();
+ },
+
+ _getItemNode: function(node){
+ while(node && !dojo.hasClass(node, "mblThumb") && node != this.domNode){
+ node = node.parentNode;
+ }
+
+ return (node == this.domNode) ? null : node;
+ },
+
+ _getItemNodeFromEvent: function(event){
+ if(event.touches && event.touches.length > 0){
+ event = event.touches[0];
+ }
+ return this._getItemNode(event.target);
+ },
+
+ resize: function(){
+ this._thumbSize = null;
+
+ this._size = dojo.contentBox(this.domNode);
+
+ this.disableHide = true;
+ this.render();
+ this.disableHide = false;
+ },
+
+ hideCached: function(){
+ // summary:
+ // Hides all cached nodes, so that they're no invisible and overlaying
+ // other screen elements.
+ for(var i = 0; i < this.cache.length; i++){
+ if (this.cache[i]) {
+ dojo.style(this.cache[i], "display", "none");
+ }
+ }
+ },
+
+ render: function(){
+ var i;
+ var url;
+ var item;
+
+ var thumb;
+ while(this.visibleImages && this.visibleImages.length > 0){
+ thumb = this.visibleImages.pop();
+ this.cache.push(thumb);
+
+ if (!this.disableHide) {
+ dojo.addClass(thumb, "hidden");
+ }
+ thumb._cached = true;
+ }
+
+ if(this.cache && this.cache.length > 0){
+ setTimeout(this.hideCached, 1000);
+ }
+
+ if(!this.items || this.items.length == 0){
+ return;
+ }
+
+ for(i = 0; i < this.items.length; i++){
+ item = this.items[i];
+ url = (dojo.isString(item) ? item : item[this.urlParam]);
+
+ this.addThumb(item, url, i);
+
+ if(this.maxRows > 0 && (i + 1) / this.maxPerRow >= this.maxRows){
+ break;
+ }
+ }
+
+ if(!this._thumbSize){
+ return;
+ }
+
+ var column = 0;
+ var row = -1;
+
+ var totalThumbWidth = this._thumbSize.w + (this.padding * 2);
+ var totalThumbHeight = this._thumbSize.h + (this.padding * 2);
+
+ var nodes = this.thumbNodes =
+ dojo.query(".mblThumb", this.domNode);
+
+ var pos = 0;
+ nodes = this.visibleImages;
+ for(i = 0; i < nodes.length; i++){
+ if(nodes[i]._cached){
+ continue;
+ }
+
+ if(pos % this.maxPerRow == 0){
+ row ++;
+ }
+ column = pos % this.maxPerRow;
+
+ this.place(
+ nodes[i],
+ (column * totalThumbWidth) + this.padding, // x position
+ (row * totalThumbHeight) + this.padding // y position
+ );
+
+ if(!nodes[i]._loading){
+ dojo.removeClass(nodes[i], "hidden");
+ }
+
+ if(pos == this.selectedIndex){
+ dojo[pos == this.selectedIndex ? "addClass" : "removeClass"]
+ (nodes[i], "selected");
+ }
+ pos++;
+ }
+
+ var numRows = Math.ceil(pos / this.maxPerRow);
+
+ this._numRows = numRows;
+
+ this.setContainerHeight((numRows * (this._thumbSize.h + this.padding * 2)));
+ },
+
+ setContainerHeight: function(amount){
+ dojo.style(this.domNode, "height", amount + "px");
+ },
+
+ addThumb: function(item, url, index){
+
+ var thumbDiv;
+ var cacheHit = false;
+ if(this.cache.length > 0){
+ // Reuse a previously created node if possible
+ var found = false;
+ // Search for an image with the same url first
+ for(var i = 0; i < this.cache.length; i++){
+ if(this.cache[i]._url == url){
+ thumbDiv = this.cache.splice(i, 1)[0];
+ found = true;
+ break
+ }
+ }
+
+ // if no image with the same url is found, just take the last one
+ if(!thumbDiv && !this.cacheMustMatch){
+ thumbDiv = this.cache.pop();
+ dojo.removeClass(thumbDiv, "selected");
+ } else {
+ cacheHit = true;
+ }
+ }
+
+ if(!thumbDiv){
+
+ // Create a new thumb
+ thumbDiv = dojo.create("div", {
+ "class": "mblThumb hidden",
+ innerHTML: dojo.string.substitute(this.itemTemplate, {
+ url: url
+ }, null, this)
+ }, this.domNode);
+ }
+
+ if(this.labelParam) {
+ var labelNode = dojo.query(".mblThumbLabel", thumbDiv)[0];
+ if(!labelNode) {
+ labelNode = dojo.create("div", {
+ "class": "mblThumbLabel"
+ }, thumbDiv);
+ }
+ labelNode.innerHTML = item[this.labelParam] || "";
+ }
+
+ dojo.style(thumbDiv, "display", "");
+ if (!this.disableHide) {
+ dojo.addClass(thumbDiv, "hidden");
+ }
+
+ if (!cacheHit) {
+ var loader = dojo.create("img", {});
+ loader._thumbDiv = thumbDiv;
+ loader._conn = dojo.connect(loader, "onload", this.handleImgLoad);
+ loader._url = url;
+ thumbDiv._loading = true;
+
+ this._onLoadImages[url] = loader;
+ if (loader) {
+ loader.src = url;
+ }
+ }
+ this.visibleImages.push(thumbDiv);
+
+ thumbDiv._index = index;
+ thumbDiv._item = item;
+ thumbDiv._url = url;
+ thumbDiv._cached = false;
+
+ if(!this._thumbSize){
+ this._thumbSize = dojo.marginBox(thumbDiv);
+
+ if(this._thumbSize.h == 0){
+ this._thumbSize.h = 100;
+ this._thumbSize.w = 100;
+ }
+
+ if(this.labelParam){
+ this._thumbSize.h += 8;
+ }
+
+ this.calcPadding();
+ }
+ },
+
+ handleImgLoad: function(event){
+ var img = event.target;
+ dojo.disconnect(img._conn);
+ dojo.removeClass(img._thumbDiv, "hidden");
+ img._thumbDiv._loading = false;
+ img._conn = null;
+
+ var url = img._url;
+ if(this.cacheBust){
+ url += (url.indexOf("?") > -1 ? "&" : "?")
+ + "cacheBust=" + (new Date()).getTime() + "_" + (this._cacheCounter++);
+ }
+
+ dojo.query(".mblThumbSrc", img._thumbDiv)
+ .style("backgroundImage", "url(" + url + ")");
+
+ delete this._onLoadImages[img._url];
+ },
+
+ calcPadding: function(){
+ var width = this._size.w;
+
+ var thumbWidth = this._thumbSize.w;
+
+ var imgBounds = thumbWidth + this.minPadding;
+
+ this.maxPerRow = Math.floor(width / imgBounds);
+
+ this.padding = Math.floor((width - (thumbWidth * this.maxPerRow)) / (this.maxPerRow * 2));
+ },
+
+ place: function(node, x, y){
+ dojo.style(node, {
+ "-webkit-transform" :"translate(" + x + "px," + y + "px)"
+ });
+ },
+
+ destroy: function(){
+ // Stop the loading of any more images
+
+ var img;
+ var counter = 0;
+ for (var url in this._onLoadImages){
+ img = this._onLoadImages[url];
+ if (img) {
+ img.src = null;
+ counter++;
+ }
+ }
+
+ this.inherited(arguments);
+ }
+});
+
+}
+
+}};});
diff --git a/js/dojo-1.6/dojox/mobile/app/ImageView.js b/js/dojo-1.6/dojox/mobile/app/ImageView.js
new file mode 100644
index 0000000..cb77865
--- /dev/null
+++ b/js/dojo-1.6/dojox/mobile/app/ImageView.js
@@ -0,0 +1,727 @@
+/*
+ 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
+*/
+
+
+if(!dojo._hasResource["dojox.mobile.app.ImageView"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.mobile.app.ImageView"] = true;
+dojo.provide("dojox.mobile.app.ImageView");
+dojo.experimental("dojox.mobile.app.ImageView");
+dojo.require("dojox.mobile.app._Widget");
+
+dojo.require("dojo.fx.easing");
+
+dojo.declare("dojox.mobile.app.ImageView", dojox.mobile.app._Widget, {
+
+ // zoom: Number
+ // The current level of zoom. This should not be set manually.
+ zoom: 1,
+
+ // zoomCenterX: Number
+ // The X coordinate in the image where the zoom is focused
+ zoomCenterX: 0,
+
+ // zoomCenterY: Number
+ // The Y coordinate in the image where the zoom is focused
+ zoomCenterY: 0,
+
+ // maxZoom: Number
+ // The highest degree to which an image can be zoomed. For example,
+ // a maxZoom of 5 means that the image will be 5 times larger than normal
+ maxZoom: 5,
+
+ // autoZoomLevel: Number
+ // The degree to which the image is zoomed when auto zoom is invoked.
+ // The higher the number, the more the image is zoomed in.
+ autoZoomLevel: 3,
+
+ // disableAutoZoom: Boolean
+ // Disables auto zoom
+ disableAutoZoom: false,
+
+ // disableSwipe: Boolean
+ // Disables the users ability to swipe from one image to the next.
+ disableSwipe: false,
+
+ // autoZoomEvent: String
+ // Overrides the default event listened to which invokes auto zoom
+ autoZoomEvent: null,
+
+ // _leftImg: Node
+ // The full sized image to the left
+ _leftImg: null,
+
+ // _centerImg: Node
+ // The full sized image in the center
+ _centerImg: null,
+
+ // _rightImg: Node
+ // The full sized image to the right
+ _rightImg: null,
+
+ // _leftImg: Node
+ // The small sized image to the left
+ _leftSmallImg: null,
+
+ // _centerImg: Node
+ // The small sized image in the center
+ _centerSmallImg: null,
+
+ // _rightImg: Node
+ // The small sized image to the right
+ _rightSmallImg: null,
+
+ constructor: function(){
+
+ this.panX = 0;
+ this.panY = 0;
+
+ this.handleLoad = dojo.hitch(this, this.handleLoad);
+ this._updateAnimatedZoom = dojo.hitch(this, this._updateAnimatedZoom);
+ this._updateAnimatedPan = dojo.hitch(this, this._updateAnimatedPan);
+ this._onAnimPanEnd = dojo.hitch(this, this._onAnimPanEnd);
+ },
+
+ buildRendering: function(){
+ this.inherited(arguments);
+
+ this.canvas = dojo.create("canvas", {}, this.domNode);
+
+ dojo.addClass(this.domNode, "mblImageView");
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+
+ this.size = dojo.marginBox(this.domNode);
+
+ dojo.style(this.canvas, {
+ width: this.size.w + "px",
+ height: this.size.h + "px"
+ });
+ this.canvas.height = this.size.h;
+ this.canvas.width = this.size.w;
+
+ var _this = this;
+
+ // Listen to the mousedown/touchstart event. Record the position
+ // so we can use it to pan the image.
+ this.connect(this.domNode, "onmousedown", function(event){
+ if(_this.isAnimating()){
+ return;
+ }
+ if(_this.panX){
+ _this.handleDragEnd();
+ }
+
+ _this.downX = event.targetTouches ? event.targetTouches[0].clientX : event.clientX;
+ _this.downY = event.targetTouches ? event.targetTouches[0].clientY : event.clientY;
+ });
+
+ // record the movement of the mouse.
+ this.connect(this.domNode, "onmousemove", function(event){
+ if(_this.isAnimating()){
+ return;
+ }
+ if((!_this.downX && _this.downX !== 0) || (!_this.downY && _this.downY !== 0)){
+ // If the touch didn't begin on this widget, ignore the movement
+ return;
+ }
+
+ if((!_this.disableSwipe && _this.zoom == 1)
+ || (!_this.disableAutoZoom && _this.zoom != 1)){
+ var x = event.targetTouches ?
+ event.targetTouches[0].clientX : event.pageX;
+ var y = event.targetTouches ?
+ event.targetTouches[0].clientY : event.pageY;
+
+ _this.panX = x - _this.downX;
+ _this.panY = y - _this.downY;
+
+ if(_this.zoom == 1){
+ // If not zoomed in, then try to move to the next or prev image
+ // but only if the mouse has moved more than 10 pixels
+ // in the X direction
+ if(Math.abs(_this.panX) > 10){
+ _this.render();
+ }
+ }else{
+ // If zoomed in, pan the image if the mouse has moved more
+ // than 10 pixels in either direction.
+ if(Math.abs(_this.panX) > 10 || Math.abs(_this.panY) > 10){
+ _this.render();
+ }
+ }
+ }
+ });
+
+ this.connect(this.domNode, "onmouseout", function(event){
+ if(!_this.isAnimating() && _this.panX){
+ _this.handleDragEnd();
+ }
+ });
+
+ this.connect(this.domNode, "onmouseover", function(event){
+ _this.downX = _this.downY = null;
+ });
+
+ // Set up AutoZoom, which zooms in a fixed amount when the user taps
+ // a part of the canvas
+ this.connect(this.domNode, "onclick", function(event){
+ if(_this.isAnimating()){
+ return;
+ }
+ if(_this.downX == null || _this.downY == null){
+ return;
+ }
+
+ var x = (event.targetTouches ?
+ event.targetTouches[0].clientX : event.pageX);
+ var y = (event.targetTouches ?
+ event.targetTouches[0].clientY : event.pageY);
+
+ // If the mouse/finger has moved more than 14 pixels from where it
+ // started, do not treat it as a click. It is a drag.
+ if(Math.abs(_this.panX) > 14 || Math.abs(_this.panY) > 14){
+ _this.downX = _this.downY = null;
+ _this.handleDragEnd();
+ return;
+ }
+ _this.downX = _this.downY = null;
+
+ if(!_this.disableAutoZoom){
+
+ if(!_this._centerImg || !_this._centerImg._loaded){
+ // Do nothing until the image is loaded
+ return;
+ }
+ if(_this.zoom != 1){
+ _this.set("animatedZoom", 1);
+ return;
+ }
+
+ var pos = dojo._abs(_this.domNode);
+
+ // Translate the clicked point to a point on the source image
+ var xRatio = _this.size.w / _this._centerImg.width;
+ var yRatio = _this.size.h / _this._centerImg.height;
+
+ // Do an animated zoom to the point which was clicked.
+ _this.zoomTo(
+ ((x - pos.x) / xRatio) - _this.panX,
+ ((y - pos.y) / yRatio) - _this.panY,
+ _this.autoZoomLevel);
+ }
+ });
+
+ // Listen for Flick events
+ dojo.connect(this.domNode, "flick", this, "handleFlick");
+ },
+
+ isAnimating: function(){
+ // summary:
+ // Returns true if an animation is in progress, false otherwise.
+ return this._anim && this._anim.status() == "playing";
+ },
+
+ handleDragEnd: function(){
+ // summary:
+ // Handles the end of a dragging event. If not zoomed in, it
+ // determines if the next or previous image should be transitioned
+ // to.
+ this.downX = this.downY = null;
+ console.log("handleDragEnd");
+
+ if(this.zoom == 1){
+ if(!this.panX){
+ return;
+ }
+
+ var leftLoaded = (this._leftImg && this._leftImg._loaded)
+ || (this._leftSmallImg && this._leftSmallImg._loaded);
+ var rightLoaded = (this._rightImg && this._rightImg._loaded)
+ || (this._rightSmallImg && this._rightSmallImg._loaded);
+
+ // Check if the drag has moved the image more than half its length.
+ // If so, move to either the previous or next image.
+ var doMove =
+ !(Math.abs(this.panX) < this._centerImg._baseWidth / 2) &&
+ (
+ (this.panX > 0 && leftLoaded ? 1 : 0) ||
+ (this.panX < 0 && rightLoaded ? 1 : 0)
+ );
+
+
+ if(!doMove){
+ // If not moving to another image, animate the sliding of the
+ // image back into place.
+ this._animPanTo(0, dojo.fx.easing.expoOut, 700);
+ }else{
+ // Move to another image.
+ this.moveTo(this.panX);
+ }
+ }else{
+ if(!this.panX && !this.panY){
+ return;
+ }
+ // Recenter the zoomed image based on where it was panned to
+ // previously
+ this.zoomCenterX -= (this.panX / this.zoom);
+ this.zoomCenterY -= (this.panY / this.zoom);
+
+ this.panX = this.panY = 0;
+ }
+
+ },
+
+ handleFlick: function(event){
+ // summary:
+ // Handle a flick event.
+ if(this.zoom == 1 && event.duration < 500){
+ // Only handle quick flicks here, less than 0.5 seconds
+
+ // If not zoomed in, then check if we should move to the next photo
+ // or not
+ if(event.direction == "ltr"){
+ this.moveTo(1);
+ }else if(event.direction == "rtl"){
+ this.moveTo(-1);
+ }
+ // If an up or down flick occurs, it means nothing so ignore it
+ this.downX = this.downY = null;
+ }
+ },
+
+ moveTo: function(direction){
+ direction = direction > 0 ? 1 : -1;
+ var toImg;
+
+ if(direction < 1){
+ if(this._rightImg && this._rightImg._loaded){
+ toImg = this._rightImg;
+ }else if(this._rightSmallImg && this._rightSmallImg._loaded){
+ toImg = this._rightSmallImg;
+ }
+ }else{
+ if(this._leftImg && this._leftImg._loaded){
+ toImg = this._leftImg;
+ }else if(this._leftSmallImg && this._leftSmallImg._loaded){
+ toImg = this._leftSmallImg;
+ }
+ }
+
+ this._moveDir = direction;
+ var _this = this;
+
+ if(toImg && toImg._loaded){
+ // If the image is loaded, make a linear animation to show it
+ this._animPanTo(this.size.w * direction, null, 500, function(){
+ _this.panX = 0;
+ _this.panY = 0;
+
+ if(direction < 0){
+ // Moving to show the right image
+ _this._switchImage("left", "right");
+ }else{
+ // Moving to show the left image
+ _this._switchImage("right", "left");
+ }
+
+ _this.render();
+ _this.onChange(direction * -1);
+ });
+
+ }else{
+ // If the next image is not loaded, make an animation to
+ // move the center image to half the width of the widget and back
+ // again
+
+ console.log("moveTo image not loaded!", toImg);
+
+ this._animPanTo(0, dojo.fx.easing.expoOut, 700);
+ }
+ },
+
+ _switchImage: function(toImg, fromImg){
+ var toSmallImgName = "_" + toImg + "SmallImg";
+ var toImgName = "_" + toImg + "Img";
+
+ var fromSmallImgName = "_" + fromImg + "SmallImg";
+ var fromImgName = "_" + fromImg + "Img";
+
+ this[toImgName] = this._centerImg;
+ this[toSmallImgName] = this._centerSmallImg;
+
+ this[toImgName]._type = toImg;
+
+ if(this[toSmallImgName]){
+ this[toSmallImgName]._type = toImg;
+ }
+
+ this._centerImg = this[fromImgName];
+ this._centerSmallImg = this[fromSmallImgName];
+ this._centerImg._type = "center";
+
+ if(this._centerSmallImg){
+ this._centerSmallImg._type = "center";
+ }
+ this[fromImgName] = this[fromSmallImgName] = null;
+ },
+
+ _animPanTo: function(to, easing, duration, callback){
+ this._animCallback = callback;
+ this._anim = new dojo.Animation({
+ curve: [this.panX, to],
+ onAnimate: this._updateAnimatedPan,
+ duration: duration || 500,
+ easing: easing,
+ onEnd: this._onAnimPanEnd
+ });
+
+ this._anim.play();
+ return this._anim;
+ },
+
+ onChange: function(direction){
+ // summary:
+ // Stub function that can be listened to in order to provide
+ // new images when the displayed image changes
+ },
+
+ _updateAnimatedPan: function(amount){
+ this.panX = amount;
+ this.render();
+ },
+
+ _onAnimPanEnd: function(){
+ this.panX = this.panY = 0;
+
+ if(this._animCallback){
+ this._animCallback();
+ }
+ },
+
+ zoomTo: function(centerX, centerY, zoom){
+ this.set("zoomCenterX", centerX);
+ this.set("zoomCenterY", centerY);
+
+ this.set("animatedZoom", zoom);
+ },
+
+ render: function(){
+ var cxt = this.canvas.getContext('2d');
+
+ cxt.clearRect(0, 0, this.canvas.width, this.canvas.height);
+
+ // Render the center image
+ this._renderImg(
+ this._centerSmallImg,
+ this._centerImg,
+ this.zoom == 1 ? (this.panX < 0 ? 1 : this.panX > 0 ? -1 : 0) : 0);
+
+ if(this.zoom == 1 && this.panX != 0){
+ if(this.panX > 0){
+ // Render the left image, showing the right side of it
+ this._renderImg(this._leftSmallImg, this._leftImg, 1);
+ }else{
+ // Render the right image, showing the left side of it
+ this._renderImg(this._rightSmallImg, this._rightImg, -1);
+ }
+ }
+ },
+
+ _renderImg: function(smallImg, largeImg, panDir){
+ // summary:
+ // Renders a single image
+
+
+ // If zoomed, we just display the center img
+ var img = (largeImg && largeImg._loaded) ? largeImg : smallImg;
+
+ if(!img || !img._loaded){
+ // If neither the large or small image is loaded, display nothing
+ return;
+ }
+ var cxt = this.canvas.getContext('2d');
+
+ var baseWidth = img._baseWidth;
+ var baseHeight = img._baseHeight;
+
+ // Calculate the size the image would be if there were no bounds
+ var desiredWidth = baseWidth * this.zoom;
+ var desiredHeight = baseHeight * this.zoom;
+
+ // Calculate the actual size of the viewable image
+ var destWidth = Math.min(this.size.w, desiredWidth);
+ var destHeight = Math.min(this.size.h, desiredHeight);
+
+
+ // Calculate the size of the window on the original image to use
+ var sourceWidth = this.dispWidth = img.width * (destWidth / desiredWidth);
+ var sourceHeight = this.dispHeight = img.height * (destHeight / desiredHeight);
+
+ var zoomCenterX = this.zoomCenterX - (this.panX / this.zoom);
+ var zoomCenterY = this.zoomCenterY - (this.panY / this.zoom);
+
+ // Calculate where the center of the view should be
+ var centerX = Math.floor(Math.max(sourceWidth / 2,
+ Math.min(img.width - sourceWidth / 2, zoomCenterX)));
+ var centerY = Math.floor(Math.max(sourceHeight / 2,
+ Math.min(img.height - sourceHeight / 2, zoomCenterY)));
+
+
+ var sourceX = Math.max(0,
+ Math.round((img.width - sourceWidth)/2 + (centerX - img._centerX)) );
+ var sourceY = Math.max(0,
+ Math.round((img.height - sourceHeight) / 2 + (centerY - img._centerY))
+ );
+
+ var destX = Math.round(Math.max(0, this.canvas.width - destWidth)/2);
+ var destY = Math.round(Math.max(0, this.canvas.height - destHeight)/2);
+
+ var oldDestWidth = destWidth;
+ var oldSourceWidth = sourceWidth;
+
+ if(this.zoom == 1 && panDir && this.panX){
+
+ if(this.panX < 0){
+ if(panDir > 0){
+ // If the touch is moving left, and the right side of the
+ // image should be shown, then reduce the destination width
+ // by the absolute value of panX
+ destWidth -= Math.abs(this.panX);
+ destX = 0;
+ }else if(panDir < 0){
+ // If the touch is moving left, and the left side of the
+ // image should be shown, then set the displayed width
+ // to the absolute value of panX, less some pixels for
+ // a padding between images
+ destWidth = Math.max(1, Math.abs(this.panX) - 5);
+ destX = this.size.w - destWidth;
+ }
+ }else{
+ if(panDir > 0){
+ // If the touch is moving right, and the right side of the
+ // image should be shown, then set the destination width
+ // to the absolute value of the pan, less some pixels for
+ // padding
+ destWidth = Math.max(1, Math.abs(this.panX) - 5);
+ destX = 0;
+ }else if(panDir < 0){
+ // If the touch is moving right, and the left side of the
+ // image should be shown, then reduce the destination width
+ // by the widget width minus the absolute value of panX
+ destWidth -= Math.abs(this.panX);
+ destX = this.size.w - destWidth;
+ }
+ }
+
+ sourceWidth = Math.max(1,
+ Math.floor(sourceWidth * (destWidth / oldDestWidth)));
+
+ if(panDir > 0){
+ // If the right side of the image should be displayed, move
+ // the sourceX to be the width of the image minus the difference
+ // between the original sourceWidth and the new sourceWidth
+ sourceX = (sourceX + oldSourceWidth) - (sourceWidth);
+ }
+ sourceX = Math.floor(sourceX);
+ }
+
+ try{
+
+ // See https://developer.mozilla.org/en/Canvas_tutorial/Using_images
+ cxt.drawImage(
+ img,
+ Math.max(0, sourceX),
+ sourceY,
+ Math.min(oldSourceWidth, sourceWidth),
+ sourceHeight,
+ destX, // Xpos
+ destY, // Ypos
+ Math.min(oldDestWidth, destWidth),
+ destHeight
+ );
+ }catch(e){
+ console.log("Caught Error",e,
+
+ "type=", img._type,
+ "oldDestWidth = ", oldDestWidth,
+ "destWidth", destWidth,
+ "destX", destX
+ , "oldSourceWidth=",oldSourceWidth,
+ "sourceWidth=", sourceWidth,
+ "sourceX = " + sourceX
+ );
+ }
+ },
+
+ _setZoomAttr: function(amount){
+ this.zoom = Math.min(this.maxZoom, Math.max(1, amount));
+
+ if(this.zoom == 1
+ && this._centerImg
+ && this._centerImg._loaded){
+
+ if(!this.isAnimating()){
+ this.zoomCenterX = this._centerImg.width / 2;
+ this.zoomCenterY = this._centerImg.height / 2;
+ }
+ this.panX = this.panY = 0;
+ }
+
+ this.render();
+ },
+
+ _setZoomCenterXAttr: function(value){
+ if(value != this.zoomCenterX){
+ if(this._centerImg && this._centerImg._loaded){
+ value = Math.min(this._centerImg.width, value);
+ }
+ this.zoomCenterX = Math.max(0, Math.round(value));
+ }
+ },
+
+ _setZoomCenterYAttr: function(value){
+ if(value != this.zoomCenterY){
+ if(this._centerImg && this._centerImg._loaded){
+ value = Math.min(this._centerImg.height, value);
+ }
+ this.zoomCenterY = Math.max(0, Math.round(value));
+ }
+ },
+
+ _setZoomCenterAttr: function(value){
+ if(value.x != this.zoomCenterX || value.y != this.zoomCenterY){
+ this.set("zoomCenterX", value.x);
+ this.set("zoomCenterY", value.y);
+ this.render();
+ }
+ },
+
+ _setAnimatedZoomAttr: function(amount){
+ if(this._anim && this._anim.status() == "playing"){
+ return;
+ }
+
+ this._anim = new dojo.Animation({
+ curve: [this.zoom, amount],
+ onAnimate: this._updateAnimatedZoom,
+ onEnd: this._onAnimEnd
+ });
+
+ this._anim.play();
+ },
+
+ _updateAnimatedZoom: function(amount){
+ this._setZoomAttr(amount);
+ },
+
+ _setCenterUrlAttr: function(urlOrObj){
+ this._setImage("center", urlOrObj);
+ },
+ _setLeftUrlAttr: function(urlOrObj){
+ this._setImage("left", urlOrObj);
+ },
+ _setRightUrlAttr: function(urlOrObj){
+ this._setImage("right", urlOrObj);
+ },
+
+ _setImage: function(name, urlOrObj){
+ var smallUrl = null;
+
+ var largeUrl = null;
+
+ if(dojo.isString(urlOrObj)){
+ // If the argument is a string, then just load the large url
+ largeUrl = urlOrObj;
+ }else{
+ largeUrl = urlOrObj.large;
+ smallUrl = urlOrObj.small;
+ }
+
+ if(this["_" + name + "Img"] && this["_" + name + "Img"]._src == largeUrl){
+ // Identical URL, ignore it
+ return;
+ }
+
+ // Just do the large image for now
+ var largeImg = this["_" + name + "Img"] = new Image();
+ largeImg._type = name;
+ largeImg._loaded = false;
+ largeImg._src = largeUrl;
+ largeImg._conn = dojo.connect(largeImg, "onload", this.handleLoad);
+
+ if(smallUrl){
+ // If a url to a small version of the image has been provided,
+ // load that image first.
+ var smallImg = this["_" + name + "SmallImg"] = new Image();
+ smallImg._type = name;
+ smallImg._loaded = false;
+ smallImg._conn = dojo.connect(smallImg, "onload", this.handleLoad);
+ smallImg._isSmall = true;
+ smallImg._src = smallUrl;
+ smallImg.src = smallUrl;
+ }
+
+ // It's important that the large url's src is set after the small image
+ // to ensure it's loaded second.
+ largeImg.src = largeUrl;
+ },
+
+ handleLoad: function(evt){
+ // summary:
+ // Handles the loading of an image, both the large and small
+ // versions. A render is triggered as a result of each image load.
+
+ var img = evt.target;
+ img._loaded = true;
+
+ dojo.disconnect(img._conn);
+
+ var type = img._type;
+
+ switch(type){
+ case "center":
+ this.zoomCenterX = img.width / 2;
+ this.zoomCenterY = img.height / 2;
+ break;
+ }
+
+ var height = img.height;
+ var width = img.width;
+
+ if(width / this.size.w < height / this.size.h){
+ // Fit the height to the height of the canvas
+ img._baseHeight = this.canvas.height;
+ img._baseWidth = width / (height / this.size.h);
+ }else{
+ // Fix the width to the width of the canvas
+ img._baseWidth = this.canvas.width;
+ img._baseHeight = height / (width / this.size.w);
+ }
+ img._centerX = width / 2;
+ img._centerY = height / 2;
+
+ this.render();
+
+ this.onLoad(img._type, img._src, img._isSmall);
+ },
+
+ onLoad: function(type, url, isSmall){
+ // summary:
+ // Dummy function that is called whenever an image loads.
+ // type: String
+ // The position of the image that has loaded, either
+ // "center", "left" or "right"
+ // url: String
+ // The src of the image
+ // isSmall: Boolean
+ // True if it is a small version of the image that has loaded,
+ // false otherwise.
+ }
+});
+
+}
diff --git a/js/dojo-1.6/dojox/mobile/app/ImageView.xd.js b/js/dojo-1.6/dojox/mobile/app/ImageView.xd.js
new file mode 100644
index 0000000..9f4226f
--- /dev/null
+++ b/js/dojo-1.6/dojox/mobile/app/ImageView.xd.js
@@ -0,0 +1,733 @@
+/*
+ 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
+*/
+
+
+dojo._xdResourceLoaded(function(dojo, dijit, dojox){
+return {depends: [["provide", "dojox.mobile.app.ImageView"],
+["require", "dojox.mobile.app._Widget"],
+["require", "dojo.fx.easing"]],
+defineResource: function(dojo, dijit, dojox){if(!dojo._hasResource["dojox.mobile.app.ImageView"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.mobile.app.ImageView"] = true;
+dojo.provide("dojox.mobile.app.ImageView");
+dojo.experimental("dojox.mobile.app.ImageView");
+dojo.require("dojox.mobile.app._Widget");
+
+dojo.require("dojo.fx.easing");
+
+dojo.declare("dojox.mobile.app.ImageView", dojox.mobile.app._Widget, {
+
+ // zoom: Number
+ // The current level of zoom. This should not be set manually.
+ zoom: 1,
+
+ // zoomCenterX: Number
+ // The X coordinate in the image where the zoom is focused
+ zoomCenterX: 0,
+
+ // zoomCenterY: Number
+ // The Y coordinate in the image where the zoom is focused
+ zoomCenterY: 0,
+
+ // maxZoom: Number
+ // The highest degree to which an image can be zoomed. For example,
+ // a maxZoom of 5 means that the image will be 5 times larger than normal
+ maxZoom: 5,
+
+ // autoZoomLevel: Number
+ // The degree to which the image is zoomed when auto zoom is invoked.
+ // The higher the number, the more the image is zoomed in.
+ autoZoomLevel: 3,
+
+ // disableAutoZoom: Boolean
+ // Disables auto zoom
+ disableAutoZoom: false,
+
+ // disableSwipe: Boolean
+ // Disables the users ability to swipe from one image to the next.
+ disableSwipe: false,
+
+ // autoZoomEvent: String
+ // Overrides the default event listened to which invokes auto zoom
+ autoZoomEvent: null,
+
+ // _leftImg: Node
+ // The full sized image to the left
+ _leftImg: null,
+
+ // _centerImg: Node
+ // The full sized image in the center
+ _centerImg: null,
+
+ // _rightImg: Node
+ // The full sized image to the right
+ _rightImg: null,
+
+ // _leftImg: Node
+ // The small sized image to the left
+ _leftSmallImg: null,
+
+ // _centerImg: Node
+ // The small sized image in the center
+ _centerSmallImg: null,
+
+ // _rightImg: Node
+ // The small sized image to the right
+ _rightSmallImg: null,
+
+ constructor: function(){
+
+ this.panX = 0;
+ this.panY = 0;
+
+ this.handleLoad = dojo.hitch(this, this.handleLoad);
+ this._updateAnimatedZoom = dojo.hitch(this, this._updateAnimatedZoom);
+ this._updateAnimatedPan = dojo.hitch(this, this._updateAnimatedPan);
+ this._onAnimPanEnd = dojo.hitch(this, this._onAnimPanEnd);
+ },
+
+ buildRendering: function(){
+ this.inherited(arguments);
+
+ this.canvas = dojo.create("canvas", {}, this.domNode);
+
+ dojo.addClass(this.domNode, "mblImageView");
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+
+ this.size = dojo.marginBox(this.domNode);
+
+ dojo.style(this.canvas, {
+ width: this.size.w + "px",
+ height: this.size.h + "px"
+ });
+ this.canvas.height = this.size.h;
+ this.canvas.width = this.size.w;
+
+ var _this = this;
+
+ // Listen to the mousedown/touchstart event. Record the position
+ // so we can use it to pan the image.
+ this.connect(this.domNode, "onmousedown", function(event){
+ if(_this.isAnimating()){
+ return;
+ }
+ if(_this.panX){
+ _this.handleDragEnd();
+ }
+
+ _this.downX = event.targetTouches ? event.targetTouches[0].clientX : event.clientX;
+ _this.downY = event.targetTouches ? event.targetTouches[0].clientY : event.clientY;
+ });
+
+ // record the movement of the mouse.
+ this.connect(this.domNode, "onmousemove", function(event){
+ if(_this.isAnimating()){
+ return;
+ }
+ if((!_this.downX && _this.downX !== 0) || (!_this.downY && _this.downY !== 0)){
+ // If the touch didn't begin on this widget, ignore the movement
+ return;
+ }
+
+ if((!_this.disableSwipe && _this.zoom == 1)
+ || (!_this.disableAutoZoom && _this.zoom != 1)){
+ var x = event.targetTouches ?
+ event.targetTouches[0].clientX : event.pageX;
+ var y = event.targetTouches ?
+ event.targetTouches[0].clientY : event.pageY;
+
+ _this.panX = x - _this.downX;
+ _this.panY = y - _this.downY;
+
+ if(_this.zoom == 1){
+ // If not zoomed in, then try to move to the next or prev image
+ // but only if the mouse has moved more than 10 pixels
+ // in the X direction
+ if(Math.abs(_this.panX) > 10){
+ _this.render();
+ }
+ }else{
+ // If zoomed in, pan the image if the mouse has moved more
+ // than 10 pixels in either direction.
+ if(Math.abs(_this.panX) > 10 || Math.abs(_this.panY) > 10){
+ _this.render();
+ }
+ }
+ }
+ });
+
+ this.connect(this.domNode, "onmouseout", function(event){
+ if(!_this.isAnimating() && _this.panX){
+ _this.handleDragEnd();
+ }
+ });
+
+ this.connect(this.domNode, "onmouseover", function(event){
+ _this.downX = _this.downY = null;
+ });
+
+ // Set up AutoZoom, which zooms in a fixed amount when the user taps
+ // a part of the canvas
+ this.connect(this.domNode, "onclick", function(event){
+ if(_this.isAnimating()){
+ return;
+ }
+ if(_this.downX == null || _this.downY == null){
+ return;
+ }
+
+ var x = (event.targetTouches ?
+ event.targetTouches[0].clientX : event.pageX);
+ var y = (event.targetTouches ?
+ event.targetTouches[0].clientY : event.pageY);
+
+ // If the mouse/finger has moved more than 14 pixels from where it
+ // started, do not treat it as a click. It is a drag.
+ if(Math.abs(_this.panX) > 14 || Math.abs(_this.panY) > 14){
+ _this.downX = _this.downY = null;
+ _this.handleDragEnd();
+ return;
+ }
+ _this.downX = _this.downY = null;
+
+ if(!_this.disableAutoZoom){
+
+ if(!_this._centerImg || !_this._centerImg._loaded){
+ // Do nothing until the image is loaded
+ return;
+ }
+ if(_this.zoom != 1){
+ _this.set("animatedZoom", 1);
+ return;
+ }
+
+ var pos = dojo._abs(_this.domNode);
+
+ // Translate the clicked point to a point on the source image
+ var xRatio = _this.size.w / _this._centerImg.width;
+ var yRatio = _this.size.h / _this._centerImg.height;
+
+ // Do an animated zoom to the point which was clicked.
+ _this.zoomTo(
+ ((x - pos.x) / xRatio) - _this.panX,
+ ((y - pos.y) / yRatio) - _this.panY,
+ _this.autoZoomLevel);
+ }
+ });
+
+ // Listen for Flick events
+ dojo.connect(this.domNode, "flick", this, "handleFlick");
+ },
+
+ isAnimating: function(){
+ // summary:
+ // Returns true if an animation is in progress, false otherwise.
+ return this._anim && this._anim.status() == "playing";
+ },
+
+ handleDragEnd: function(){
+ // summary:
+ // Handles the end of a dragging event. If not zoomed in, it
+ // determines if the next or previous image should be transitioned
+ // to.
+ this.downX = this.downY = null;
+ console.log("handleDragEnd");
+
+ if(this.zoom == 1){
+ if(!this.panX){
+ return;
+ }
+
+ var leftLoaded = (this._leftImg && this._leftImg._loaded)
+ || (this._leftSmallImg && this._leftSmallImg._loaded);
+ var rightLoaded = (this._rightImg && this._rightImg._loaded)
+ || (this._rightSmallImg && this._rightSmallImg._loaded);
+
+ // Check if the drag has moved the image more than half its length.
+ // If so, move to either the previous or next image.
+ var doMove =
+ !(Math.abs(this.panX) < this._centerImg._baseWidth / 2) &&
+ (
+ (this.panX > 0 && leftLoaded ? 1 : 0) ||
+ (this.panX < 0 && rightLoaded ? 1 : 0)
+ );
+
+
+ if(!doMove){
+ // If not moving to another image, animate the sliding of the
+ // image back into place.
+ this._animPanTo(0, dojo.fx.easing.expoOut, 700);
+ }else{
+ // Move to another image.
+ this.moveTo(this.panX);
+ }
+ }else{
+ if(!this.panX && !this.panY){
+ return;
+ }
+ // Recenter the zoomed image based on where it was panned to
+ // previously
+ this.zoomCenterX -= (this.panX / this.zoom);
+ this.zoomCenterY -= (this.panY / this.zoom);
+
+ this.panX = this.panY = 0;
+ }
+
+ },
+
+ handleFlick: function(event){
+ // summary:
+ // Handle a flick event.
+ if(this.zoom == 1 && event.duration < 500){
+ // Only handle quick flicks here, less than 0.5 seconds
+
+ // If not zoomed in, then check if we should move to the next photo
+ // or not
+ if(event.direction == "ltr"){
+ this.moveTo(1);
+ }else if(event.direction == "rtl"){
+ this.moveTo(-1);
+ }
+ // If an up or down flick occurs, it means nothing so ignore it
+ this.downX = this.downY = null;
+ }
+ },
+
+ moveTo: function(direction){
+ direction = direction > 0 ? 1 : -1;
+ var toImg;
+
+ if(direction < 1){
+ if(this._rightImg && this._rightImg._loaded){
+ toImg = this._rightImg;
+ }else if(this._rightSmallImg && this._rightSmallImg._loaded){
+ toImg = this._rightSmallImg;
+ }
+ }else{
+ if(this._leftImg && this._leftImg._loaded){
+ toImg = this._leftImg;
+ }else if(this._leftSmallImg && this._leftSmallImg._loaded){
+ toImg = this._leftSmallImg;
+ }
+ }
+
+ this._moveDir = direction;
+ var _this = this;
+
+ if(toImg && toImg._loaded){
+ // If the image is loaded, make a linear animation to show it
+ this._animPanTo(this.size.w * direction, null, 500, function(){
+ _this.panX = 0;
+ _this.panY = 0;
+
+ if(direction < 0){
+ // Moving to show the right image
+ _this._switchImage("left", "right");
+ }else{
+ // Moving to show the left image
+ _this._switchImage("right", "left");
+ }
+
+ _this.render();
+ _this.onChange(direction * -1);
+ });
+
+ }else{
+ // If the next image is not loaded, make an animation to
+ // move the center image to half the width of the widget and back
+ // again
+
+ console.log("moveTo image not loaded!", toImg);
+
+ this._animPanTo(0, dojo.fx.easing.expoOut, 700);
+ }
+ },
+
+ _switchImage: function(toImg, fromImg){
+ var toSmallImgName = "_" + toImg + "SmallImg";
+ var toImgName = "_" + toImg + "Img";
+
+ var fromSmallImgName = "_" + fromImg + "SmallImg";
+ var fromImgName = "_" + fromImg + "Img";
+
+ this[toImgName] = this._centerImg;
+ this[toSmallImgName] = this._centerSmallImg;
+
+ this[toImgName]._type = toImg;
+
+ if(this[toSmallImgName]){
+ this[toSmallImgName]._type = toImg;
+ }
+
+ this._centerImg = this[fromImgName];
+ this._centerSmallImg = this[fromSmallImgName];
+ this._centerImg._type = "center";
+
+ if(this._centerSmallImg){
+ this._centerSmallImg._type = "center";
+ }
+ this[fromImgName] = this[fromSmallImgName] = null;
+ },
+
+ _animPanTo: function(to, easing, duration, callback){
+ this._animCallback = callback;
+ this._anim = new dojo.Animation({
+ curve: [this.panX, to],
+ onAnimate: this._updateAnimatedPan,
+ duration: duration || 500,
+ easing: easing,
+ onEnd: this._onAnimPanEnd
+ });
+
+ this._anim.play();
+ return this._anim;
+ },
+
+ onChange: function(direction){
+ // summary:
+ // Stub function that can be listened to in order to provide
+ // new images when the displayed image changes
+ },
+
+ _updateAnimatedPan: function(amount){
+ this.panX = amount;
+ this.render();
+ },
+
+ _onAnimPanEnd: function(){
+ this.panX = this.panY = 0;
+
+ if(this._animCallback){
+ this._animCallback();
+ }
+ },
+
+ zoomTo: function(centerX, centerY, zoom){
+ this.set("zoomCenterX", centerX);
+ this.set("zoomCenterY", centerY);
+
+ this.set("animatedZoom", zoom);
+ },
+
+ render: function(){
+ var cxt = this.canvas.getContext('2d');
+
+ cxt.clearRect(0, 0, this.canvas.width, this.canvas.height);
+
+ // Render the center image
+ this._renderImg(
+ this._centerSmallImg,
+ this._centerImg,
+ this.zoom == 1 ? (this.panX < 0 ? 1 : this.panX > 0 ? -1 : 0) : 0);
+
+ if(this.zoom == 1 && this.panX != 0){
+ if(this.panX > 0){
+ // Render the left image, showing the right side of it
+ this._renderImg(this._leftSmallImg, this._leftImg, 1);
+ }else{
+ // Render the right image, showing the left side of it
+ this._renderImg(this._rightSmallImg, this._rightImg, -1);
+ }
+ }
+ },
+
+ _renderImg: function(smallImg, largeImg, panDir){
+ // summary:
+ // Renders a single image
+
+
+ // If zoomed, we just display the center img
+ var img = (largeImg && largeImg._loaded) ? largeImg : smallImg;
+
+ if(!img || !img._loaded){
+ // If neither the large or small image is loaded, display nothing
+ return;
+ }
+ var cxt = this.canvas.getContext('2d');
+
+ var baseWidth = img._baseWidth;
+ var baseHeight = img._baseHeight;
+
+ // Calculate the size the image would be if there were no bounds
+ var desiredWidth = baseWidth * this.zoom;
+ var desiredHeight = baseHeight * this.zoom;
+
+ // Calculate the actual size of the viewable image
+ var destWidth = Math.min(this.size.w, desiredWidth);
+ var destHeight = Math.min(this.size.h, desiredHeight);
+
+
+ // Calculate the size of the window on the original image to use
+ var sourceWidth = this.dispWidth = img.width * (destWidth / desiredWidth);
+ var sourceHeight = this.dispHeight = img.height * (destHeight / desiredHeight);
+
+ var zoomCenterX = this.zoomCenterX - (this.panX / this.zoom);
+ var zoomCenterY = this.zoomCenterY - (this.panY / this.zoom);
+
+ // Calculate where the center of the view should be
+ var centerX = Math.floor(Math.max(sourceWidth / 2,
+ Math.min(img.width - sourceWidth / 2, zoomCenterX)));
+ var centerY = Math.floor(Math.max(sourceHeight / 2,
+ Math.min(img.height - sourceHeight / 2, zoomCenterY)));
+
+
+ var sourceX = Math.max(0,
+ Math.round((img.width - sourceWidth)/2 + (centerX - img._centerX)) );
+ var sourceY = Math.max(0,
+ Math.round((img.height - sourceHeight) / 2 + (centerY - img._centerY))
+ );
+
+ var destX = Math.round(Math.max(0, this.canvas.width - destWidth)/2);
+ var destY = Math.round(Math.max(0, this.canvas.height - destHeight)/2);
+
+ var oldDestWidth = destWidth;
+ var oldSourceWidth = sourceWidth;
+
+ if(this.zoom == 1 && panDir && this.panX){
+
+ if(this.panX < 0){
+ if(panDir > 0){
+ // If the touch is moving left, and the right side of the
+ // image should be shown, then reduce the destination width
+ // by the absolute value of panX
+ destWidth -= Math.abs(this.panX);
+ destX = 0;
+ }else if(panDir < 0){
+ // If the touch is moving left, and the left side of the
+ // image should be shown, then set the displayed width
+ // to the absolute value of panX, less some pixels for
+ // a padding between images
+ destWidth = Math.max(1, Math.abs(this.panX) - 5);
+ destX = this.size.w - destWidth;
+ }
+ }else{
+ if(panDir > 0){
+ // If the touch is moving right, and the right side of the
+ // image should be shown, then set the destination width
+ // to the absolute value of the pan, less some pixels for
+ // padding
+ destWidth = Math.max(1, Math.abs(this.panX) - 5);
+ destX = 0;
+ }else if(panDir < 0){
+ // If the touch is moving right, and the left side of the
+ // image should be shown, then reduce the destination width
+ // by the widget width minus the absolute value of panX
+ destWidth -= Math.abs(this.panX);
+ destX = this.size.w - destWidth;
+ }
+ }
+
+ sourceWidth = Math.max(1,
+ Math.floor(sourceWidth * (destWidth / oldDestWidth)));
+
+ if(panDir > 0){
+ // If the right side of the image should be displayed, move
+ // the sourceX to be the width of the image minus the difference
+ // between the original sourceWidth and the new sourceWidth
+ sourceX = (sourceX + oldSourceWidth) - (sourceWidth);
+ }
+ sourceX = Math.floor(sourceX);
+ }
+
+ try{
+
+ // See https://developer.mozilla.org/en/Canvas_tutorial/Using_images
+ cxt.drawImage(
+ img,
+ Math.max(0, sourceX),
+ sourceY,
+ Math.min(oldSourceWidth, sourceWidth),
+ sourceHeight,
+ destX, // Xpos
+ destY, // Ypos
+ Math.min(oldDestWidth, destWidth),
+ destHeight
+ );
+ }catch(e){
+ console.log("Caught Error",e,
+
+ "type=", img._type,
+ "oldDestWidth = ", oldDestWidth,
+ "destWidth", destWidth,
+ "destX", destX
+ , "oldSourceWidth=",oldSourceWidth,
+ "sourceWidth=", sourceWidth,
+ "sourceX = " + sourceX
+ );
+ }
+ },
+
+ _setZoomAttr: function(amount){
+ this.zoom = Math.min(this.maxZoom, Math.max(1, amount));
+
+ if(this.zoom == 1
+ && this._centerImg
+ && this._centerImg._loaded){
+
+ if(!this.isAnimating()){
+ this.zoomCenterX = this._centerImg.width / 2;
+ this.zoomCenterY = this._centerImg.height / 2;
+ }
+ this.panX = this.panY = 0;
+ }
+
+ this.render();
+ },
+
+ _setZoomCenterXAttr: function(value){
+ if(value != this.zoomCenterX){
+ if(this._centerImg && this._centerImg._loaded){
+ value = Math.min(this._centerImg.width, value);
+ }
+ this.zoomCenterX = Math.max(0, Math.round(value));
+ }
+ },
+
+ _setZoomCenterYAttr: function(value){
+ if(value != this.zoomCenterY){
+ if(this._centerImg && this._centerImg._loaded){
+ value = Math.min(this._centerImg.height, value);
+ }
+ this.zoomCenterY = Math.max(0, Math.round(value));
+ }
+ },
+
+ _setZoomCenterAttr: function(value){
+ if(value.x != this.zoomCenterX || value.y != this.zoomCenterY){
+ this.set("zoomCenterX", value.x);
+ this.set("zoomCenterY", value.y);
+ this.render();
+ }
+ },
+
+ _setAnimatedZoomAttr: function(amount){
+ if(this._anim && this._anim.status() == "playing"){
+ return;
+ }
+
+ this._anim = new dojo.Animation({
+ curve: [this.zoom, amount],
+ onAnimate: this._updateAnimatedZoom,
+ onEnd: this._onAnimEnd
+ });
+
+ this._anim.play();
+ },
+
+ _updateAnimatedZoom: function(amount){
+ this._setZoomAttr(amount);
+ },
+
+ _setCenterUrlAttr: function(urlOrObj){
+ this._setImage("center", urlOrObj);
+ },
+ _setLeftUrlAttr: function(urlOrObj){
+ this._setImage("left", urlOrObj);
+ },
+ _setRightUrlAttr: function(urlOrObj){
+ this._setImage("right", urlOrObj);
+ },
+
+ _setImage: function(name, urlOrObj){
+ var smallUrl = null;
+
+ var largeUrl = null;
+
+ if(dojo.isString(urlOrObj)){
+ // If the argument is a string, then just load the large url
+ largeUrl = urlOrObj;
+ }else{
+ largeUrl = urlOrObj.large;
+ smallUrl = urlOrObj.small;
+ }
+
+ if(this["_" + name + "Img"] && this["_" + name + "Img"]._src == largeUrl){
+ // Identical URL, ignore it
+ return;
+ }
+
+ // Just do the large image for now
+ var largeImg = this["_" + name + "Img"] = new Image();
+ largeImg._type = name;
+ largeImg._loaded = false;
+ largeImg._src = largeUrl;
+ largeImg._conn = dojo.connect(largeImg, "onload", this.handleLoad);
+
+ if(smallUrl){
+ // If a url to a small version of the image has been provided,
+ // load that image first.
+ var smallImg = this["_" + name + "SmallImg"] = new Image();
+ smallImg._type = name;
+ smallImg._loaded = false;
+ smallImg._conn = dojo.connect(smallImg, "onload", this.handleLoad);
+ smallImg._isSmall = true;
+ smallImg._src = smallUrl;
+ smallImg.src = smallUrl;
+ }
+
+ // It's important that the large url's src is set after the small image
+ // to ensure it's loaded second.
+ largeImg.src = largeUrl;
+ },
+
+ handleLoad: function(evt){
+ // summary:
+ // Handles the loading of an image, both the large and small
+ // versions. A render is triggered as a result of each image load.
+
+ var img = evt.target;
+ img._loaded = true;
+
+ dojo.disconnect(img._conn);
+
+ var type = img._type;
+
+ switch(type){
+ case "center":
+ this.zoomCenterX = img.width / 2;
+ this.zoomCenterY = img.height / 2;
+ break;
+ }
+
+ var height = img.height;
+ var width = img.width;
+
+ if(width / this.size.w < height / this.size.h){
+ // Fit the height to the height of the canvas
+ img._baseHeight = this.canvas.height;
+ img._baseWidth = width / (height / this.size.h);
+ }else{
+ // Fix the width to the width of the canvas
+ img._baseWidth = this.canvas.width;
+ img._baseHeight = height / (width / this.size.w);
+ }
+ img._centerX = width / 2;
+ img._centerY = height / 2;
+
+ this.render();
+
+ this.onLoad(img._type, img._src, img._isSmall);
+ },
+
+ onLoad: function(type, url, isSmall){
+ // summary:
+ // Dummy function that is called whenever an image loads.
+ // type: String
+ // The position of the image that has loaded, either
+ // "center", "left" or "right"
+ // url: String
+ // The src of the image
+ // isSmall: Boolean
+ // True if it is a small version of the image that has loaded,
+ // false otherwise.
+ }
+});
+
+}
+
+}};});
diff --git a/js/dojo-1.6/dojox/mobile/app/List.js b/js/dojo-1.6/dojox/mobile/app/List.js
new file mode 100644
index 0000000..b2bcc0b
--- /dev/null
+++ b/js/dojo-1.6/dojox/mobile/app/List.js
@@ -0,0 +1,656 @@
+/*
+ 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
+*/
+
+
+if(!dojo._hasResource["dojox.mobile.app.List"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.mobile.app.List"] = true;
+dojo.provide("dojox.mobile.app.List");
+dojo.experimental("dojox.mobile.app.List");
+
+dojo.require("dojo.string");
+dojo.require("dijit._WidgetBase");
+
+(function(){
+
+ var templateCache = {};
+
+ dojo.declare("dojox.mobile.app.List", dijit._WidgetBase, {
+ // summary:
+ // A templated list widget. Given a simple array of data objects
+ // and a HTML template, it renders a list of elements, with
+ // support for a swipe delete action. An optional template
+ // can be provided for when the list is empty.
+
+ // items: Array
+ // The array of data items that will be rendered.
+ items: null,
+
+ // itemTemplate: String
+ // The URL to the HTML file containing the markup for each individual
+ // data item.
+ itemTemplate: "",
+
+ // emptyTemplate: String
+ // The URL to the HTML file containing the HTML to display if there
+ // are no data items. This is optional.
+ emptyTemplate: "",
+
+ // dividerTemplate: String
+ // The URL to the HTML file containing the markup for the dividers
+ // between groups of list items
+ dividerTemplate: "",
+
+ // dividerFunction: Function
+ // Function to create divider elements. This should return a divider
+ // value for each item in the list
+ dividerFunction: null,
+
+ // labelDelete: String
+ // The label to display for the Delete button
+ labelDelete: "Delete",
+
+ // labelCancel: String
+ // The label to display for the Cancel button
+ labelCancel: "Cancel",
+
+ // controller: Object
+ //
+ controller: null,
+
+ // autoDelete: Boolean
+ autoDelete: true,
+
+ // enableDelete: Boolean
+ enableDelete: true,
+
+ // enableHold: Boolean
+ enableHold: true,
+
+ // formatters: Object
+ // A name/value map of functions used to format data for display
+ formatters: null,
+
+ // _templateLoadCount: Number
+ // The number of templates remaining to load before the list renders.
+ _templateLoadCount: 0,
+
+ // _mouseDownPos: Object
+ // The coordinates of where a mouseDown event was detected
+ _mouseDownPos: null,
+
+ baseClass: "list",
+
+ constructor: function(){
+ this._checkLoadComplete = dojo.hitch(this, this._checkLoadComplete);
+ this._replaceToken = dojo.hitch(this, this._replaceToken);
+ this._postDeleteAnim = dojo.hitch(this, this._postDeleteAnim);
+ },
+
+ postCreate: function(){
+
+ var _this = this;
+
+ if(this.emptyTemplate){
+ this._templateLoadCount++;
+ }
+ if(this.itemTemplate){
+ this._templateLoadCount++;
+ }
+ if(this.dividerTemplate){
+ this._templateLoadCount++;
+ }
+
+ this.connect(this.domNode, "onmousedown", function(event){
+ var touch = event;
+ if(event.targetTouches && event.targetTouches.length > 0){
+ touch = event.targetTouches[0];
+ }
+
+ // Find the node that was tapped/clicked
+ var rowNode = _this._getRowNode(event.target);
+
+ if(rowNode){
+ // Add the rows data to the event so it can be picked up
+ // by any listeners
+ _this._setDataInfo(rowNode, event);
+
+ // Select and highlight the row
+ _this._selectRow(rowNode);
+
+ // Record the position that was tapped
+ _this._mouseDownPos = {
+ x: touch.pageX,
+ y: touch.pageY
+ };
+ _this._dragThreshold = null;
+ }
+ });
+
+ this.connect(this.domNode, "onmouseup", function(event){
+ // When the mouse/finger comes off the list,
+ // call the onSelect function and deselect the row.
+ if(event.targetTouches && event.targetTouches.length > 0){
+ event = event.targetTouches[0];
+ }
+ var rowNode = _this._getRowNode(event.target);
+
+ if(rowNode){
+
+ _this._setDataInfo(rowNode, event);
+
+ if(_this._selectedRow){
+ _this.onSelect(rowNode._data, rowNode._idx, rowNode);
+ }
+
+ this._deselectRow();
+ }
+ });
+
+ // If swipe-to-delete is enabled, listen for the mouse moving
+ if(this.enableDelete){
+ this.connect(this.domNode, "mousemove", function(event){
+ dojo.stopEvent(event);
+ if(!_this._selectedRow){
+ return;
+ }
+ var rowNode = _this._getRowNode(event.target);
+
+ // Still check for enableDelete in case it's changed after
+ // this listener is added.
+ if(_this.enableDelete && rowNode && !_this._deleting){
+ _this.handleDrag(event);
+ }
+ });
+ }
+
+ // Put the data and index onto each onclick event.
+ this.connect(this.domNode, "onclick", function(event){
+ if(event.touches && event.touches.length > 0){
+ event = event.touches[0];
+ }
+ var rowNode = _this._getRowNode(event.target, true);
+
+ if(rowNode){
+ _this._setDataInfo(rowNode, event);
+ }
+ });
+
+ // If the mouse or finger moves off the selected row,
+ // deselect it.
+ this.connect(this.domNode, "mouseout", function(event){
+ if(event.touches && event.touches.length > 0){
+ event = event.touches[0];
+ }
+ if(event.target == _this._selectedRow){
+ _this._deselectRow();
+ }
+ });
+
+ // If no item template has been provided, it is an error.
+ if(!this.itemTemplate){
+ throw Error("An item template must be provided to " + this.declaredClass);
+ }
+
+ // Load the item template
+ this._loadTemplate(this.itemTemplate, "itemTemplate", this._checkLoadComplete);
+
+ if(this.emptyTemplate){
+ // If the optional empty template has been provided, load it.
+ this._loadTemplate(this.emptyTemplate, "emptyTemplate", this._checkLoadComplete);
+ }
+
+ if(this.dividerTemplate){
+ this._loadTemplate(this.dividerTemplate, "dividerTemplate", this._checkLoadComplete);
+ }
+ },
+
+ handleDrag: function(event){
+ // summary:
+ // Handles rows being swiped for deletion.
+ var touch = event;
+ if(event.targetTouches && event.targetTouches.length > 0){
+ touch = event.targetTouches[0];
+ }
+
+ // Get the distance that the mouse or finger has moved since
+ // beginning the swipe action.
+ var diff = touch.pageX - this._mouseDownPos.x;
+
+ var absDiff = Math.abs(diff);
+ if(absDiff > 10 && !this._dragThreshold){
+ // Make the user drag the row 60% of the width to remove it
+ this._dragThreshold = dojo.marginBox(this._selectedRow).w * 0.6;
+ if(!this.autoDelete){
+ this.createDeleteButtons(this._selectedRow);
+ }
+ }
+
+ this._selectedRow.style.left = (absDiff > 10 ? diff : 0) + "px";
+
+ // If the user has dragged the row more than the threshold, slide
+ // it off the screen in preparation for deletion.
+ if(this._dragThreshold && this._dragThreshold < absDiff){
+ this.preDelete(diff);
+ }
+ },
+
+ handleDragCancel: function(){
+ // summary:
+ // Handle a drag action being cancelled, for whatever reason.
+ // Reset handles, remove CSS classes etc.
+ if(this._deleting){
+ return;
+ }
+ dojo.removeClass(this._selectedRow, "hold");
+ this._selectedRow.style.left = 0;
+ this._mouseDownPos = null;
+ this._dragThreshold = null;
+
+ this._deleteBtns && dojo.style(this._deleteBtns, "display", "none");
+ },
+
+ preDelete: function(currentLeftPos){
+ // summary:
+ // Slides the row offscreen before it is deleted
+
+ // TODO: do this with CSS3!
+ var self = this;
+
+ this._deleting = true;
+
+ dojo.animateProperty({
+ node: this._selectedRow,
+ duration: 400,
+ properties: {
+ left: {
+ end: currentLeftPos +
+ ((currentLeftPos > 0 ? 1 : -1) * this._dragThreshold * 0.8)
+ }
+ },
+ onEnd: dojo.hitch(this, function(){
+ if(this.autoDelete){
+ this.deleteRow(this._selectedRow);
+ }
+ })
+ }).play();
+ },
+
+ deleteRow: function(row){
+
+ // First make the row invisible
+ // Put it back where it came from
+ dojo.style(row, {
+ visibility: "hidden",
+ minHeight: "0px"
+ });
+ dojo.removeClass(row, "hold");
+
+ this._deleteAnimConn =
+ this.connect(row, "webkitAnimationEnd", this._postDeleteAnim);
+
+ dojo.addClass(row, "collapsed");
+ },
+
+ _postDeleteAnim: function(event){
+ // summary:
+ // Completes the deletion of a row.
+
+ if(this._deleteAnimConn){
+ this.disconnect(this._deleteAnimConn);
+ this._deleteAnimConn = null;
+ }
+
+ var row = this._selectedRow;
+ var sibling = row.nextSibling;
+ var prevSibling = row.previousSibling;
+
+ // If the previous node is a divider and either this is
+ // the last element in the list, or the next node is
+ // also a divider, remove the divider for the deleted section.
+ if(prevSibling && prevSibling._isDivider){
+ if(!sibling || sibling._isDivider){
+ prevSibling.parentNode.removeChild(prevSibling);
+ }
+ }
+
+ row.parentNode.removeChild(row);
+ this.onDelete(row._data, row._idx, this.items);
+
+ // Decrement the index of each following row
+ while(sibling){
+ if(sibling._idx){
+ sibling._idx--;
+ }
+ sibling = sibling.nextSibling;
+ }
+
+ dojo.destroy(row);
+
+ // Fix up the 'first' and 'last' CSS classes on the rows
+ dojo.query("> *:not(.buttons)", this.domNode).forEach(this.applyClass);
+
+ this._deleting = false;
+ this._deselectRow();
+ },
+
+ createDeleteButtons: function(aroundNode){
+ // summary:
+ // Creates the two buttons displayed when confirmation is
+ // required before deletion of a row.
+ // aroundNode:
+ // The DOM node of the row about to be deleted.
+ var mb = dojo.marginBox(aroundNode);
+ var pos = dojo._abs(aroundNode, true);
+
+ if(!this._deleteBtns){
+ // Create the delete buttons.
+ this._deleteBtns = dojo.create("div",{
+ "class": "buttons"
+ }, this.domNode);
+
+ this.buttons = [];
+
+ this.buttons.push(new dojox.mobile.Button({
+ btnClass: "mblRedButton",
+ label: this.labelDelete
+ }));
+ this.buttons.push(new dojox.mobile.Button({
+ btnClass: "mblBlueButton",
+ label: this.labelCancel
+ }));
+
+ dojo.place(this.buttons[0].domNode, this._deleteBtns);
+ dojo.place(this.buttons[1].domNode, this._deleteBtns);
+
+ dojo.addClass(this.buttons[0].domNode, "deleteBtn");
+ dojo.addClass(this.buttons[1].domNode, "cancelBtn");
+
+ this._handleButtonClick = dojo.hitch(this._handleButtonClick);
+ this.connect(this._deleteBtns, "onclick", this._handleButtonClick);
+ }
+ dojo.removeClass(this._deleteBtns, "fade out fast");
+ dojo.style(this._deleteBtns, {
+ display: "",
+ width: mb.w + "px",
+ height: mb.h + "px",
+ top: (aroundNode.offsetTop) + "px",
+ left: "0px"
+ });
+ },
+
+ onDelete: function(data, index, array){
+ // summary:
+ // Called when a row is deleted
+ // data:
+ // The data related to the row being deleted
+ // index:
+ // The index of the data in the total array
+ // array:
+ // The array of data used.
+
+ array.splice(index, 1);
+
+ // If the data is empty, rerender in case an emptyTemplate has
+ // been provided
+ if(array.length < 1){
+ this.render();
+ }
+ },
+
+ cancelDelete: function(){
+ // summary:
+ // Cancels the deletion of a row.
+ this._deleting = false;
+ this.handleDragCancel();
+ },
+
+ _handleButtonClick: function(event){
+ // summary:
+ // Handles the click of one of the deletion buttons, either to
+ // delete the row or to cancel the deletion.
+ if(event.touches && event.touches.length > 0){
+ event = event.touches[0];
+ }
+ var node = event.target;
+ if(dojo.hasClass(node, "deleteBtn")){
+ this.deleteRow(this._selectedRow);
+ }else if(dojo.hasClass(node, "cancelBtn")){
+ this.cancelDelete();
+ }else{
+ return;
+ }
+ dojo.addClass(this._deleteBtns, "fade out");
+ },
+
+ applyClass: function(node, idx, array){
+ // summary:
+ // Applies the 'first' and 'last' CSS classes to the relevant
+ // rows.
+
+ dojo.removeClass(node, "first last");
+ if(idx == 0){
+ dojo.addClass(node, "first");
+ }
+ if(idx == array.length - 1){
+ dojo.addClass(node, "last");
+ }
+ },
+
+ _setDataInfo: function(rowNode, event){
+ // summary:
+ // Attaches the data item and index for each row to any event
+ // that occurs on that row.
+ event.item = rowNode._data;
+ event.index = rowNode._idx;
+ },
+
+ onSelect: function(data, index, rowNode){
+ // summary:
+ // Dummy function that is called when a row is tapped
+ },
+
+ _selectRow: function(row){
+ // summary:
+ // Selects a row, applies the relevant CSS classes.
+ if(this._deleting && this._selectedRow && row != this._selectedRow){
+ this.cancelDelete();
+ }
+
+ if(!dojo.hasClass(row, "row")){
+ return;
+ }
+ if(this.enableHold || this.enableDelete){
+ dojo.addClass(row, "hold");
+ }
+ this._selectedRow = row;
+ },
+
+ _deselectRow: function(){
+ // summary:
+ // Deselects a row, and cancels any drag actions that were
+ // occurring.
+ if(!this._selectedRow || this._deleting){
+ return;
+ }
+ this.handleDragCancel();
+ dojo.removeClass(this._selectedRow, "hold");
+ this._selectedRow = null;
+ },
+
+ _getRowNode: function(fromNode, ignoreNoClick){
+ // summary:
+ // Gets the DOM node of the row that is equal to or the parent
+ // of the node passed to this function.
+ while(fromNode && !fromNode._data && fromNode != this.domNode){
+ if(!ignoreNoClick && dojo.hasClass(fromNode, "noclick")){
+ return null;
+ }
+ fromNode = fromNode.parentNode;
+ }
+ return fromNode == this.domNode ? null : fromNode;
+ },
+
+ applyTemplate: function(template, data){
+ return dojo._toDom(dojo.string.substitute(
+ template, data, this._replaceToken, this.formatters || this));
+ },
+
+ render: function(){
+ // summary:
+ // Renders the list.
+
+ // Delete all existing nodes, except the deletion buttons.
+ dojo.query("> *:not(.buttons)", this.domNode).forEach(dojo.destroy);
+
+ // If there is no data, and an empty template has been provided,
+ // render it.
+ if(this.items.length < 1 && this.emptyTemplate){
+ dojo.place(dojo._toDom(this.emptyTemplate), this.domNode, "first");
+ }else{
+ this.domNode.appendChild(this._renderRange(0, this.items.length));
+ }
+ if(dojo.hasClass(this.domNode.parentNode, "mblRoundRect")){
+ dojo.addClass(this.domNode.parentNode, "mblRoundRectList")
+ }
+
+ var divs = dojo.query("> .row", this.domNode);
+ if(divs.length > 0){
+ dojo.addClass(divs[0], "first");
+ dojo.addClass(divs[divs.length - 1], "last");
+ }
+ },
+
+ _renderRange: function(startIdx, endIdx){
+
+ var rows = [];
+ var row, i;
+ var frag = document.createDocumentFragment();
+ startIdx = Math.max(0, startIdx);
+ endIdx = Math.min(endIdx, this.items.length);
+
+ for(i = startIdx; i < endIdx; i++){
+ // Create a document fragment containing the templated row
+ row = this.applyTemplate(this.itemTemplate, this.items[i]);
+ dojo.addClass(row, 'row');
+ row._data = this.items[i];
+ row._idx = i;
+ rows.push(row);
+ }
+ if(!this.dividerFunction || !this.dividerTemplate){
+ for(i = startIdx; i < endIdx; i++){
+ rows[i]._data = this.items[i];
+ rows[i]._idx = i;
+ frag.appendChild(rows[i]);
+ }
+ }else{
+ var prevDividerValue = null;
+ var dividerValue;
+ var divider;
+ for(i = startIdx; i < endIdx; i++){
+ rows[i]._data = this.items[i];
+ rows[i]._idx = i;
+
+ dividerValue = this.dividerFunction(this.items[i]);
+ if(dividerValue && dividerValue != prevDividerValue){
+ divider = this.applyTemplate(this.dividerTemplate, {
+ label: dividerValue,
+ item: this.items[i]
+ });
+ divider._isDivider = true;
+ frag.appendChild(divider);
+ prevDividerValue = dividerValue;
+ }
+ frag.appendChild(rows[i]);
+ }
+ }
+ return frag;
+ },
+
+ _replaceToken: function(value, key){
+ if(key.charAt(0) == '!'){ value = dojo.getObject(key.substr(1), false, _this); }
+ if(typeof value == "undefined"){ return ""; } // a debugging aide
+ if(value == null){ return ""; }
+
+ // Substitution keys beginning with ! will skip the transform step,
+ // in case a user wishes to insert unescaped markup, e.g. ${!foo}
+ return key.charAt(0) == "!" ? value :
+ // Safer substitution, see heading "Attribute values" in
+ // http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2
+ value.toString().replace(/"/g,"&quot;"); //TODO: add &amp? use encodeXML method?
+
+ },
+
+ _checkLoadComplete: function(){
+ // summary:
+ // Checks if all templates have loaded
+ this._templateLoadCount--;
+
+ if(this._templateLoadCount < 1 && this.get("items")){
+ this.render();
+ }
+ },
+
+ _loadTemplate: function(url, thisAttr, callback){
+ // summary:
+ // Loads a template
+ if(!url){
+ callback();
+ return;
+ }
+
+ if(templateCache[url]){
+ this.set(thisAttr, templateCache[url]);
+ callback();
+ }else{
+ var _this = this;
+
+ dojo.xhrGet({
+ url: url,
+ sync: false,
+ handleAs: "text",
+ load: function(text){
+ templateCache[url] = dojo.trim(text);
+ _this.set(thisAttr, templateCache[url]);
+ callback();
+ }
+ });
+ }
+ },
+
+
+ _setFormattersAttr: function(formatters){
+ // summary:
+ // Sets the data items, and causes a rerender of the list
+ this.formatters = formatters;
+ },
+
+ _setItemsAttr: function(items){
+ // summary:
+ // Sets the data items, and causes a rerender of the list
+
+ this.items = items || [];
+
+ if(this._templateLoadCount < 1 && items){
+ this.render();
+ }
+ },
+
+ destroy: function(){
+ if(this.buttons){
+ dojo.forEach(this.buttons, function(button){
+ button.destroy();
+ });
+ this.buttons = null;
+ }
+
+ this.inherited(arguments);
+ }
+
+ });
+
+})();
+
+}
diff --git a/js/dojo-1.6/dojox/mobile/app/List.xd.js b/js/dojo-1.6/dojox/mobile/app/List.xd.js
new file mode 100644
index 0000000..5b8481c
--- /dev/null
+++ b/js/dojo-1.6/dojox/mobile/app/List.xd.js
@@ -0,0 +1,662 @@
+/*
+ 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
+*/
+
+
+dojo._xdResourceLoaded(function(dojo, dijit, dojox){
+return {depends: [["provide", "dojox.mobile.app.List"],
+["require", "dojo.string"],
+["require", "dijit._WidgetBase"]],
+defineResource: function(dojo, dijit, dojox){if(!dojo._hasResource["dojox.mobile.app.List"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.mobile.app.List"] = true;
+dojo.provide("dojox.mobile.app.List");
+dojo.experimental("dojox.mobile.app.List");
+
+dojo.require("dojo.string");
+dojo.require("dijit._WidgetBase");
+
+(function(){
+
+ var templateCache = {};
+
+ dojo.declare("dojox.mobile.app.List", dijit._WidgetBase, {
+ // summary:
+ // A templated list widget. Given a simple array of data objects
+ // and a HTML template, it renders a list of elements, with
+ // support for a swipe delete action. An optional template
+ // can be provided for when the list is empty.
+
+ // items: Array
+ // The array of data items that will be rendered.
+ items: null,
+
+ // itemTemplate: String
+ // The URL to the HTML file containing the markup for each individual
+ // data item.
+ itemTemplate: "",
+
+ // emptyTemplate: String
+ // The URL to the HTML file containing the HTML to display if there
+ // are no data items. This is optional.
+ emptyTemplate: "",
+
+ // dividerTemplate: String
+ // The URL to the HTML file containing the markup for the dividers
+ // between groups of list items
+ dividerTemplate: "",
+
+ // dividerFunction: Function
+ // Function to create divider elements. This should return a divider
+ // value for each item in the list
+ dividerFunction: null,
+
+ // labelDelete: String
+ // The label to display for the Delete button
+ labelDelete: "Delete",
+
+ // labelCancel: String
+ // The label to display for the Cancel button
+ labelCancel: "Cancel",
+
+ // controller: Object
+ //
+ controller: null,
+
+ // autoDelete: Boolean
+ autoDelete: true,
+
+ // enableDelete: Boolean
+ enableDelete: true,
+
+ // enableHold: Boolean
+ enableHold: true,
+
+ // formatters: Object
+ // A name/value map of functions used to format data for display
+ formatters: null,
+
+ // _templateLoadCount: Number
+ // The number of templates remaining to load before the list renders.
+ _templateLoadCount: 0,
+
+ // _mouseDownPos: Object
+ // The coordinates of where a mouseDown event was detected
+ _mouseDownPos: null,
+
+ baseClass: "list",
+
+ constructor: function(){
+ this._checkLoadComplete = dojo.hitch(this, this._checkLoadComplete);
+ this._replaceToken = dojo.hitch(this, this._replaceToken);
+ this._postDeleteAnim = dojo.hitch(this, this._postDeleteAnim);
+ },
+
+ postCreate: function(){
+
+ var _this = this;
+
+ if(this.emptyTemplate){
+ this._templateLoadCount++;
+ }
+ if(this.itemTemplate){
+ this._templateLoadCount++;
+ }
+ if(this.dividerTemplate){
+ this._templateLoadCount++;
+ }
+
+ this.connect(this.domNode, "onmousedown", function(event){
+ var touch = event;
+ if(event.targetTouches && event.targetTouches.length > 0){
+ touch = event.targetTouches[0];
+ }
+
+ // Find the node that was tapped/clicked
+ var rowNode = _this._getRowNode(event.target);
+
+ if(rowNode){
+ // Add the rows data to the event so it can be picked up
+ // by any listeners
+ _this._setDataInfo(rowNode, event);
+
+ // Select and highlight the row
+ _this._selectRow(rowNode);
+
+ // Record the position that was tapped
+ _this._mouseDownPos = {
+ x: touch.pageX,
+ y: touch.pageY
+ };
+ _this._dragThreshold = null;
+ }
+ });
+
+ this.connect(this.domNode, "onmouseup", function(event){
+ // When the mouse/finger comes off the list,
+ // call the onSelect function and deselect the row.
+ if(event.targetTouches && event.targetTouches.length > 0){
+ event = event.targetTouches[0];
+ }
+ var rowNode = _this._getRowNode(event.target);
+
+ if(rowNode){
+
+ _this._setDataInfo(rowNode, event);
+
+ if(_this._selectedRow){
+ _this.onSelect(rowNode._data, rowNode._idx, rowNode);
+ }
+
+ this._deselectRow();
+ }
+ });
+
+ // If swipe-to-delete is enabled, listen for the mouse moving
+ if(this.enableDelete){
+ this.connect(this.domNode, "mousemove", function(event){
+ dojo.stopEvent(event);
+ if(!_this._selectedRow){
+ return;
+ }
+ var rowNode = _this._getRowNode(event.target);
+
+ // Still check for enableDelete in case it's changed after
+ // this listener is added.
+ if(_this.enableDelete && rowNode && !_this._deleting){
+ _this.handleDrag(event);
+ }
+ });
+ }
+
+ // Put the data and index onto each onclick event.
+ this.connect(this.domNode, "onclick", function(event){
+ if(event.touches && event.touches.length > 0){
+ event = event.touches[0];
+ }
+ var rowNode = _this._getRowNode(event.target, true);
+
+ if(rowNode){
+ _this._setDataInfo(rowNode, event);
+ }
+ });
+
+ // If the mouse or finger moves off the selected row,
+ // deselect it.
+ this.connect(this.domNode, "mouseout", function(event){
+ if(event.touches && event.touches.length > 0){
+ event = event.touches[0];
+ }
+ if(event.target == _this._selectedRow){
+ _this._deselectRow();
+ }
+ });
+
+ // If no item template has been provided, it is an error.
+ if(!this.itemTemplate){
+ throw Error("An item template must be provided to " + this.declaredClass);
+ }
+
+ // Load the item template
+ this._loadTemplate(this.itemTemplate, "itemTemplate", this._checkLoadComplete);
+
+ if(this.emptyTemplate){
+ // If the optional empty template has been provided, load it.
+ this._loadTemplate(this.emptyTemplate, "emptyTemplate", this._checkLoadComplete);
+ }
+
+ if(this.dividerTemplate){
+ this._loadTemplate(this.dividerTemplate, "dividerTemplate", this._checkLoadComplete);
+ }
+ },
+
+ handleDrag: function(event){
+ // summary:
+ // Handles rows being swiped for deletion.
+ var touch = event;
+ if(event.targetTouches && event.targetTouches.length > 0){
+ touch = event.targetTouches[0];
+ }
+
+ // Get the distance that the mouse or finger has moved since
+ // beginning the swipe action.
+ var diff = touch.pageX - this._mouseDownPos.x;
+
+ var absDiff = Math.abs(diff);
+ if(absDiff > 10 && !this._dragThreshold){
+ // Make the user drag the row 60% of the width to remove it
+ this._dragThreshold = dojo.marginBox(this._selectedRow).w * 0.6;
+ if(!this.autoDelete){
+ this.createDeleteButtons(this._selectedRow);
+ }
+ }
+
+ this._selectedRow.style.left = (absDiff > 10 ? diff : 0) + "px";
+
+ // If the user has dragged the row more than the threshold, slide
+ // it off the screen in preparation for deletion.
+ if(this._dragThreshold && this._dragThreshold < absDiff){
+ this.preDelete(diff);
+ }
+ },
+
+ handleDragCancel: function(){
+ // summary:
+ // Handle a drag action being cancelled, for whatever reason.
+ // Reset handles, remove CSS classes etc.
+ if(this._deleting){
+ return;
+ }
+ dojo.removeClass(this._selectedRow, "hold");
+ this._selectedRow.style.left = 0;
+ this._mouseDownPos = null;
+ this._dragThreshold = null;
+
+ this._deleteBtns && dojo.style(this._deleteBtns, "display", "none");
+ },
+
+ preDelete: function(currentLeftPos){
+ // summary:
+ // Slides the row offscreen before it is deleted
+
+ // TODO: do this with CSS3!
+ var self = this;
+
+ this._deleting = true;
+
+ dojo.animateProperty({
+ node: this._selectedRow,
+ duration: 400,
+ properties: {
+ left: {
+ end: currentLeftPos +
+ ((currentLeftPos > 0 ? 1 : -1) * this._dragThreshold * 0.8)
+ }
+ },
+ onEnd: dojo.hitch(this, function(){
+ if(this.autoDelete){
+ this.deleteRow(this._selectedRow);
+ }
+ })
+ }).play();
+ },
+
+ deleteRow: function(row){
+
+ // First make the row invisible
+ // Put it back where it came from
+ dojo.style(row, {
+ visibility: "hidden",
+ minHeight: "0px"
+ });
+ dojo.removeClass(row, "hold");
+
+ this._deleteAnimConn =
+ this.connect(row, "webkitAnimationEnd", this._postDeleteAnim);
+
+ dojo.addClass(row, "collapsed");
+ },
+
+ _postDeleteAnim: function(event){
+ // summary:
+ // Completes the deletion of a row.
+
+ if(this._deleteAnimConn){
+ this.disconnect(this._deleteAnimConn);
+ this._deleteAnimConn = null;
+ }
+
+ var row = this._selectedRow;
+ var sibling = row.nextSibling;
+ var prevSibling = row.previousSibling;
+
+ // If the previous node is a divider and either this is
+ // the last element in the list, or the next node is
+ // also a divider, remove the divider for the deleted section.
+ if(prevSibling && prevSibling._isDivider){
+ if(!sibling || sibling._isDivider){
+ prevSibling.parentNode.removeChild(prevSibling);
+ }
+ }
+
+ row.parentNode.removeChild(row);
+ this.onDelete(row._data, row._idx, this.items);
+
+ // Decrement the index of each following row
+ while(sibling){
+ if(sibling._idx){
+ sibling._idx--;
+ }
+ sibling = sibling.nextSibling;
+ }
+
+ dojo.destroy(row);
+
+ // Fix up the 'first' and 'last' CSS classes on the rows
+ dojo.query("> *:not(.buttons)", this.domNode).forEach(this.applyClass);
+
+ this._deleting = false;
+ this._deselectRow();
+ },
+
+ createDeleteButtons: function(aroundNode){
+ // summary:
+ // Creates the two buttons displayed when confirmation is
+ // required before deletion of a row.
+ // aroundNode:
+ // The DOM node of the row about to be deleted.
+ var mb = dojo.marginBox(aroundNode);
+ var pos = dojo._abs(aroundNode, true);
+
+ if(!this._deleteBtns){
+ // Create the delete buttons.
+ this._deleteBtns = dojo.create("div",{
+ "class": "buttons"
+ }, this.domNode);
+
+ this.buttons = [];
+
+ this.buttons.push(new dojox.mobile.Button({
+ btnClass: "mblRedButton",
+ label: this.labelDelete
+ }));
+ this.buttons.push(new dojox.mobile.Button({
+ btnClass: "mblBlueButton",
+ label: this.labelCancel
+ }));
+
+ dojo.place(this.buttons[0].domNode, this._deleteBtns);
+ dojo.place(this.buttons[1].domNode, this._deleteBtns);
+
+ dojo.addClass(this.buttons[0].domNode, "deleteBtn");
+ dojo.addClass(this.buttons[1].domNode, "cancelBtn");
+
+ this._handleButtonClick = dojo.hitch(this._handleButtonClick);
+ this.connect(this._deleteBtns, "onclick", this._handleButtonClick);
+ }
+ dojo.removeClass(this._deleteBtns, "fade out fast");
+ dojo.style(this._deleteBtns, {
+ display: "",
+ width: mb.w + "px",
+ height: mb.h + "px",
+ top: (aroundNode.offsetTop) + "px",
+ left: "0px"
+ });
+ },
+
+ onDelete: function(data, index, array){
+ // summary:
+ // Called when a row is deleted
+ // data:
+ // The data related to the row being deleted
+ // index:
+ // The index of the data in the total array
+ // array:
+ // The array of data used.
+
+ array.splice(index, 1);
+
+ // If the data is empty, rerender in case an emptyTemplate has
+ // been provided
+ if(array.length < 1){
+ this.render();
+ }
+ },
+
+ cancelDelete: function(){
+ // summary:
+ // Cancels the deletion of a row.
+ this._deleting = false;
+ this.handleDragCancel();
+ },
+
+ _handleButtonClick: function(event){
+ // summary:
+ // Handles the click of one of the deletion buttons, either to
+ // delete the row or to cancel the deletion.
+ if(event.touches && event.touches.length > 0){
+ event = event.touches[0];
+ }
+ var node = event.target;
+ if(dojo.hasClass(node, "deleteBtn")){
+ this.deleteRow(this._selectedRow);
+ }else if(dojo.hasClass(node, "cancelBtn")){
+ this.cancelDelete();
+ }else{
+ return;
+ }
+ dojo.addClass(this._deleteBtns, "fade out");
+ },
+
+ applyClass: function(node, idx, array){
+ // summary:
+ // Applies the 'first' and 'last' CSS classes to the relevant
+ // rows.
+
+ dojo.removeClass(node, "first last");
+ if(idx == 0){
+ dojo.addClass(node, "first");
+ }
+ if(idx == array.length - 1){
+ dojo.addClass(node, "last");
+ }
+ },
+
+ _setDataInfo: function(rowNode, event){
+ // summary:
+ // Attaches the data item and index for each row to any event
+ // that occurs on that row.
+ event.item = rowNode._data;
+ event.index = rowNode._idx;
+ },
+
+ onSelect: function(data, index, rowNode){
+ // summary:
+ // Dummy function that is called when a row is tapped
+ },
+
+ _selectRow: function(row){
+ // summary:
+ // Selects a row, applies the relevant CSS classes.
+ if(this._deleting && this._selectedRow && row != this._selectedRow){
+ this.cancelDelete();
+ }
+
+ if(!dojo.hasClass(row, "row")){
+ return;
+ }
+ if(this.enableHold || this.enableDelete){
+ dojo.addClass(row, "hold");
+ }
+ this._selectedRow = row;
+ },
+
+ _deselectRow: function(){
+ // summary:
+ // Deselects a row, and cancels any drag actions that were
+ // occurring.
+ if(!this._selectedRow || this._deleting){
+ return;
+ }
+ this.handleDragCancel();
+ dojo.removeClass(this._selectedRow, "hold");
+ this._selectedRow = null;
+ },
+
+ _getRowNode: function(fromNode, ignoreNoClick){
+ // summary:
+ // Gets the DOM node of the row that is equal to or the parent
+ // of the node passed to this function.
+ while(fromNode && !fromNode._data && fromNode != this.domNode){
+ if(!ignoreNoClick && dojo.hasClass(fromNode, "noclick")){
+ return null;
+ }
+ fromNode = fromNode.parentNode;
+ }
+ return fromNode == this.domNode ? null : fromNode;
+ },
+
+ applyTemplate: function(template, data){
+ return dojo._toDom(dojo.string.substitute(
+ template, data, this._replaceToken, this.formatters || this));
+ },
+
+ render: function(){
+ // summary:
+ // Renders the list.
+
+ // Delete all existing nodes, except the deletion buttons.
+ dojo.query("> *:not(.buttons)", this.domNode).forEach(dojo.destroy);
+
+ // If there is no data, and an empty template has been provided,
+ // render it.
+ if(this.items.length < 1 && this.emptyTemplate){
+ dojo.place(dojo._toDom(this.emptyTemplate), this.domNode, "first");
+ }else{
+ this.domNode.appendChild(this._renderRange(0, this.items.length));
+ }
+ if(dojo.hasClass(this.domNode.parentNode, "mblRoundRect")){
+ dojo.addClass(this.domNode.parentNode, "mblRoundRectList")
+ }
+
+ var divs = dojo.query("> .row", this.domNode);
+ if(divs.length > 0){
+ dojo.addClass(divs[0], "first");
+ dojo.addClass(divs[divs.length - 1], "last");
+ }
+ },
+
+ _renderRange: function(startIdx, endIdx){
+
+ var rows = [];
+ var row, i;
+ var frag = document.createDocumentFragment();
+ startIdx = Math.max(0, startIdx);
+ endIdx = Math.min(endIdx, this.items.length);
+
+ for(i = startIdx; i < endIdx; i++){
+ // Create a document fragment containing the templated row
+ row = this.applyTemplate(this.itemTemplate, this.items[i]);
+ dojo.addClass(row, 'row');
+ row._data = this.items[i];
+ row._idx = i;
+ rows.push(row);
+ }
+ if(!this.dividerFunction || !this.dividerTemplate){
+ for(i = startIdx; i < endIdx; i++){
+ rows[i]._data = this.items[i];
+ rows[i]._idx = i;
+ frag.appendChild(rows[i]);
+ }
+ }else{
+ var prevDividerValue = null;
+ var dividerValue;
+ var divider;
+ for(i = startIdx; i < endIdx; i++){
+ rows[i]._data = this.items[i];
+ rows[i]._idx = i;
+
+ dividerValue = this.dividerFunction(this.items[i]);
+ if(dividerValue && dividerValue != prevDividerValue){
+ divider = this.applyTemplate(this.dividerTemplate, {
+ label: dividerValue,
+ item: this.items[i]
+ });
+ divider._isDivider = true;
+ frag.appendChild(divider);
+ prevDividerValue = dividerValue;
+ }
+ frag.appendChild(rows[i]);
+ }
+ }
+ return frag;
+ },
+
+ _replaceToken: function(value, key){
+ if(key.charAt(0) == '!'){ value = dojo.getObject(key.substr(1), false, _this); }
+ if(typeof value == "undefined"){ return ""; } // a debugging aide
+ if(value == null){ return ""; }
+
+ // Substitution keys beginning with ! will skip the transform step,
+ // in case a user wishes to insert unescaped markup, e.g. ${!foo}
+ return key.charAt(0) == "!" ? value :
+ // Safer substitution, see heading "Attribute values" in
+ // http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2
+ value.toString().replace(/"/g,"&quot;"); //TODO: add &amp? use encodeXML method?
+
+ },
+
+ _checkLoadComplete: function(){
+ // summary:
+ // Checks if all templates have loaded
+ this._templateLoadCount--;
+
+ if(this._templateLoadCount < 1 && this.get("items")){
+ this.render();
+ }
+ },
+
+ _loadTemplate: function(url, thisAttr, callback){
+ // summary:
+ // Loads a template
+ if(!url){
+ callback();
+ return;
+ }
+
+ if(templateCache[url]){
+ this.set(thisAttr, templateCache[url]);
+ callback();
+ }else{
+ var _this = this;
+
+ dojo.xhrGet({
+ url: url,
+ sync: false,
+ handleAs: "text",
+ load: function(text){
+ templateCache[url] = dojo.trim(text);
+ _this.set(thisAttr, templateCache[url]);
+ callback();
+ }
+ });
+ }
+ },
+
+
+ _setFormattersAttr: function(formatters){
+ // summary:
+ // Sets the data items, and causes a rerender of the list
+ this.formatters = formatters;
+ },
+
+ _setItemsAttr: function(items){
+ // summary:
+ // Sets the data items, and causes a rerender of the list
+
+ this.items = items || [];
+
+ if(this._templateLoadCount < 1 && items){
+ this.render();
+ }
+ },
+
+ destroy: function(){
+ if(this.buttons){
+ dojo.forEach(this.buttons, function(button){
+ button.destroy();
+ });
+ this.buttons = null;
+ }
+
+ this.inherited(arguments);
+ }
+
+ });
+
+})();
+
+}
+
+}};});
diff --git a/js/dojo-1.6/dojox/mobile/app/ListSelector.js b/js/dojo-1.6/dojox/mobile/app/ListSelector.js
new file mode 100644
index 0000000..3b4cd40
--- /dev/null
+++ b/js/dojo-1.6/dojox/mobile/app/ListSelector.js
@@ -0,0 +1,229 @@
+/*
+ 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
+*/
+
+
+if(!dojo._hasResource["dojox.mobile.app.ListSelector"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.mobile.app.ListSelector"] = true;
+dojo.provide("dojox.mobile.app.ListSelector");
+dojo.experimental("dojox.mobile.app.ListSelector");
+
+dojo.require("dojox.mobile.app._Widget");
+dojo.require("dojo.fx");
+
+dojo.declare("dojox.mobile.app.ListSelector", dojox.mobile.app._Widget, {
+
+ // data: Array
+ // The array of items to display. Each element in the array
+ // should have both a label and value attribute, e.g.
+ // [{label: "Open", value: 1} , {label: "Delete", value: 2}]
+ data: null,
+
+ // controller: Object
+ // The current SceneController widget.
+ controller: null,
+
+ // onChoose: Function
+ // The callback function for when an item is selected
+ onChoose: null,
+
+ destroyOnHide: false,
+
+ _setDataAttr: function(data){
+ this.data = data;
+
+ if(this.data){
+ this.render();
+ }
+ },
+
+ postCreate: function(){
+ dojo.addClass(this.domNode, "listSelector");
+
+ var _this = this;
+
+ this.connect(this.domNode, "onclick", function(event){
+ if(!dojo.hasClass(event.target, "listSelectorRow")){
+ return;
+ }
+
+ if(_this.onChoose){
+ _this.onChoose(_this.data[event.target._idx].value);
+ }
+ _this.hide();
+ });
+
+ this.connect(this.domNode, "onmousedown", function(event){
+ if(!dojo.hasClass(event.target, "listSelectorRow")){
+ return;
+ }
+ dojo.addClass(event.target, "listSelectorRow-selected");
+ });
+
+ this.connect(this.domNode, "onmouseup", function(event){
+ if(!dojo.hasClass(event.target, "listSelectorRow")){
+ return;
+ }
+ dojo.removeClass(event.target, "listSelectorRow-selected");
+ });
+
+ this.connect(this.domNode, "onmouseout", function(event){
+ if(!dojo.hasClass(event.target, "listSelectorRow")){
+ return;
+ }
+ dojo.removeClass(event.target, "listSelectorRow-selected");
+ });
+
+ var viewportSize = this.controller.getWindowSize();
+
+ this.mask = dojo.create("div", {"class": "dialogUnderlayWrapper",
+ innerHTML: "<div class=\"dialogUnderlay\"></div>"
+ }, this.controller.assistant.domNode);
+
+ this.connect(this.mask, "onclick", function(){
+ _this.onChoose && _this.onChoose();
+ _this.hide();
+ });
+ },
+
+ show: function(fromNode){
+
+ // Using dojo.fx here. Must figure out how to do this with CSS animations!!
+ var startPos;
+
+ var windowSize = this.controller.getWindowSize();
+ var fromNodePos;
+ if(fromNode){
+ fromNodePos = dojo._abs(fromNode);
+ startPos = fromNodePos;
+ }else{
+ startPos.x = windowSize.w / 2;
+ startPos.y = 200;
+ }
+ console.log("startPos = ", startPos);
+
+ dojo.style(this.domNode, {
+ opacity: 0,
+ display: "",
+ width: Math.floor(windowSize.w * 0.8) + "px"
+ });
+
+ var maxWidth = 0;
+ dojo.query(">", this.domNode).forEach(function(node){
+ dojo.style(node, {
+ "float": "left"
+ });
+ maxWidth = Math.max(maxWidth, dojo.marginBox(node).w);
+ dojo.style(node, {
+ "float": "none"
+ });
+ });
+ maxWidth = Math.min(maxWidth, Math.round(windowSize.w * 0.8))
+ + dojo.style(this.domNode, "paddingLeft")
+ + dojo.style(this.domNode, "paddingRight")
+ + 1;
+
+ dojo.style(this.domNode, "width", maxWidth + "px");
+ var targetHeight = dojo.marginBox(this.domNode).h;
+
+ var _this = this;
+
+
+ var targetY = fromNodePos ?
+ Math.max(30, fromNodePos.y - targetHeight - 10) :
+ this.getScroll().y + 30;
+
+ console.log("fromNodePos = ", fromNodePos, " targetHeight = ", targetHeight,
+ " targetY = " + targetY, " startPos ", startPos);
+
+
+ var anim1 = dojo.animateProperty({
+ node: this.domNode,
+ duration: 400,
+ properties: {
+ width: {start: 1, end: maxWidth},
+ height: {start: 1, end: targetHeight},
+ top: {start: startPos.y, end: targetY},
+ left: {start: startPos.x, end: (windowSize.w/2 - maxWidth/2)},
+ opacity: {start: 0, end: 1},
+ fontSize: {start: 1}
+ },
+ onEnd: function(){
+ dojo.style(_this.domNode, "width", "inherit");
+ }
+ });
+ var anim2 = dojo.fadeIn({
+ node: this.mask,
+ duration: 400
+ });
+ dojo.fx.combine([anim1, anim2]).play();
+
+ },
+
+ hide: function(){
+ // Using dojo.fx here. Must figure out how to do this with CSS animations!!
+
+ var _this = this;
+
+ var anim1 = dojo.animateProperty({
+ node: this.domNode,
+ duration: 500,
+ properties: {
+ width: {end: 1},
+ height: {end: 1},
+ opacity: {end: 0},
+ fontSize: {end: 1}
+ },
+ onEnd: function(){
+ if(_this.get("destroyOnHide")){
+ _this.destroy();
+ }
+ }
+ });
+
+ var anim2 = dojo.fadeOut({
+ node: this.mask,
+ duration: 400
+ });
+ dojo.fx.combine([anim1, anim2]).play();
+ },
+
+ render: function(){
+ // summary:
+ // Renders
+
+ dojo.empty(this.domNode);
+ dojo.style(this.domNode, "opacity", 0);
+
+ var row;
+
+ for(var i = 0; i < this.data.length; i++){
+ // Create each row and add any custom classes. Also set the _idx property.
+ row = dojo.create("div", {
+ "class": "listSelectorRow " + (this.data[i].className || ""),
+ innerHTML: this.data[i].label
+ }, this.domNode);
+
+ row._idx = i;
+
+ if(i == 0){
+ dojo.addClass(row, "first");
+ }
+ if(i == this.data.length - 1){
+ dojo.addClass(row, "last");
+ }
+
+ }
+ },
+
+
+ destroy: function(){
+ this.inherited(arguments);
+ dojo.destroy(this.mask);
+ }
+
+});
+
+}
diff --git a/js/dojo-1.6/dojox/mobile/app/ListSelector.xd.js b/js/dojo-1.6/dojox/mobile/app/ListSelector.xd.js
new file mode 100644
index 0000000..cd8ccd8
--- /dev/null
+++ b/js/dojo-1.6/dojox/mobile/app/ListSelector.xd.js
@@ -0,0 +1,235 @@
+/*
+ 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
+*/
+
+
+dojo._xdResourceLoaded(function(dojo, dijit, dojox){
+return {depends: [["provide", "dojox.mobile.app.ListSelector"],
+["require", "dojox.mobile.app._Widget"],
+["require", "dojo.fx"]],
+defineResource: function(dojo, dijit, dojox){if(!dojo._hasResource["dojox.mobile.app.ListSelector"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.mobile.app.ListSelector"] = true;
+dojo.provide("dojox.mobile.app.ListSelector");
+dojo.experimental("dojox.mobile.app.ListSelector");
+
+dojo.require("dojox.mobile.app._Widget");
+dojo.require("dojo.fx");
+
+dojo.declare("dojox.mobile.app.ListSelector", dojox.mobile.app._Widget, {
+
+ // data: Array
+ // The array of items to display. Each element in the array
+ // should have both a label and value attribute, e.g.
+ // [{label: "Open", value: 1} , {label: "Delete", value: 2}]
+ data: null,
+
+ // controller: Object
+ // The current SceneController widget.
+ controller: null,
+
+ // onChoose: Function
+ // The callback function for when an item is selected
+ onChoose: null,
+
+ destroyOnHide: false,
+
+ _setDataAttr: function(data){
+ this.data = data;
+
+ if(this.data){
+ this.render();
+ }
+ },
+
+ postCreate: function(){
+ dojo.addClass(this.domNode, "listSelector");
+
+ var _this = this;
+
+ this.connect(this.domNode, "onclick", function(event){
+ if(!dojo.hasClass(event.target, "listSelectorRow")){
+ return;
+ }
+
+ if(_this.onChoose){
+ _this.onChoose(_this.data[event.target._idx].value);
+ }
+ _this.hide();
+ });
+
+ this.connect(this.domNode, "onmousedown", function(event){
+ if(!dojo.hasClass(event.target, "listSelectorRow")){
+ return;
+ }
+ dojo.addClass(event.target, "listSelectorRow-selected");
+ });
+
+ this.connect(this.domNode, "onmouseup", function(event){
+ if(!dojo.hasClass(event.target, "listSelectorRow")){
+ return;
+ }
+ dojo.removeClass(event.target, "listSelectorRow-selected");
+ });
+
+ this.connect(this.domNode, "onmouseout", function(event){
+ if(!dojo.hasClass(event.target, "listSelectorRow")){
+ return;
+ }
+ dojo.removeClass(event.target, "listSelectorRow-selected");
+ });
+
+ var viewportSize = this.controller.getWindowSize();
+
+ this.mask = dojo.create("div", {"class": "dialogUnderlayWrapper",
+ innerHTML: "<div class=\"dialogUnderlay\"></div>"
+ }, this.controller.assistant.domNode);
+
+ this.connect(this.mask, "onclick", function(){
+ _this.onChoose && _this.onChoose();
+ _this.hide();
+ });
+ },
+
+ show: function(fromNode){
+
+ // Using dojo.fx here. Must figure out how to do this with CSS animations!!
+ var startPos;
+
+ var windowSize = this.controller.getWindowSize();
+ var fromNodePos;
+ if(fromNode){
+ fromNodePos = dojo._abs(fromNode);
+ startPos = fromNodePos;
+ }else{
+ startPos.x = windowSize.w / 2;
+ startPos.y = 200;
+ }
+ console.log("startPos = ", startPos);
+
+ dojo.style(this.domNode, {
+ opacity: 0,
+ display: "",
+ width: Math.floor(windowSize.w * 0.8) + "px"
+ });
+
+ var maxWidth = 0;
+ dojo.query(">", this.domNode).forEach(function(node){
+ dojo.style(node, {
+ "float": "left"
+ });
+ maxWidth = Math.max(maxWidth, dojo.marginBox(node).w);
+ dojo.style(node, {
+ "float": "none"
+ });
+ });
+ maxWidth = Math.min(maxWidth, Math.round(windowSize.w * 0.8))
+ + dojo.style(this.domNode, "paddingLeft")
+ + dojo.style(this.domNode, "paddingRight")
+ + 1;
+
+ dojo.style(this.domNode, "width", maxWidth + "px");
+ var targetHeight = dojo.marginBox(this.domNode).h;
+
+ var _this = this;
+
+
+ var targetY = fromNodePos ?
+ Math.max(30, fromNodePos.y - targetHeight - 10) :
+ this.getScroll().y + 30;
+
+ console.log("fromNodePos = ", fromNodePos, " targetHeight = ", targetHeight,
+ " targetY = " + targetY, " startPos ", startPos);
+
+
+ var anim1 = dojo.animateProperty({
+ node: this.domNode,
+ duration: 400,
+ properties: {
+ width: {start: 1, end: maxWidth},
+ height: {start: 1, end: targetHeight},
+ top: {start: startPos.y, end: targetY},
+ left: {start: startPos.x, end: (windowSize.w/2 - maxWidth/2)},
+ opacity: {start: 0, end: 1},
+ fontSize: {start: 1}
+ },
+ onEnd: function(){
+ dojo.style(_this.domNode, "width", "inherit");
+ }
+ });
+ var anim2 = dojo.fadeIn({
+ node: this.mask,
+ duration: 400
+ });
+ dojo.fx.combine([anim1, anim2]).play();
+
+ },
+
+ hide: function(){
+ // Using dojo.fx here. Must figure out how to do this with CSS animations!!
+
+ var _this = this;
+
+ var anim1 = dojo.animateProperty({
+ node: this.domNode,
+ duration: 500,
+ properties: {
+ width: {end: 1},
+ height: {end: 1},
+ opacity: {end: 0},
+ fontSize: {end: 1}
+ },
+ onEnd: function(){
+ if(_this.get("destroyOnHide")){
+ _this.destroy();
+ }
+ }
+ });
+
+ var anim2 = dojo.fadeOut({
+ node: this.mask,
+ duration: 400
+ });
+ dojo.fx.combine([anim1, anim2]).play();
+ },
+
+ render: function(){
+ // summary:
+ // Renders
+
+ dojo.empty(this.domNode);
+ dojo.style(this.domNode, "opacity", 0);
+
+ var row;
+
+ for(var i = 0; i < this.data.length; i++){
+ // Create each row and add any custom classes. Also set the _idx property.
+ row = dojo.create("div", {
+ "class": "listSelectorRow " + (this.data[i].className || ""),
+ innerHTML: this.data[i].label
+ }, this.domNode);
+
+ row._idx = i;
+
+ if(i == 0){
+ dojo.addClass(row, "first");
+ }
+ if(i == this.data.length - 1){
+ dojo.addClass(row, "last");
+ }
+
+ }
+ },
+
+
+ destroy: function(){
+ this.inherited(arguments);
+ dojo.destroy(this.mask);
+ }
+
+});
+
+}
+
+}};});
diff --git a/js/dojo-1.6/dojox/mobile/app/SceneAssistant.js b/js/dojo-1.6/dojox/mobile/app/SceneAssistant.js
new file mode 100644
index 0000000..d92767d
--- /dev/null
+++ b/js/dojo-1.6/dojox/mobile/app/SceneAssistant.js
@@ -0,0 +1,67 @@
+/*
+ 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
+*/
+
+
+if(!dojo._hasResource["dojox.mobile.app.SceneAssistant"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.mobile.app.SceneAssistant"] = true;
+dojo.provide("dojox.mobile.app.SceneAssistant");
+dojo.experimental("dojox.mobile.app.SceneAssistant");
+
+dojo.declare("dojox.mobile.app.SceneAssistant", null, {
+ // summary:
+ // The base class for all scene assistants.
+
+ constructor: function(){
+
+ },
+
+ setup: function(){
+ // summary:
+ // Called to set up the widget. The UI is not visible at this time
+
+ },
+
+ activate: function(params){
+ // summary:
+ // Called each time the scene becomes visible. This can be as a result
+ // of a new scene being created, or a subsequent scene being destroyed
+ // and control transferring back to this scene assistant.
+ // params:
+ // Optional paramters, only passed when a subsequent scene pops itself
+ // off the stack and passes back data.
+ },
+
+ deactivate: function(){
+ // summary:
+ // Called each time the scene becomes invisible. This can be as a result
+ // of it being popped off the stack and destroyed,
+ // or another scene being created and pushed on top of it on the stack
+ },
+
+ destroy: function(){
+
+ var children =
+ dojo.query("> [widgetId]", this.containerNode).map(dijit.byNode);
+ dojo.forEach(children, function(child){ child.destroyRecursive(); });
+
+ this.disconnect();
+ },
+
+ connect: function(obj, method, callback){
+ if(!this._connects){
+ this._connects = [];
+ }
+ this._connects.push(dojo.connect(obj, method, callback));
+ },
+
+ disconnect: function(){
+ dojo.forEach(this._connects, dojo.disconnect);
+ this._connects = [];
+ }
+});
+
+
+}
diff --git a/js/dojo-1.6/dojox/mobile/app/SceneAssistant.xd.js b/js/dojo-1.6/dojox/mobile/app/SceneAssistant.xd.js
new file mode 100644
index 0000000..4d62f75
--- /dev/null
+++ b/js/dojo-1.6/dojox/mobile/app/SceneAssistant.xd.js
@@ -0,0 +1,71 @@
+/*
+ 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
+*/
+
+
+dojo._xdResourceLoaded(function(dojo, dijit, dojox){
+return {depends: [["provide", "dojox.mobile.app.SceneAssistant"]],
+defineResource: function(dojo, dijit, dojox){if(!dojo._hasResource["dojox.mobile.app.SceneAssistant"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.mobile.app.SceneAssistant"] = true;
+dojo.provide("dojox.mobile.app.SceneAssistant");
+dojo.experimental("dojox.mobile.app.SceneAssistant");
+
+dojo.declare("dojox.mobile.app.SceneAssistant", null, {
+ // summary:
+ // The base class for all scene assistants.
+
+ constructor: function(){
+
+ },
+
+ setup: function(){
+ // summary:
+ // Called to set up the widget. The UI is not visible at this time
+
+ },
+
+ activate: function(params){
+ // summary:
+ // Called each time the scene becomes visible. This can be as a result
+ // of a new scene being created, or a subsequent scene being destroyed
+ // and control transferring back to this scene assistant.
+ // params:
+ // Optional paramters, only passed when a subsequent scene pops itself
+ // off the stack and passes back data.
+ },
+
+ deactivate: function(){
+ // summary:
+ // Called each time the scene becomes invisible. This can be as a result
+ // of it being popped off the stack and destroyed,
+ // or another scene being created and pushed on top of it on the stack
+ },
+
+ destroy: function(){
+
+ var children =
+ dojo.query("> [widgetId]", this.containerNode).map(dijit.byNode);
+ dojo.forEach(children, function(child){ child.destroyRecursive(); });
+
+ this.disconnect();
+ },
+
+ connect: function(obj, method, callback){
+ if(!this._connects){
+ this._connects = [];
+ }
+ this._connects.push(dojo.connect(obj, method, callback));
+ },
+
+ disconnect: function(){
+ dojo.forEach(this._connects, dojo.disconnect);
+ this._connects = [];
+ }
+});
+
+
+}
+
+}};});
diff --git a/js/dojo-1.6/dojox/mobile/app/SceneController.js b/js/dojo-1.6/dojox/mobile/app/SceneController.js
new file mode 100644
index 0000000..bcf25cd
--- /dev/null
+++ b/js/dojo-1.6/dojox/mobile/app/SceneController.js
@@ -0,0 +1,181 @@
+/*
+ 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
+*/
+
+
+if(!dojo._hasResource["dojox.mobile.app.SceneController"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.mobile.app.SceneController"] = true;
+dojo.provide("dojox.mobile.app.SceneController");
+dojo.experimental("dojox.mobile.app.SceneController");
+dojo.require("dojox.mobile._base");
+
+(function(){
+
+ var app = dojox.mobile.app;
+
+ var templates = {};
+
+ dojo.declare("dojox.mobile.app.SceneController", dojox.mobile.View, {
+
+ stageController: null,
+
+ keepScrollPos: false,
+
+ init: function(sceneName, params){
+ // summary:
+ // Initializes the scene by loading the HTML template and code, if it has
+ // not already been loaded
+
+ this.sceneName = sceneName;
+ this.params = params;
+ var templateUrl = app.resolveTemplate(sceneName);
+
+ this._deferredInit = new dojo.Deferred();
+
+ if(templates[sceneName]){
+ // If the template has been cached, do not load it again.
+ this._setContents(templates[sceneName]);
+ }else{
+ // Otherwise load the template
+ dojo.xhrGet({
+ url: templateUrl,
+ handleAs: "text"
+ }).addCallback(dojo.hitch(this, this._setContents));
+ }
+
+ return this._deferredInit;
+ },
+
+ _setContents: function(templateHtml){
+ // summary:
+ // Sets the content of the View, and invokes either the loading or
+ // initialization of the scene assistant.
+ templates[this.sceneName] = templateHtml;
+
+ this.domNode.innerHTML = "<div>" + templateHtml + "</div>";
+
+ var sceneAssistantName = "";
+
+ var nameParts = this.sceneName.split("-");
+
+ for(var i = 0; i < nameParts.length; i++){
+ sceneAssistantName += nameParts[i].substring(0, 1).toUpperCase()
+ + nameParts[i].substring(1);
+ }
+ sceneAssistantName += "Assistant";
+ this.sceneAssistantName = sceneAssistantName;
+
+ var _this = this;
+
+ dojox.mobile.app.loadResourcesForScene(this.sceneName, function(){
+
+ console.log("All resources for ",_this.sceneName," loaded");
+
+ var assistant;
+ if(typeof(dojo.global[sceneAssistantName]) != "undefined"){
+ _this._initAssistant();
+ }else{
+ var assistantUrl = app.resolveAssistant(_this.sceneName);
+
+ dojo.xhrGet({
+ url: assistantUrl,
+ handleAs: "text"
+ }).addCallback(function(text){
+ try{
+ dojo.eval(text);
+ }catch(e){
+ console.log("Error initializing code for scene " + _this.sceneName
+ + '. Please check for syntax errors');
+ throw e;
+ }
+ _this._initAssistant();
+ });
+ }
+ });
+
+ },
+
+ _initAssistant: function(){
+ // summary:
+ // Initializes the scene assistant. At this point, the View is
+ // populated with the HTML template, and the scene assistant type
+ // is declared.
+
+ console.log("Instantiating the scene assistant " + this.sceneAssistantName);
+
+ var cls = dojo.getObject(this.sceneAssistantName);
+
+ if(!cls){
+ throw Error("Unable to resolve scene assistant "
+ + this.sceneAssistantName);
+ }
+
+ this.assistant = new cls(this.params);
+
+ this.assistant.controller = this;
+ this.assistant.domNode = this.domNode.firstChild;
+
+ this.assistant.setup();
+
+ this._deferredInit.callback();
+ },
+
+ query: function(selector, node){
+ // summary:
+ // Queries for DOM nodes within either the node passed in as an argument
+ // or within this view.
+
+ return dojo.query(selector, node || this.domNode)
+ },
+
+ parse: function(node){
+ var widgets = this._widgets =
+ dojox.mobile.parser.parse(node || this.domNode, {
+ controller: this
+ });
+
+ // Tell all widgets what their controller is.
+ for(var i = 0; i < widgets.length; i++){
+ widgets[i].set("controller", this);
+ }
+ },
+
+ getWindowSize: function(){
+ // TODO, this needs cross browser testing
+
+ return {
+ w: dojo.global.innerWidth,
+ h: dojo.global.innerHeight
+ }
+ },
+
+ showAlertDialog: function(props){
+
+ var size = dojo.marginBox(this.assistant.domNode);
+ var dialog = new dojox.mobile.app.AlertDialog(
+ dojo.mixin(props, {controller: this}));
+ this.assistant.domNode.appendChild(dialog.domNode);
+
+ console.log("Appended " , dialog.domNode, " to ", this.assistant.domNode);
+ dialog.show();
+ },
+
+ popupSubMenu: function(info){
+ var widget = new dojox.mobile.app.ListSelector({
+ controller: this,
+ destroyOnHide: true,
+ onChoose: info.onChoose
+ });
+
+ this.assistant.domNode.appendChild(widget.domNode);
+
+ widget.set("data", info.choices);
+ widget.show(info.fromNode);
+ }
+ });
+
+})();
+
+}
diff --git a/js/dojo-1.6/dojox/mobile/app/SceneController.xd.js b/js/dojo-1.6/dojox/mobile/app/SceneController.xd.js
new file mode 100644
index 0000000..ac36faa
--- /dev/null
+++ b/js/dojo-1.6/dojox/mobile/app/SceneController.xd.js
@@ -0,0 +1,186 @@
+/*
+ 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
+*/
+
+
+dojo._xdResourceLoaded(function(dojo, dijit, dojox){
+return {depends: [["provide", "dojox.mobile.app.SceneController"],
+["require", "dojox.mobile._base"]],
+defineResource: function(dojo, dijit, dojox){if(!dojo._hasResource["dojox.mobile.app.SceneController"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.mobile.app.SceneController"] = true;
+dojo.provide("dojox.mobile.app.SceneController");
+dojo.experimental("dojox.mobile.app.SceneController");
+dojo.require("dojox.mobile._base");
+
+(function(){
+
+ var app = dojox.mobile.app;
+
+ var templates = {};
+
+ dojo.declare("dojox.mobile.app.SceneController", dojox.mobile.View, {
+
+ stageController: null,
+
+ keepScrollPos: false,
+
+ init: function(sceneName, params){
+ // summary:
+ // Initializes the scene by loading the HTML template and code, if it has
+ // not already been loaded
+
+ this.sceneName = sceneName;
+ this.params = params;
+ var templateUrl = app.resolveTemplate(sceneName);
+
+ this._deferredInit = new dojo.Deferred();
+
+ if(templates[sceneName]){
+ // If the template has been cached, do not load it again.
+ this._setContents(templates[sceneName]);
+ }else{
+ // Otherwise load the template
+ dojo.xhrGet({
+ url: templateUrl,
+ handleAs: "text"
+ }).addCallback(dojo.hitch(this, this._setContents));
+ }
+
+ return this._deferredInit;
+ },
+
+ _setContents: function(templateHtml){
+ // summary:
+ // Sets the content of the View, and invokes either the loading or
+ // initialization of the scene assistant.
+ templates[this.sceneName] = templateHtml;
+
+ this.domNode.innerHTML = "<div>" + templateHtml + "</div>";
+
+ var sceneAssistantName = "";
+
+ var nameParts = this.sceneName.split("-");
+
+ for(var i = 0; i < nameParts.length; i++){
+ sceneAssistantName += nameParts[i].substring(0, 1).toUpperCase()
+ + nameParts[i].substring(1);
+ }
+ sceneAssistantName += "Assistant";
+ this.sceneAssistantName = sceneAssistantName;
+
+ var _this = this;
+
+ dojox.mobile.app.loadResourcesForScene(this.sceneName, function(){
+
+ console.log("All resources for ",_this.sceneName," loaded");
+
+ var assistant;
+ if(typeof(dojo.global[sceneAssistantName]) != "undefined"){
+ _this._initAssistant();
+ }else{
+ var assistantUrl = app.resolveAssistant(_this.sceneName);
+
+ dojo.xhrGet({
+ url: assistantUrl,
+ handleAs: "text"
+ }).addCallback(function(text){
+ try{
+ dojo.eval(text);
+ }catch(e){
+ console.log("Error initializing code for scene " + _this.sceneName
+ + '. Please check for syntax errors');
+ throw e;
+ }
+ _this._initAssistant();
+ });
+ }
+ });
+
+ },
+
+ _initAssistant: function(){
+ // summary:
+ // Initializes the scene assistant. At this point, the View is
+ // populated with the HTML template, and the scene assistant type
+ // is declared.
+
+ console.log("Instantiating the scene assistant " + this.sceneAssistantName);
+
+ var cls = dojo.getObject(this.sceneAssistantName);
+
+ if(!cls){
+ throw Error("Unable to resolve scene assistant "
+ + this.sceneAssistantName);
+ }
+
+ this.assistant = new cls(this.params);
+
+ this.assistant.controller = this;
+ this.assistant.domNode = this.domNode.firstChild;
+
+ this.assistant.setup();
+
+ this._deferredInit.callback();
+ },
+
+ query: function(selector, node){
+ // summary:
+ // Queries for DOM nodes within either the node passed in as an argument
+ // or within this view.
+
+ return dojo.query(selector, node || this.domNode)
+ },
+
+ parse: function(node){
+ var widgets = this._widgets =
+ dojox.mobile.parser.parse(node || this.domNode, {
+ controller: this
+ });
+
+ // Tell all widgets what their controller is.
+ for(var i = 0; i < widgets.length; i++){
+ widgets[i].set("controller", this);
+ }
+ },
+
+ getWindowSize: function(){
+ // TODO, this needs cross browser testing
+
+ return {
+ w: dojo.global.innerWidth,
+ h: dojo.global.innerHeight
+ }
+ },
+
+ showAlertDialog: function(props){
+
+ var size = dojo.marginBox(this.assistant.domNode);
+ var dialog = new dojox.mobile.app.AlertDialog(
+ dojo.mixin(props, {controller: this}));
+ this.assistant.domNode.appendChild(dialog.domNode);
+
+ console.log("Appended " , dialog.domNode, " to ", this.assistant.domNode);
+ dialog.show();
+ },
+
+ popupSubMenu: function(info){
+ var widget = new dojox.mobile.app.ListSelector({
+ controller: this,
+ destroyOnHide: true,
+ onChoose: info.onChoose
+ });
+
+ this.assistant.domNode.appendChild(widget.domNode);
+
+ widget.set("data", info.choices);
+ widget.show(info.fromNode);
+ }
+ });
+
+})();
+
+}
+
+}};});
diff --git a/js/dojo-1.6/dojox/mobile/app/StageController.js b/js/dojo-1.6/dojox/mobile/app/StageController.js
new file mode 100644
index 0000000..43c6798
--- /dev/null
+++ b/js/dojo-1.6/dojox/mobile/app/StageController.js
@@ -0,0 +1,143 @@
+/*
+ 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
+*/
+
+
+if(!dojo._hasResource["dojox.mobile.app.StageController"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.mobile.app.StageController"] = true;
+dojo.provide("dojox.mobile.app.StageController");
+dojo.experimental("dojox.mobile.app.StageController");
+
+dojo.require("dojox.mobile.app.SceneController");
+
+dojo.declare("dojox.mobile.app.StageController", null,{
+
+ // scenes: Array
+ // The list of scenes currently in existance in the app.
+ scenes: null,
+
+ effect: "fade",
+
+ constructor: function(node){
+ this.domNode = node;
+ this.scenes = [];
+
+ if(dojo.config.mobileAnim){
+ this.effect = dojo.config.mobileAnim;
+ }
+ },
+
+ getActiveSceneController: function(){
+ return this.scenes[this.scenes.length - 1];
+ },
+
+ pushScene: function(sceneName, params){
+ if(this._opInProgress){
+ return;
+ }
+ this._opInProgress = true;
+
+ // Push new scenes as the first element on the page.
+ var node = dojo.create("div", {
+ "class": "scene-wrapper",
+ style: {
+ visibility: "hidden"
+ }
+ }, this.domNode);
+
+ var controller = new dojox.mobile.app.SceneController({}, node);
+
+ if(this.scenes.length > 0){
+ this.scenes[this.scenes.length -1].assistant.deactivate();
+ }
+
+ this.scenes.push(controller);
+
+ var _this = this;
+
+ dojo.forEach(this.scenes, this.setZIndex);
+
+ controller.stageController = this;
+
+ controller.init(sceneName, params).addCallback(function(){
+
+ if(_this.scenes.length == 1){
+ controller.domNode.style.visibility = "visible";
+ _this.scenes[_this.scenes.length - 1].assistant.activate(params);
+ _this._opInProgress = false;
+ }else{
+ _this.scenes[_this.scenes.length - 2]
+ .performTransition(
+ _this.scenes[_this.scenes.length - 1].domNode,
+ 1,
+ _this.effect,
+ null,
+ function(){
+ // When the scene is ready, activate it.
+ _this.scenes[_this.scenes.length - 1].assistant.activate(params);
+ _this._opInProgress = false;
+ });
+ }
+ });
+ },
+
+ setZIndex: function(controller, idx){
+ dojo.style(controller.domNode, "zIndex", idx + 1);
+ },
+
+ popScene: function(data){
+ // performTransition: function(/*String*/moveTo, /*Number*/dir, /*String*/transition,
+ // /*Object|null*/context, /*String|Function*/method /*optional args*/){
+ if(this._opInProgress){
+ return;
+ }
+
+ var _this = this;
+ if(this.scenes.length > 1){
+
+ this._opInProgress = true;
+ this.scenes[_this.scenes.length - 2].assistant.activate(data);
+ this.scenes[_this.scenes.length - 1]
+ .performTransition(
+ _this.scenes[this.scenes.length - 2].domNode,
+ -1,
+ this.effect,
+ null,
+ function(){
+ // When the scene is no longer visible, destroy it
+ _this._destroyScene(_this.scenes[_this.scenes.length - 1]);
+ _this.scenes.splice(_this.scenes.length - 1, 1);
+ _this._opInProgress = false;
+ });
+ }else{
+ console.log("cannot pop the scene if there is just one");
+ }
+ },
+
+ popScenesTo: function(sceneName, data){
+ if(this._opInProgress){
+ return;
+ }
+
+ while(this.scenes.length > 2 &&
+ this.scenes[this.scenes.length - 2].sceneName != sceneName){
+ this._destroyScene(this.scenes[this.scenes.length - 2]);
+ this.scenes.splice(this.scenes.length - 2, 1);
+ }
+
+ this.popScene(data);
+ },
+
+ _destroyScene: function(scene){
+ scene.assistant.deactivate();
+ scene.assistant.destroy();
+ scene.destroyRecursive();
+ }
+
+
+});
+
+
+}
diff --git a/js/dojo-1.6/dojox/mobile/app/StageController.xd.js b/js/dojo-1.6/dojox/mobile/app/StageController.xd.js
new file mode 100644
index 0000000..5542ab5
--- /dev/null
+++ b/js/dojo-1.6/dojox/mobile/app/StageController.xd.js
@@ -0,0 +1,148 @@
+/*
+ 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
+*/
+
+
+dojo._xdResourceLoaded(function(dojo, dijit, dojox){
+return {depends: [["provide", "dojox.mobile.app.StageController"],
+["require", "dojox.mobile.app.SceneController"]],
+defineResource: function(dojo, dijit, dojox){if(!dojo._hasResource["dojox.mobile.app.StageController"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.mobile.app.StageController"] = true;
+dojo.provide("dojox.mobile.app.StageController");
+dojo.experimental("dojox.mobile.app.StageController");
+
+dojo.require("dojox.mobile.app.SceneController");
+
+dojo.declare("dojox.mobile.app.StageController", null,{
+
+ // scenes: Array
+ // The list of scenes currently in existance in the app.
+ scenes: null,
+
+ effect: "fade",
+
+ constructor: function(node){
+ this.domNode = node;
+ this.scenes = [];
+
+ if(dojo.config.mobileAnim){
+ this.effect = dojo.config.mobileAnim;
+ }
+ },
+
+ getActiveSceneController: function(){
+ return this.scenes[this.scenes.length - 1];
+ },
+
+ pushScene: function(sceneName, params){
+ if(this._opInProgress){
+ return;
+ }
+ this._opInProgress = true;
+
+ // Push new scenes as the first element on the page.
+ var node = dojo.create("div", {
+ "class": "scene-wrapper",
+ style: {
+ visibility: "hidden"
+ }
+ }, this.domNode);
+
+ var controller = new dojox.mobile.app.SceneController({}, node);
+
+ if(this.scenes.length > 0){
+ this.scenes[this.scenes.length -1].assistant.deactivate();
+ }
+
+ this.scenes.push(controller);
+
+ var _this = this;
+
+ dojo.forEach(this.scenes, this.setZIndex);
+
+ controller.stageController = this;
+
+ controller.init(sceneName, params).addCallback(function(){
+
+ if(_this.scenes.length == 1){
+ controller.domNode.style.visibility = "visible";
+ _this.scenes[_this.scenes.length - 1].assistant.activate(params);
+ _this._opInProgress = false;
+ }else{
+ _this.scenes[_this.scenes.length - 2]
+ .performTransition(
+ _this.scenes[_this.scenes.length - 1].domNode,
+ 1,
+ _this.effect,
+ null,
+ function(){
+ // When the scene is ready, activate it.
+ _this.scenes[_this.scenes.length - 1].assistant.activate(params);
+ _this._opInProgress = false;
+ });
+ }
+ });
+ },
+
+ setZIndex: function(controller, idx){
+ dojo.style(controller.domNode, "zIndex", idx + 1);
+ },
+
+ popScene: function(data){
+ // performTransition: function(/*String*/moveTo, /*Number*/dir, /*String*/transition,
+ // /*Object|null*/context, /*String|Function*/method /*optional args*/){
+ if(this._opInProgress){
+ return;
+ }
+
+ var _this = this;
+ if(this.scenes.length > 1){
+
+ this._opInProgress = true;
+ this.scenes[_this.scenes.length - 2].assistant.activate(data);
+ this.scenes[_this.scenes.length - 1]
+ .performTransition(
+ _this.scenes[this.scenes.length - 2].domNode,
+ -1,
+ this.effect,
+ null,
+ function(){
+ // When the scene is no longer visible, destroy it
+ _this._destroyScene(_this.scenes[_this.scenes.length - 1]);
+ _this.scenes.splice(_this.scenes.length - 1, 1);
+ _this._opInProgress = false;
+ });
+ }else{
+ console.log("cannot pop the scene if there is just one");
+ }
+ },
+
+ popScenesTo: function(sceneName, data){
+ if(this._opInProgress){
+ return;
+ }
+
+ while(this.scenes.length > 2 &&
+ this.scenes[this.scenes.length - 2].sceneName != sceneName){
+ this._destroyScene(this.scenes[this.scenes.length - 2]);
+ this.scenes.splice(this.scenes.length - 2, 1);
+ }
+
+ this.popScene(data);
+ },
+
+ _destroyScene: function(scene){
+ scene.assistant.deactivate();
+ scene.assistant.destroy();
+ scene.destroyRecursive();
+ }
+
+
+});
+
+
+}
+
+}};});
diff --git a/js/dojo-1.6/dojox/mobile/app/TextBox.js b/js/dojo-1.6/dojox/mobile/app/TextBox.js
new file mode 100644
index 0000000..409178a
--- /dev/null
+++ b/js/dojo-1.6/dojox/mobile/app/TextBox.js
@@ -0,0 +1,330 @@
+/*
+ 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
+*/
+
+
+if(!dojo._hasResource["dojox.mobile.app.TextBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.mobile.app.TextBox"] = true;
+dojo.provide("dojox.mobile.app.TextBox");
+dojo.experimental("dojox.mobile.app.TextBox");
+
+dojo.require("dojox.mobile.app._Widget");
+dojo.require("dojox.mobile.app._FormWidget");
+
+dojo.declare(
+ "dojox.mobile.app.TextBox",
+ dojox.mobile.app._FormValueWidget, {
+
+ // summary:
+ // A base class for textbox form inputs
+
+ // trim: Boolean
+ // Removes leading and trailing whitespace if true. Default is false.
+ trim: false,
+
+ // uppercase: Boolean
+ // Converts all characters to uppercase if true. Default is false.
+ uppercase: false,
+
+ // lowercase: Boolean
+ // Converts all characters to lowercase if true. Default is false.
+ lowercase: false,
+
+ // propercase: Boolean
+ // Converts the first character of each word to uppercase if true.
+ propercase: false,
+
+ // maxLength: String
+ // HTML INPUT tag maxLength declaration.
+ maxLength: "",
+
+ // selectOnClick: [const] Boolean
+ // If true, all text will be selected when focused with mouse
+ selectOnClick: false,
+
+ // placeHolder: String
+ // Defines a hint to help users fill out the input field (as defined in HTML 5).
+ // This should only contain plain text (no html markup).
+ placeHolder: "",
+
+ baseClass: "mblTextBox",
+
+ attributeMap: dojo.delegate(dojox.mobile.app._FormValueWidget.prototype.attributeMap, {
+ maxLength: "focusNode"
+ }),
+
+ buildRendering: function(){
+ var node = this.srcNodeRef;
+
+ // If an input is used as the source node, wrap it in a div
+ if(!node || node.tagName != "INPUT"){
+ node = dojo.create("input", {});
+ }
+
+ dojo.attr(node, {
+ type: "text",
+ value: dojo.attr(node, "value") || "",
+ placeholder: this.placeHolder || null
+ });
+
+ this.domNode = this.textbox = this.focusNode = node;
+ },
+
+ _setPlaceHolderAttr: function(v){
+ this.placeHolder = v;
+ if(this.textbox){
+ dojo.attr(this.textbox, "placeholder", v);
+ }
+ },
+
+
+ _getValueAttr: function(){
+ // summary:
+ // Hook so attr('value') works as we like.
+ // description:
+ // For `dijit.form.TextBox` this basically returns the value of the <input>.
+ //
+ // For `dijit.form.MappedTextBox` subclasses, which have both
+ // a "displayed value" and a separate "submit value",
+ // This treats the "displayed value" as the master value, computing the
+ // submit value from it via this.parse().
+ return this.parse(this.get('displayedValue'), this.constraints);
+ },
+
+ _setValueAttr: function(value, /*Boolean?*/ priorityChange, /*String?*/ formattedValue){
+ // summary:
+ // Hook so attr('value', ...) works.
+ //
+ // description:
+ // Sets the value of the widget to "value" which can be of
+ // any type as determined by the widget.
+ //
+ // value:
+ // The visual element value is also set to a corresponding,
+ // but not necessarily the same, value.
+ //
+ // formattedValue:
+ // If specified, used to set the visual element value,
+ // otherwise a computed visual value is used.
+ //
+ // priorityChange:
+ // If true, an onChange event is fired immediately instead of
+ // waiting for the next blur event.
+
+ var filteredValue;
+ if(value !== undefined){
+ // TODO: this is calling filter() on both the display value and the actual value.
+ // I added a comment to the filter() definition about this, but it should be changed.
+ filteredValue = this.filter(value);
+ if(typeof formattedValue != "string"){
+ if(filteredValue !== null
+ && ((typeof filteredValue != "number") || !isNaN(filteredValue))){
+ formattedValue = this.filter(this.format(filteredValue, this.constraints));
+ }else{ formattedValue = ''; }
+ }
+ }
+ if(formattedValue != null && formattedValue != undefined
+ && ((typeof formattedValue) != "number" || !isNaN(formattedValue))
+ && this.textbox.value != formattedValue){
+ this.textbox.value = formattedValue;
+ }
+
+ this.inherited(arguments, [filteredValue, priorityChange]);
+ },
+
+ // displayedValue: String
+ // For subclasses like ComboBox where the displayed value
+ // (ex: Kentucky) and the serialized value (ex: KY) are different,
+ // this represents the displayed value.
+ //
+ // Setting 'displayedValue' through attr('displayedValue', ...)
+ // updates 'value', and vice-versa. Otherwise 'value' is updated
+ // from 'displayedValue' periodically, like onBlur etc.
+ //
+ // TODO: move declaration to MappedTextBox?
+ // Problem is that ComboBox references displayedValue,
+ // for benefit of FilteringSelect.
+ displayedValue: "",
+
+ _getDisplayedValueAttr: function(){
+ // summary:
+ // Hook so attr('displayedValue') works.
+ // description:
+ // Returns the displayed value (what the user sees on the screen),
+ // after filtering (ie, trimming spaces etc.).
+ //
+ // For some subclasses of TextBox (like ComboBox), the displayed value
+ // is different from the serialized value that's actually
+ // sent to the server (see dijit.form.ValidationTextBox.serialize)
+
+ return this.filter(this.textbox.value);
+ },
+
+ _setDisplayedValueAttr: function(/*String*/value){
+ // summary:
+ // Hook so attr('displayedValue', ...) works.
+ // description:
+ // Sets the value of the visual element to the string "value".
+ // The widget value is also set to a corresponding,
+ // but not necessarily the same, value.
+
+ if(value === null || value === undefined){ value = '' }
+ else if(typeof value != "string"){ value = String(value) }
+ this.textbox.value = value;
+ this._setValueAttr(this.get('value'), undefined, value);
+ },
+
+ format: function(/* String */ value, /* Object */ constraints){
+ // summary:
+ // Replacable function to convert a value to a properly formatted string.
+ // tags:
+ // protected extension
+ return ((value == null || value == undefined) ? "" : (value.toString ? value.toString() : value));
+ },
+
+ parse: function(/* String */ value, /* Object */ constraints){
+ // summary:
+ // Replacable function to convert a formatted string to a value
+ // tags:
+ // protected extension
+
+ return value; // String
+ },
+
+ _refreshState: function(){
+ // summary:
+ // After the user types some characters, etc., this method is
+ // called to check the field for validity etc. The base method
+ // in `dijit.form.TextBox` does nothing, but subclasses override.
+ // tags:
+ // protected
+ },
+
+ _onInput: function(e){
+ if(e && e.type && /key/i.test(e.type) && e.keyCode){
+ switch(e.keyCode){
+ case dojo.keys.SHIFT:
+ case dojo.keys.ALT:
+ case dojo.keys.CTRL:
+ case dojo.keys.TAB:
+ return;
+ }
+ }
+ if(this.intermediateChanges){
+ var _this = this;
+ // the setTimeout allows the key to post to the widget input box
+ setTimeout(function(){ _this._handleOnChange(_this.get('value'), false); }, 0);
+ }
+ this._refreshState();
+ },
+
+ postCreate: function(){
+ // setting the value here is needed since value="" in the template causes "undefined"
+ // and setting in the DOM (instead of the JS object) helps with form reset actions
+
+ this.textbox.setAttribute("value", this.textbox.value); // DOM and JS values shuld be the same
+ this.inherited(arguments);
+ if(dojo.isMoz || dojo.isOpera){
+ this.connect(this.textbox, "oninput", this._onInput);
+ }else{
+ this.connect(this.textbox, "onkeydown", this._onInput);
+ this.connect(this.textbox, "onkeyup", this._onInput);
+ this.connect(this.textbox, "onpaste", this._onInput);
+ this.connect(this.textbox, "oncut", this._onInput);
+ }
+ },
+
+ _blankValue: '', // if the textbox is blank, what value should be reported
+ filter: function(val){
+ // summary:
+ // Auto-corrections (such as trimming) that are applied to textbox
+ // value on blur or form submit.
+ // description:
+ // For MappedTextBox subclasses, this is called twice
+ // - once with the display value
+ // - once the value as set/returned by attr('value', ...)
+ // and attr('value'), ex: a Number for NumberTextBox.
+ //
+ // In the latter case it does corrections like converting null to NaN. In
+ // the former case the NumberTextBox.filter() method calls this.inherited()
+ // to execute standard trimming code in TextBox.filter().
+ //
+ // TODO: break this into two methods in 2.0
+ //
+ // tags:
+ // protected extension
+ if(val === null){ return this._blankValue; }
+ if(typeof val != "string"){ return val; }
+ if(this.trim){
+ val = dojo.trim(val);
+ }
+ if(this.uppercase){
+ val = val.toUpperCase();
+ }
+ if(this.lowercase){
+ val = val.toLowerCase();
+ }
+ if(this.propercase){
+ val = val.replace(/[^\s]+/g, function(word){
+ return word.substring(0,1).toUpperCase() + word.substring(1);
+ });
+ }
+ return val;
+ },
+
+ _setBlurValue: function(){
+ this._setValueAttr(this.get('value'), true);
+ },
+
+ _onBlur: function(e){
+ if(this.disabled){ return; }
+ this._setBlurValue();
+ this.inherited(arguments);
+
+ if(this._selectOnClickHandle){
+ this.disconnect(this._selectOnClickHandle);
+ }
+ if(this.selectOnClick && dojo.isMoz){
+ this.textbox.selectionStart = this.textbox.selectionEnd = undefined; // clear selection so that the next mouse click doesn't reselect
+ }
+
+ },
+
+ _onFocus: function(/*String*/ by){
+ if(this.disabled || this.readOnly){ return; }
+
+ // Select all text on focus via click if nothing already selected.
+ // Since mouse-up will clear the selection need to defer selection until after mouse-up.
+ // Don't do anything on focus by tabbing into the widget since there's no associated mouse-up event.
+ if(this.selectOnClick && by == "mouse"){
+ this._selectOnClickHandle = this.connect(this.domNode, "onmouseup", function(){
+ // Only select all text on first click; otherwise users would have no way to clear
+ // the selection.
+ this.disconnect(this._selectOnClickHandle);
+
+ // Check if the user selected some text manually (mouse-down, mouse-move, mouse-up)
+ // and if not, then select all the text
+ var textIsNotSelected;
+ textIsNotSelected = this.textbox.selectionStart == this.textbox.selectionEnd;
+ if(textIsNotSelected){
+ this.selectInputText(this.textbox);
+ }
+ });
+ }
+
+ this._refreshState();
+ this.inherited(arguments);
+ },
+
+ reset: function(){
+ // Overrides dijit._FormWidget.reset().
+ // Additionally resets the displayed textbox value to ''
+ this.textbox.value = '';
+ this.inherited(arguments);
+ }
+ }
+);
+
+}
diff --git a/js/dojo-1.6/dojox/mobile/app/TextBox.xd.js b/js/dojo-1.6/dojox/mobile/app/TextBox.xd.js
new file mode 100644
index 0000000..ac55c3b
--- /dev/null
+++ b/js/dojo-1.6/dojox/mobile/app/TextBox.xd.js
@@ -0,0 +1,336 @@
+/*
+ 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
+*/
+
+
+dojo._xdResourceLoaded(function(dojo, dijit, dojox){
+return {depends: [["provide", "dojox.mobile.app.TextBox"],
+["require", "dojox.mobile.app._Widget"],
+["require", "dojox.mobile.app._FormWidget"]],
+defineResource: function(dojo, dijit, dojox){if(!dojo._hasResource["dojox.mobile.app.TextBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.mobile.app.TextBox"] = true;
+dojo.provide("dojox.mobile.app.TextBox");
+dojo.experimental("dojox.mobile.app.TextBox");
+
+dojo.require("dojox.mobile.app._Widget");
+dojo.require("dojox.mobile.app._FormWidget");
+
+dojo.declare(
+ "dojox.mobile.app.TextBox",
+ dojox.mobile.app._FormValueWidget, {
+
+ // summary:
+ // A base class for textbox form inputs
+
+ // trim: Boolean
+ // Removes leading and trailing whitespace if true. Default is false.
+ trim: false,
+
+ // uppercase: Boolean
+ // Converts all characters to uppercase if true. Default is false.
+ uppercase: false,
+
+ // lowercase: Boolean
+ // Converts all characters to lowercase if true. Default is false.
+ lowercase: false,
+
+ // propercase: Boolean
+ // Converts the first character of each word to uppercase if true.
+ propercase: false,
+
+ // maxLength: String
+ // HTML INPUT tag maxLength declaration.
+ maxLength: "",
+
+ // selectOnClick: [const] Boolean
+ // If true, all text will be selected when focused with mouse
+ selectOnClick: false,
+
+ // placeHolder: String
+ // Defines a hint to help users fill out the input field (as defined in HTML 5).
+ // This should only contain plain text (no html markup).
+ placeHolder: "",
+
+ baseClass: "mblTextBox",
+
+ attributeMap: dojo.delegate(dojox.mobile.app._FormValueWidget.prototype.attributeMap, {
+ maxLength: "focusNode"
+ }),
+
+ buildRendering: function(){
+ var node = this.srcNodeRef;
+
+ // If an input is used as the source node, wrap it in a div
+ if(!node || node.tagName != "INPUT"){
+ node = dojo.create("input", {});
+ }
+
+ dojo.attr(node, {
+ type: "text",
+ value: dojo.attr(node, "value") || "",
+ placeholder: this.placeHolder || null
+ });
+
+ this.domNode = this.textbox = this.focusNode = node;
+ },
+
+ _setPlaceHolderAttr: function(v){
+ this.placeHolder = v;
+ if(this.textbox){
+ dojo.attr(this.textbox, "placeholder", v);
+ }
+ },
+
+
+ _getValueAttr: function(){
+ // summary:
+ // Hook so attr('value') works as we like.
+ // description:
+ // For `dijit.form.TextBox` this basically returns the value of the <input>.
+ //
+ // For `dijit.form.MappedTextBox` subclasses, which have both
+ // a "displayed value" and a separate "submit value",
+ // This treats the "displayed value" as the master value, computing the
+ // submit value from it via this.parse().
+ return this.parse(this.get('displayedValue'), this.constraints);
+ },
+
+ _setValueAttr: function(value, /*Boolean?*/ priorityChange, /*String?*/ formattedValue){
+ // summary:
+ // Hook so attr('value', ...) works.
+ //
+ // description:
+ // Sets the value of the widget to "value" which can be of
+ // any type as determined by the widget.
+ //
+ // value:
+ // The visual element value is also set to a corresponding,
+ // but not necessarily the same, value.
+ //
+ // formattedValue:
+ // If specified, used to set the visual element value,
+ // otherwise a computed visual value is used.
+ //
+ // priorityChange:
+ // If true, an onChange event is fired immediately instead of
+ // waiting for the next blur event.
+
+ var filteredValue;
+ if(value !== undefined){
+ // TODO: this is calling filter() on both the display value and the actual value.
+ // I added a comment to the filter() definition about this, but it should be changed.
+ filteredValue = this.filter(value);
+ if(typeof formattedValue != "string"){
+ if(filteredValue !== null
+ && ((typeof filteredValue != "number") || !isNaN(filteredValue))){
+ formattedValue = this.filter(this.format(filteredValue, this.constraints));
+ }else{ formattedValue = ''; }
+ }
+ }
+ if(formattedValue != null && formattedValue != undefined
+ && ((typeof formattedValue) != "number" || !isNaN(formattedValue))
+ && this.textbox.value != formattedValue){
+ this.textbox.value = formattedValue;
+ }
+
+ this.inherited(arguments, [filteredValue, priorityChange]);
+ },
+
+ // displayedValue: String
+ // For subclasses like ComboBox where the displayed value
+ // (ex: Kentucky) and the serialized value (ex: KY) are different,
+ // this represents the displayed value.
+ //
+ // Setting 'displayedValue' through attr('displayedValue', ...)
+ // updates 'value', and vice-versa. Otherwise 'value' is updated
+ // from 'displayedValue' periodically, like onBlur etc.
+ //
+ // TODO: move declaration to MappedTextBox?
+ // Problem is that ComboBox references displayedValue,
+ // for benefit of FilteringSelect.
+ displayedValue: "",
+
+ _getDisplayedValueAttr: function(){
+ // summary:
+ // Hook so attr('displayedValue') works.
+ // description:
+ // Returns the displayed value (what the user sees on the screen),
+ // after filtering (ie, trimming spaces etc.).
+ //
+ // For some subclasses of TextBox (like ComboBox), the displayed value
+ // is different from the serialized value that's actually
+ // sent to the server (see dijit.form.ValidationTextBox.serialize)
+
+ return this.filter(this.textbox.value);
+ },
+
+ _setDisplayedValueAttr: function(/*String*/value){
+ // summary:
+ // Hook so attr('displayedValue', ...) works.
+ // description:
+ // Sets the value of the visual element to the string "value".
+ // The widget value is also set to a corresponding,
+ // but not necessarily the same, value.
+
+ if(value === null || value === undefined){ value = '' }
+ else if(typeof value != "string"){ value = String(value) }
+ this.textbox.value = value;
+ this._setValueAttr(this.get('value'), undefined, value);
+ },
+
+ format: function(/* String */ value, /* Object */ constraints){
+ // summary:
+ // Replacable function to convert a value to a properly formatted string.
+ // tags:
+ // protected extension
+ return ((value == null || value == undefined) ? "" : (value.toString ? value.toString() : value));
+ },
+
+ parse: function(/* String */ value, /* Object */ constraints){
+ // summary:
+ // Replacable function to convert a formatted string to a value
+ // tags:
+ // protected extension
+
+ return value; // String
+ },
+
+ _refreshState: function(){
+ // summary:
+ // After the user types some characters, etc., this method is
+ // called to check the field for validity etc. The base method
+ // in `dijit.form.TextBox` does nothing, but subclasses override.
+ // tags:
+ // protected
+ },
+
+ _onInput: function(e){
+ if(e && e.type && /key/i.test(e.type) && e.keyCode){
+ switch(e.keyCode){
+ case dojo.keys.SHIFT:
+ case dojo.keys.ALT:
+ case dojo.keys.CTRL:
+ case dojo.keys.TAB:
+ return;
+ }
+ }
+ if(this.intermediateChanges){
+ var _this = this;
+ // the setTimeout allows the key to post to the widget input box
+ setTimeout(function(){ _this._handleOnChange(_this.get('value'), false); }, 0);
+ }
+ this._refreshState();
+ },
+
+ postCreate: function(){
+ // setting the value here is needed since value="" in the template causes "undefined"
+ // and setting in the DOM (instead of the JS object) helps with form reset actions
+
+ this.textbox.setAttribute("value", this.textbox.value); // DOM and JS values shuld be the same
+ this.inherited(arguments);
+ if(dojo.isMoz || dojo.isOpera){
+ this.connect(this.textbox, "oninput", this._onInput);
+ }else{
+ this.connect(this.textbox, "onkeydown", this._onInput);
+ this.connect(this.textbox, "onkeyup", this._onInput);
+ this.connect(this.textbox, "onpaste", this._onInput);
+ this.connect(this.textbox, "oncut", this._onInput);
+ }
+ },
+
+ _blankValue: '', // if the textbox is blank, what value should be reported
+ filter: function(val){
+ // summary:
+ // Auto-corrections (such as trimming) that are applied to textbox
+ // value on blur or form submit.
+ // description:
+ // For MappedTextBox subclasses, this is called twice
+ // - once with the display value
+ // - once the value as set/returned by attr('value', ...)
+ // and attr('value'), ex: a Number for NumberTextBox.
+ //
+ // In the latter case it does corrections like converting null to NaN. In
+ // the former case the NumberTextBox.filter() method calls this.inherited()
+ // to execute standard trimming code in TextBox.filter().
+ //
+ // TODO: break this into two methods in 2.0
+ //
+ // tags:
+ // protected extension
+ if(val === null){ return this._blankValue; }
+ if(typeof val != "string"){ return val; }
+ if(this.trim){
+ val = dojo.trim(val);
+ }
+ if(this.uppercase){
+ val = val.toUpperCase();
+ }
+ if(this.lowercase){
+ val = val.toLowerCase();
+ }
+ if(this.propercase){
+ val = val.replace(/[^\s]+/g, function(word){
+ return word.substring(0,1).toUpperCase() + word.substring(1);
+ });
+ }
+ return val;
+ },
+
+ _setBlurValue: function(){
+ this._setValueAttr(this.get('value'), true);
+ },
+
+ _onBlur: function(e){
+ if(this.disabled){ return; }
+ this._setBlurValue();
+ this.inherited(arguments);
+
+ if(this._selectOnClickHandle){
+ this.disconnect(this._selectOnClickHandle);
+ }
+ if(this.selectOnClick && dojo.isMoz){
+ this.textbox.selectionStart = this.textbox.selectionEnd = undefined; // clear selection so that the next mouse click doesn't reselect
+ }
+
+ },
+
+ _onFocus: function(/*String*/ by){
+ if(this.disabled || this.readOnly){ return; }
+
+ // Select all text on focus via click if nothing already selected.
+ // Since mouse-up will clear the selection need to defer selection until after mouse-up.
+ // Don't do anything on focus by tabbing into the widget since there's no associated mouse-up event.
+ if(this.selectOnClick && by == "mouse"){
+ this._selectOnClickHandle = this.connect(this.domNode, "onmouseup", function(){
+ // Only select all text on first click; otherwise users would have no way to clear
+ // the selection.
+ this.disconnect(this._selectOnClickHandle);
+
+ // Check if the user selected some text manually (mouse-down, mouse-move, mouse-up)
+ // and if not, then select all the text
+ var textIsNotSelected;
+ textIsNotSelected = this.textbox.selectionStart == this.textbox.selectionEnd;
+ if(textIsNotSelected){
+ this.selectInputText(this.textbox);
+ }
+ });
+ }
+
+ this._refreshState();
+ this.inherited(arguments);
+ },
+
+ reset: function(){
+ // Overrides dijit._FormWidget.reset().
+ // Additionally resets the displayed textbox value to ''
+ this.textbox.value = '';
+ this.inherited(arguments);
+ }
+ }
+);
+
+}
+
+}};});
diff --git a/js/dojo-1.6/dojox/mobile/app/_FormWidget.js b/js/dojo-1.6/dojox/mobile/app/_FormWidget.js
new file mode 100644
index 0000000..ccf0091
--- /dev/null
+++ b/js/dojo-1.6/dojox/mobile/app/_FormWidget.js
@@ -0,0 +1,298 @@
+/*
+ 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
+*/
+
+
+if(!dojo._hasResource["dojox.mobile.app._FormWidget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.mobile.app._FormWidget"] = true;
+dojo.provide("dojox.mobile.app._FormWidget");
+dojo.experimental("dojox.mobile.app._FormWidget");
+
+dojo.require("dojo.window");
+
+dojo.require("dijit._WidgetBase");
+
+dojo.declare("dojox.mobile.app._FormWidget", dijit._WidgetBase, {
+ // summary:
+ // Base class for widgets corresponding to native HTML elements such as <checkbox> or <button>,
+ // which can be children of a <form> node or a `dojox.mobile.app.Form` widget.
+ //
+ // description:
+ // Represents a single HTML element.
+ // All these widgets should have these attributes just like native HTML input elements.
+ // You can set them during widget construction or afterwards, via `dijit._WidgetBase.attr`.
+ //
+ // They also share some common methods.
+
+ // name: String
+ // Name used when submitting form; same as "name" attribute or plain HTML elements
+ name: "",
+
+ // alt: String
+ // Corresponds to the native HTML <input> element's attribute.
+ alt: "",
+
+ // value: String
+ // Corresponds to the native HTML <input> element's attribute.
+ value: "",
+
+ // type: String
+ // Corresponds to the native HTML <input> element's attribute.
+ type: "text",
+
+ // disabled: Boolean
+ // Should this widget respond to user input?
+ // In markup, this is specified as "disabled='disabled'", or just "disabled".
+ disabled: false,
+
+ // intermediateChanges: Boolean
+ // Fires onChange for each value change or only on demand
+ intermediateChanges: false,
+
+ // scrollOnFocus: Boolean
+ // On focus, should this widget scroll into view?
+ scrollOnFocus: false,
+
+ // These mixins assume that the focus node is an INPUT, as many but not all _FormWidgets are.
+ attributeMap: dojo.delegate(dijit._WidgetBase.prototype.attributeMap, {
+ value: "focusNode",
+ id: "focusNode",
+ alt: "focusNode",
+ title: "focusNode"
+ }),
+
+ postMixInProperties: function(){
+ // Setup name=foo string to be referenced from the template (but only if a name has been specified)
+ // Unfortunately we can't use attributeMap to set the name due to IE limitations, see #8660
+ // Regarding escaping, see heading "Attribute values" in
+ // http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2
+ this.nameAttrSetting = this.name ? ('name="' + this.name.replace(/'/g, "&quot;") + '"') : '';
+ this.inherited(arguments);
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+ this.connect(this.domNode, "onmousedown", "_onMouseDown");
+ },
+
+ _setDisabledAttr: function(/*Boolean*/ value){
+ this.disabled = value;
+ dojo.attr(this.focusNode, 'disabled', value);
+ if(this.valueNode){
+ dojo.attr(this.valueNode, 'disabled', value);
+ }
+ },
+
+ _onFocus: function(e){
+ if(this.scrollOnFocus){
+ dojo.window.scrollIntoView(this.domNode);
+ }
+ this.inherited(arguments);
+ },
+
+ isFocusable: function(){
+ // summary:
+ // Tells if this widget is focusable or not. Used internally by dijit.
+ // tags:
+ // protected
+ return !this.disabled && !this.readOnly
+ && this.focusNode && (dojo.style(this.domNode, "display") != "none");
+ },
+
+ focus: function(){
+ // summary:
+ // Put focus on this widget
+ this.focusNode.focus();
+ },
+
+ compare: function(/*anything*/val1, /*anything*/val2){
+ // summary:
+ // Compare 2 values (as returned by attr('value') for this widget).
+ // tags:
+ // protected
+ if(typeof val1 == "number" && typeof val2 == "number"){
+ return (isNaN(val1) && isNaN(val2)) ? 0 : val1 - val2;
+ }else if(val1 > val2){
+ return 1;
+ }else if(val1 < val2){
+ return -1;
+ }else{
+ return 0;
+ }
+ },
+
+ onChange: function(newValue){
+ // summary:
+ // Callback when this widget's value is changed.
+ // tags:
+ // callback
+ },
+
+ // _onChangeActive: [private] Boolean
+ // Indicates that changes to the value should call onChange() callback.
+ // This is false during widget initialization, to avoid calling onChange()
+ // when the initial value is set.
+ _onChangeActive: false,
+
+ _handleOnChange: function(/*anything*/ newValue, /* Boolean? */ priorityChange){
+ // summary:
+ // Called when the value of the widget is set. Calls onChange() if appropriate
+ // newValue:
+ // the new value
+ // priorityChange:
+ // For a slider, for example, dragging the slider is priorityChange==false,
+ // but on mouse up, it's priorityChange==true. If intermediateChanges==true,
+ // onChange is only called form priorityChange=true events.
+ // tags:
+ // private
+ this._lastValue = newValue;
+ if(this._lastValueReported == undefined && (priorityChange === null || !this._onChangeActive)){
+ // this block executes not for a change, but during initialization,
+ // and is used to store away the original value (or for ToggleButton, the original checked state)
+ this._resetValue = this._lastValueReported = newValue;
+ }
+ if((this.intermediateChanges || priorityChange || priorityChange === undefined) &&
+ ((typeof newValue != typeof this._lastValueReported) ||
+ this.compare(newValue, this._lastValueReported) != 0)){
+ this._lastValueReported = newValue;
+ if(this._onChangeActive){
+ if(this._onChangeHandle){
+ clearTimeout(this._onChangeHandle);
+ }
+ // setTimout allows hidden value processing to run and
+ // also the onChange handler can safely adjust focus, etc
+ this._onChangeHandle = setTimeout(dojo.hitch(this,
+ function(){
+ this._onChangeHandle = null;
+ this.onChange(newValue);
+ }), 0); // try to collapse multiple onChange's fired faster than can be processed
+ }
+ }
+ },
+
+ create: function(){
+ // Overrides _Widget.create()
+ this.inherited(arguments);
+ this._onChangeActive = true;
+ },
+
+ destroy: function(){
+ if(this._onChangeHandle){ // destroy called before last onChange has fired
+ clearTimeout(this._onChangeHandle);
+ this.onChange(this._lastValueReported);
+ }
+ this.inherited(arguments);
+ },
+
+ _onMouseDown: function(e){
+ // If user clicks on the button, even if the mouse is released outside of it,
+ // this button should get focus (to mimics native browser buttons).
+ // This is also needed on chrome because otherwise buttons won't get focus at all,
+ // which leads to bizarre focus restore on Dialog close etc.
+ if(this.isFocusable()){
+ // Set a global event to handle mouseup, so it fires properly
+ // even if the cursor leaves this.domNode before the mouse up event.
+ var mouseUpConnector = this.connect(dojo.body(), "onmouseup", function(){
+ if(this.isFocusable()){
+ this.focus();
+ }
+ this.disconnect(mouseUpConnector);
+ });
+ }
+ },
+
+ selectInputText: function(/*DomNode*/element, /*Number?*/ start, /*Number?*/ stop){
+ // summary:
+ // Select text in the input element argument, from start (default 0), to stop (default end).
+
+ // TODO: use functions in _editor/selection.js?
+ var _window = dojo.global;
+ var _document = dojo.doc;
+ element = dojo.byId(element);
+ if(isNaN(start)){ start = 0; }
+ if(isNaN(stop)){ stop = element.value ? element.value.length : 0; }
+ dijit.focus(element);
+
+ if(_window["getSelection"] && element.setSelectionRange){
+ element.setSelectionRange(start, stop);
+ }
+ }
+});
+
+dojo.declare("dojox.mobile.app._FormValueWidget", dojox.mobile.app._FormWidget,
+{
+ // summary:
+ // Base class for widgets corresponding to native HTML elements such as <input> or <select> that have user changeable values.
+ // description:
+ // Each _FormValueWidget represents a single input value, and has a (possibly hidden) <input> element,
+ // to which it serializes it's input value, so that form submission (either normal submission or via FormBind?)
+ // works as expected.
+
+ // Don't attempt to mixin the 'type', 'name' attributes here programatically -- they must be declared
+ // directly in the template as read by the parser in order to function. IE is known to specifically
+ // require the 'name' attribute at element creation time. See #8484, #8660.
+ // TODO: unclear what that {value: ""} is for; FormWidget.attributeMap copies value to focusNode,
+ // so maybe {value: ""} is so the value *doesn't* get copied to focusNode?
+ // Seems like we really want value removed from attributeMap altogether
+ // (although there's no easy way to do that now)
+
+ // readOnly: Boolean
+ // Should this widget respond to user input?
+ // In markup, this is specified as "readOnly".
+ // Similar to disabled except readOnly form values are submitted.
+ readOnly: false,
+
+ attributeMap: dojo.delegate(dojox.mobile.app._FormWidget.prototype.attributeMap, {
+ value: "",
+ readOnly: "focusNode"
+ }),
+
+ _setReadOnlyAttr: function(/*Boolean*/ value){
+ this.readOnly = value;
+ dojo.attr(this.focusNode, 'readOnly', value);
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+
+ // Update our reset value if it hasn't yet been set (because this.set()
+ // is only called when there *is* a value)
+ if(this._resetValue === undefined){
+ this._resetValue = this.value;
+ }
+ },
+
+ _setValueAttr: function(/*anything*/ newValue, /*Boolean, optional*/ priorityChange){
+ // summary:
+ // Hook so attr('value', value) works.
+ // description:
+ // Sets the value of the widget.
+ // If the value has changed, then fire onChange event, unless priorityChange
+ // is specified as null (or false?)
+ this.value = newValue;
+ this._handleOnChange(newValue, priorityChange);
+ },
+
+ _getValueAttr: function(){
+ // summary:
+ // Hook so attr('value') works.
+ return this._lastValue;
+ },
+
+ undo: function(){
+ // summary:
+ // Restore the value to the last value passed to onChange
+ this._setValueAttr(this._lastValueReported, false);
+ },
+
+ reset: function(){
+ // summary:
+ // Reset the widget's value to what it was at initialization time
+ this._hasBeenBlurred = false;
+ this._setValueAttr(this._resetValue, true);
+ }
+});
+
+}
diff --git a/js/dojo-1.6/dojox/mobile/app/_FormWidget.xd.js b/js/dojo-1.6/dojox/mobile/app/_FormWidget.xd.js
new file mode 100644
index 0000000..e668725
--- /dev/null
+++ b/js/dojo-1.6/dojox/mobile/app/_FormWidget.xd.js
@@ -0,0 +1,304 @@
+/*
+ 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
+*/
+
+
+dojo._xdResourceLoaded(function(dojo, dijit, dojox){
+return {depends: [["provide", "dojox.mobile.app._FormWidget"],
+["require", "dojo.window"],
+["require", "dijit._WidgetBase"]],
+defineResource: function(dojo, dijit, dojox){if(!dojo._hasResource["dojox.mobile.app._FormWidget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.mobile.app._FormWidget"] = true;
+dojo.provide("dojox.mobile.app._FormWidget");
+dojo.experimental("dojox.mobile.app._FormWidget");
+
+dojo.require("dojo.window");
+
+dojo.require("dijit._WidgetBase");
+
+dojo.declare("dojox.mobile.app._FormWidget", dijit._WidgetBase, {
+ // summary:
+ // Base class for widgets corresponding to native HTML elements such as <checkbox> or <button>,
+ // which can be children of a <form> node or a `dojox.mobile.app.Form` widget.
+ //
+ // description:
+ // Represents a single HTML element.
+ // All these widgets should have these attributes just like native HTML input elements.
+ // You can set them during widget construction or afterwards, via `dijit._WidgetBase.attr`.
+ //
+ // They also share some common methods.
+
+ // name: String
+ // Name used when submitting form; same as "name" attribute or plain HTML elements
+ name: "",
+
+ // alt: String
+ // Corresponds to the native HTML <input> element's attribute.
+ alt: "",
+
+ // value: String
+ // Corresponds to the native HTML <input> element's attribute.
+ value: "",
+
+ // type: String
+ // Corresponds to the native HTML <input> element's attribute.
+ type: "text",
+
+ // disabled: Boolean
+ // Should this widget respond to user input?
+ // In markup, this is specified as "disabled='disabled'", or just "disabled".
+ disabled: false,
+
+ // intermediateChanges: Boolean
+ // Fires onChange for each value change or only on demand
+ intermediateChanges: false,
+
+ // scrollOnFocus: Boolean
+ // On focus, should this widget scroll into view?
+ scrollOnFocus: false,
+
+ // These mixins assume that the focus node is an INPUT, as many but not all _FormWidgets are.
+ attributeMap: dojo.delegate(dijit._WidgetBase.prototype.attributeMap, {
+ value: "focusNode",
+ id: "focusNode",
+ alt: "focusNode",
+ title: "focusNode"
+ }),
+
+ postMixInProperties: function(){
+ // Setup name=foo string to be referenced from the template (but only if a name has been specified)
+ // Unfortunately we can't use attributeMap to set the name due to IE limitations, see #8660
+ // Regarding escaping, see heading "Attribute values" in
+ // http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2
+ this.nameAttrSetting = this.name ? ('name="' + this.name.replace(/'/g, "&quot;") + '"') : '';
+ this.inherited(arguments);
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+ this.connect(this.domNode, "onmousedown", "_onMouseDown");
+ },
+
+ _setDisabledAttr: function(/*Boolean*/ value){
+ this.disabled = value;
+ dojo.attr(this.focusNode, 'disabled', value);
+ if(this.valueNode){
+ dojo.attr(this.valueNode, 'disabled', value);
+ }
+ },
+
+ _onFocus: function(e){
+ if(this.scrollOnFocus){
+ dojo.window.scrollIntoView(this.domNode);
+ }
+ this.inherited(arguments);
+ },
+
+ isFocusable: function(){
+ // summary:
+ // Tells if this widget is focusable or not. Used internally by dijit.
+ // tags:
+ // protected
+ return !this.disabled && !this.readOnly
+ && this.focusNode && (dojo.style(this.domNode, "display") != "none");
+ },
+
+ focus: function(){
+ // summary:
+ // Put focus on this widget
+ this.focusNode.focus();
+ },
+
+ compare: function(/*anything*/val1, /*anything*/val2){
+ // summary:
+ // Compare 2 values (as returned by attr('value') for this widget).
+ // tags:
+ // protected
+ if(typeof val1 == "number" && typeof val2 == "number"){
+ return (isNaN(val1) && isNaN(val2)) ? 0 : val1 - val2;
+ }else if(val1 > val2){
+ return 1;
+ }else if(val1 < val2){
+ return -1;
+ }else{
+ return 0;
+ }
+ },
+
+ onChange: function(newValue){
+ // summary:
+ // Callback when this widget's value is changed.
+ // tags:
+ // callback
+ },
+
+ // _onChangeActive: [private] Boolean
+ // Indicates that changes to the value should call onChange() callback.
+ // This is false during widget initialization, to avoid calling onChange()
+ // when the initial value is set.
+ _onChangeActive: false,
+
+ _handleOnChange: function(/*anything*/ newValue, /* Boolean? */ priorityChange){
+ // summary:
+ // Called when the value of the widget is set. Calls onChange() if appropriate
+ // newValue:
+ // the new value
+ // priorityChange:
+ // For a slider, for example, dragging the slider is priorityChange==false,
+ // but on mouse up, it's priorityChange==true. If intermediateChanges==true,
+ // onChange is only called form priorityChange=true events.
+ // tags:
+ // private
+ this._lastValue = newValue;
+ if(this._lastValueReported == undefined && (priorityChange === null || !this._onChangeActive)){
+ // this block executes not for a change, but during initialization,
+ // and is used to store away the original value (or for ToggleButton, the original checked state)
+ this._resetValue = this._lastValueReported = newValue;
+ }
+ if((this.intermediateChanges || priorityChange || priorityChange === undefined) &&
+ ((typeof newValue != typeof this._lastValueReported) ||
+ this.compare(newValue, this._lastValueReported) != 0)){
+ this._lastValueReported = newValue;
+ if(this._onChangeActive){
+ if(this._onChangeHandle){
+ clearTimeout(this._onChangeHandle);
+ }
+ // setTimout allows hidden value processing to run and
+ // also the onChange handler can safely adjust focus, etc
+ this._onChangeHandle = setTimeout(dojo.hitch(this,
+ function(){
+ this._onChangeHandle = null;
+ this.onChange(newValue);
+ }), 0); // try to collapse multiple onChange's fired faster than can be processed
+ }
+ }
+ },
+
+ create: function(){
+ // Overrides _Widget.create()
+ this.inherited(arguments);
+ this._onChangeActive = true;
+ },
+
+ destroy: function(){
+ if(this._onChangeHandle){ // destroy called before last onChange has fired
+ clearTimeout(this._onChangeHandle);
+ this.onChange(this._lastValueReported);
+ }
+ this.inherited(arguments);
+ },
+
+ _onMouseDown: function(e){
+ // If user clicks on the button, even if the mouse is released outside of it,
+ // this button should get focus (to mimics native browser buttons).
+ // This is also needed on chrome because otherwise buttons won't get focus at all,
+ // which leads to bizarre focus restore on Dialog close etc.
+ if(this.isFocusable()){
+ // Set a global event to handle mouseup, so it fires properly
+ // even if the cursor leaves this.domNode before the mouse up event.
+ var mouseUpConnector = this.connect(dojo.body(), "onmouseup", function(){
+ if(this.isFocusable()){
+ this.focus();
+ }
+ this.disconnect(mouseUpConnector);
+ });
+ }
+ },
+
+ selectInputText: function(/*DomNode*/element, /*Number?*/ start, /*Number?*/ stop){
+ // summary:
+ // Select text in the input element argument, from start (default 0), to stop (default end).
+
+ // TODO: use functions in _editor/selection.js?
+ var _window = dojo.global;
+ var _document = dojo.doc;
+ element = dojo.byId(element);
+ if(isNaN(start)){ start = 0; }
+ if(isNaN(stop)){ stop = element.value ? element.value.length : 0; }
+ dijit.focus(element);
+
+ if(_window["getSelection"] && element.setSelectionRange){
+ element.setSelectionRange(start, stop);
+ }
+ }
+});
+
+dojo.declare("dojox.mobile.app._FormValueWidget", dojox.mobile.app._FormWidget,
+{
+ // summary:
+ // Base class for widgets corresponding to native HTML elements such as <input> or <select> that have user changeable values.
+ // description:
+ // Each _FormValueWidget represents a single input value, and has a (possibly hidden) <input> element,
+ // to which it serializes it's input value, so that form submission (either normal submission or via FormBind?)
+ // works as expected.
+
+ // Don't attempt to mixin the 'type', 'name' attributes here programatically -- they must be declared
+ // directly in the template as read by the parser in order to function. IE is known to specifically
+ // require the 'name' attribute at element creation time. See #8484, #8660.
+ // TODO: unclear what that {value: ""} is for; FormWidget.attributeMap copies value to focusNode,
+ // so maybe {value: ""} is so the value *doesn't* get copied to focusNode?
+ // Seems like we really want value removed from attributeMap altogether
+ // (although there's no easy way to do that now)
+
+ // readOnly: Boolean
+ // Should this widget respond to user input?
+ // In markup, this is specified as "readOnly".
+ // Similar to disabled except readOnly form values are submitted.
+ readOnly: false,
+
+ attributeMap: dojo.delegate(dojox.mobile.app._FormWidget.prototype.attributeMap, {
+ value: "",
+ readOnly: "focusNode"
+ }),
+
+ _setReadOnlyAttr: function(/*Boolean*/ value){
+ this.readOnly = value;
+ dojo.attr(this.focusNode, 'readOnly', value);
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+
+ // Update our reset value if it hasn't yet been set (because this.set()
+ // is only called when there *is* a value)
+ if(this._resetValue === undefined){
+ this._resetValue = this.value;
+ }
+ },
+
+ _setValueAttr: function(/*anything*/ newValue, /*Boolean, optional*/ priorityChange){
+ // summary:
+ // Hook so attr('value', value) works.
+ // description:
+ // Sets the value of the widget.
+ // If the value has changed, then fire onChange event, unless priorityChange
+ // is specified as null (or false?)
+ this.value = newValue;
+ this._handleOnChange(newValue, priorityChange);
+ },
+
+ _getValueAttr: function(){
+ // summary:
+ // Hook so attr('value') works.
+ return this._lastValue;
+ },
+
+ undo: function(){
+ // summary:
+ // Restore the value to the last value passed to onChange
+ this._setValueAttr(this._lastValueReported, false);
+ },
+
+ reset: function(){
+ // summary:
+ // Reset the widget's value to what it was at initialization time
+ this._hasBeenBlurred = false;
+ this._setValueAttr(this._resetValue, true);
+ }
+});
+
+}
+
+}};});
diff --git a/js/dojo-1.6/dojox/mobile/app/_Widget.js b/js/dojo-1.6/dojox/mobile/app/_Widget.js
new file mode 100644
index 0000000..27f16e0
--- /dev/null
+++ b/js/dojo-1.6/dojox/mobile/app/_Widget.js
@@ -0,0 +1,41 @@
+/*
+ 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
+*/
+
+
+if(!dojo._hasResource["dojox.mobile.app._Widget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.mobile.app._Widget"] = true;
+dojo.provide("dojox.mobile.app._Widget");
+dojo.experimental("dojox.mobile.app._Widget");
+
+dojo.require("dijit._WidgetBase");
+
+dojo.declare("dojox.mobile.app._Widget", dijit._WidgetBase, {
+ // summary:
+ // The base mobile app widget.
+
+ getScroll: function(){
+ // summary:
+ // Returns the scroll position.
+ return {
+ x: dojo.global.scrollX,
+ y: dojo.global.scrollY
+ };
+ },
+
+ connect: function(target, event, fn){
+ if(event.toLowerCase() == "dblclick"
+ || event.toLowerCase() == "ondblclick"){
+
+ if(dojo.global["Mojo"]){
+ // Handle webOS tap event
+ return this.connect(target, Mojo.Event.tap, fn);
+ }
+ }
+ return this.inherited(arguments);
+ }
+});
+
+}
diff --git a/js/dojo-1.6/dojox/mobile/app/_Widget.xd.js b/js/dojo-1.6/dojox/mobile/app/_Widget.xd.js
new file mode 100644
index 0000000..fe33b75
--- /dev/null
+++ b/js/dojo-1.6/dojox/mobile/app/_Widget.xd.js
@@ -0,0 +1,46 @@
+/*
+ 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
+*/
+
+
+dojo._xdResourceLoaded(function(dojo, dijit, dojox){
+return {depends: [["provide", "dojox.mobile.app._Widget"],
+["require", "dijit._WidgetBase"]],
+defineResource: function(dojo, dijit, dojox){if(!dojo._hasResource["dojox.mobile.app._Widget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.mobile.app._Widget"] = true;
+dojo.provide("dojox.mobile.app._Widget");
+dojo.experimental("dojox.mobile.app._Widget");
+
+dojo.require("dijit._WidgetBase");
+
+dojo.declare("dojox.mobile.app._Widget", dijit._WidgetBase, {
+ // summary:
+ // The base mobile app widget.
+
+ getScroll: function(){
+ // summary:
+ // Returns the scroll position.
+ return {
+ x: dojo.global.scrollX,
+ y: dojo.global.scrollY
+ };
+ },
+
+ connect: function(target, event, fn){
+ if(event.toLowerCase() == "dblclick"
+ || event.toLowerCase() == "ondblclick"){
+
+ if(dojo.global["Mojo"]){
+ // Handle webOS tap event
+ return this.connect(target, Mojo.Event.tap, fn);
+ }
+ }
+ return this.inherited(arguments);
+ }
+});
+
+}
+
+}};});
diff --git a/js/dojo-1.6/dojox/mobile/app/_base.js b/js/dojo-1.6/dojox/mobile/app/_base.js
new file mode 100644
index 0000000..22eb17a
--- /dev/null
+++ b/js/dojo-1.6/dojox/mobile/app/_base.js
@@ -0,0 +1,248 @@
+/*
+ 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
+*/
+
+
+if(!dojo._hasResource["dojox.mobile.app._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.mobile.app._base"] = true;
+dojo.provide("dojox.mobile.app._base");
+dojo.experimental("dojox.mobile.app._base");
+
+dojo.require("dijit._base");
+dojo.require("dijit._WidgetBase");
+dojo.require("dojox.mobile");
+dojo.require("dojox.mobile.parser");
+
+dojo.require("dojox.mobile.app._event");
+dojo.require("dojox.mobile.app._Widget");
+dojo.require("dojox.mobile.app.StageController");
+dojo.require("dojox.mobile.app.SceneController");
+dojo.require("dojox.mobile.app.SceneAssistant");
+dojo.require("dojox.mobile.app.AlertDialog");
+dojo.require("dojox.mobile.app.List");
+dojo.require("dojox.mobile.app.ListSelector");
+dojo.require("dojox.mobile.app.TextBox");
+dojo.require("dojox.mobile.app.ImageView");
+dojo.require("dojox.mobile.app.ImageThumbView");
+
+(function(){
+
+ var stageController;
+ var appInfo;
+
+ var jsDependencies = [
+ "dojox.mobile",
+ "dojox.mobile.parser"
+ ];
+
+ var loadedResources = {};
+ var loadingDependencies;
+
+ var rootNode;
+
+ var sceneResources = [];
+
+ // Load the required resources asynchronously, since not all mobile OSes
+ // support dojo.require and sync XHR
+ function loadResources(resources, callback){
+ // summary:
+ // Loads one or more JavaScript files asynchronously. When complete,
+ // the first scene is pushed onto the stack.
+ // resources:
+ // An array of module names, e.g. 'dojox.mobile.AlertDialog'
+
+ var resource;
+ var url;
+
+ do {
+ resource = resources.pop();
+ if (resource.source) {
+ url = resource.source;
+ }else if (resource.module) {
+ url = dojo.baseUrl + dojo._getModuleSymbols(resource.module).join("/") + '.js';
+ }else {
+ alert("Error: invalid JavaScript resource " + dojo.toJson(resource));
+ return;
+ }
+ }while (resources.length > 0 && loadedResources[url]);
+
+ if(resources.length < 1 && loadedResources[url]){
+ // All resources have already been loaded
+ callback();
+ return;
+ }
+
+ dojo.xhrGet({
+ url: url,
+ sync: false
+ }).addCallbacks(function(text){
+ dojo["eval"](text);
+ loadedResources[url] = true;
+ if(resources.length > 0){
+ loadResources(resources, callback);
+ }else{
+ callback();
+ }
+ },
+ function(){
+ alert("Failed to load resource " + url);
+ });
+ }
+
+ var pushFirstScene = function(){
+ // summary:
+ // Pushes the first scene onto the stack.
+
+ stageController = new dojox.mobile.app.StageController(rootNode);
+ var defaultInfo = {
+ id: "com.test.app",
+ version: "1.0.0",
+ initialScene: "main"
+ };
+
+ // If the application info has been defined, as it should be,
+ // use it.
+ if(dojo.global["appInfo"]){
+ dojo.mixin(defaultInfo, dojo.global["appInfo"]);
+ }
+ appInfo = dojox.mobile.app.info = defaultInfo;
+
+ // Set the document title from the app info title if it exists
+ if(appInfo.title){
+ var titleNode = dojo.query("head title")[0] ||
+ dojo.create("title", {},dojo.query("head")[0]);
+ document.title = appInfo.title;
+ }
+
+ stageController.pushScene(appInfo.initialScene);
+ };
+
+ var initBackButton = function(){
+ var hasNativeBack = false;
+ if(dojo.global.BackButton){
+ // Android phonegap support
+ BackButton.override();
+ dojo.connect(document, 'backKeyDown', function(e) {
+ dojo.publish("/dojox/mobile/app/goback");
+ });
+ hasNativeBack = true;
+ }else if(dojo.global.Mojo){
+ // TODO: add webOS support
+ }
+ if(hasNativeBack){
+ dojo.addClass(dojo.body(), "mblNativeBack");
+ }
+ };
+
+ dojo.mixin(dojox.mobile.app, {
+ init: function(node){
+ // summary:
+ // Initializes the mobile app. Creates the
+
+ rootNode = node || dojo.body();
+ dojox.mobile.app.STAGE_CONTROLLER_ACTIVE = true;
+
+ dojo.subscribe("/dojox/mobile/app/goback", function(){
+ stageController.popScene();
+ });
+
+ dojo.subscribe("/dojox/mobile/app/alert", function(params){
+ dojox.mobile.app.getActiveSceneController().showAlertDialog(params);
+ });
+
+ dojo.subscribe("/dojox/mobile/app/pushScene", function(sceneName, params){
+ stageController.pushScene(sceneName, params || {});
+ });
+
+ // Get the list of files to load per scene/view
+ dojo.xhrGet({
+ url: "view-resources.json",
+ load: function(data){
+ var resources = [];
+
+ if(data){
+ // Should be an array
+ sceneResources = data = dojo.fromJson(data);
+
+ // Get the list of files to load that have no scene
+ // specified, and therefore should be loaded on
+ // startup
+ for(var i = 0; i < data.length; i++){
+ if(!data[i].scene){
+ resources.push(data[i]);
+ }
+ }
+ }
+ if(resources.length > 0){
+ loadResources(resources, pushFirstScene);
+ }else{
+ pushFirstScene();
+ }
+ },
+ error: pushFirstScene
+ });
+
+ initBackButton();
+ },
+
+ getActiveSceneController: function(){
+ // summary:
+ // Gets the controller for the active scene.
+
+ return stageController.getActiveSceneController();
+ },
+
+ getStageController: function(){
+ // summary:
+ // Gets the stage controller.
+ return stageController;
+ },
+
+ loadResources: function(resources, callback){
+ loadResources(resources, callback);
+ },
+
+ loadResourcesForScene: function(sceneName, callback){
+ var resources = [];
+
+ // Get the list of files to load that have no scene
+ // specified, and therefore should be loaded on
+ // startup
+ for(var i = 0; i < sceneResources.length; i++){
+ if(sceneResources[i].scene == sceneName){
+ resources.push(sceneResources[i]);
+ }
+ }
+
+ if(resources.length > 0){
+ loadResources(resources, callback);
+ }else{
+ callback();
+ }
+ },
+
+ resolveTemplate: function(sceneName){
+ // summary:
+ // Given the name of a scene, returns the path to it's template
+ // file. For example, for a scene named 'main', the file
+ // returned is 'app/views/main/main-scene.html'
+ // This function can be overridden if it is desired to have
+ // a different name to file mapping.
+ return "app/views/" + sceneName + "/" + sceneName + "-scene.html";
+ },
+
+ resolveAssistant: function(sceneName){
+ // summary:
+ // Given the name of a scene, returns the path to it's assistant
+ // file. For example, for a scene named 'main', the file
+ // returned is 'app/assistants/main-assistant.js'
+ // This function can be overridden if it is desired to have
+ // a different name to file mapping.
+ return "app/assistants/" + sceneName + "-assistant.js";
+ }
+ });
+})();
+
+}
diff --git a/js/dojo-1.6/dojox/mobile/app/_base.xd.js b/js/dojo-1.6/dojox/mobile/app/_base.xd.js
new file mode 100644
index 0000000..36ba440
--- /dev/null
+++ b/js/dojo-1.6/dojox/mobile/app/_base.xd.js
@@ -0,0 +1,267 @@
+/*
+ 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
+*/
+
+
+dojo._xdResourceLoaded(function(dojo, dijit, dojox){
+return {depends: [["provide", "dojox.mobile.app._base"],
+["require", "dijit._base"],
+["require", "dijit._WidgetBase"],
+["require", "dojox.mobile"],
+["require", "dojox.mobile.parser"],
+["require", "dojox.mobile.app._event"],
+["require", "dojox.mobile.app._Widget"],
+["require", "dojox.mobile.app.StageController"],
+["require", "dojox.mobile.app.SceneController"],
+["require", "dojox.mobile.app.SceneAssistant"],
+["require", "dojox.mobile.app.AlertDialog"],
+["require", "dojox.mobile.app.List"],
+["require", "dojox.mobile.app.ListSelector"],
+["require", "dojox.mobile.app.TextBox"],
+["require", "dojox.mobile.app.ImageView"],
+["require", "dojox.mobile.app.ImageThumbView"]],
+defineResource: function(dojo, dijit, dojox){if(!dojo._hasResource["dojox.mobile.app._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.mobile.app._base"] = true;
+dojo.provide("dojox.mobile.app._base");
+dojo.experimental("dojox.mobile.app._base");
+
+dojo.require("dijit._base");
+dojo.require("dijit._WidgetBase");
+dojo.require("dojox.mobile");
+dojo.require("dojox.mobile.parser");
+
+dojo.require("dojox.mobile.app._event");
+dojo.require("dojox.mobile.app._Widget");
+dojo.require("dojox.mobile.app.StageController");
+dojo.require("dojox.mobile.app.SceneController");
+dojo.require("dojox.mobile.app.SceneAssistant");
+dojo.require("dojox.mobile.app.AlertDialog");
+dojo.require("dojox.mobile.app.List");
+dojo.require("dojox.mobile.app.ListSelector");
+dojo.require("dojox.mobile.app.TextBox");
+dojo.require("dojox.mobile.app.ImageView");
+dojo.require("dojox.mobile.app.ImageThumbView");
+
+(function(){
+
+ var stageController;
+ var appInfo;
+
+ var jsDependencies = [
+ "dojox.mobile",
+ "dojox.mobile.parser"
+ ];
+
+ var loadedResources = {};
+ var loadingDependencies;
+
+ var rootNode;
+
+ var sceneResources = [];
+
+ // Load the required resources asynchronously, since not all mobile OSes
+ // support dojo.require and sync XHR
+ function loadResources(resources, callback){
+ // summary:
+ // Loads one or more JavaScript files asynchronously. When complete,
+ // the first scene is pushed onto the stack.
+ // resources:
+ // An array of module names, e.g. 'dojox.mobile.AlertDialog'
+
+ var resource;
+ var url;
+
+ do {
+ resource = resources.pop();
+ if (resource.source) {
+ url = resource.source;
+ }else if (resource.module) {
+ url = dojo.baseUrl + dojo._getModuleSymbols(resource.module).join("/") + '.js';
+ }else {
+ alert("Error: invalid JavaScript resource " + dojo.toJson(resource));
+ return;
+ }
+ }while (resources.length > 0 && loadedResources[url]);
+
+ if(resources.length < 1 && loadedResources[url]){
+ // All resources have already been loaded
+ callback();
+ return;
+ }
+
+ dojo.xhrGet({
+ url: url,
+ sync: false
+ }).addCallbacks(function(text){
+ dojo["eval"](text);
+ loadedResources[url] = true;
+ if(resources.length > 0){
+ loadResources(resources, callback);
+ }else{
+ callback();
+ }
+ },
+ function(){
+ alert("Failed to load resource " + url);
+ });
+ }
+
+ var pushFirstScene = function(){
+ // summary:
+ // Pushes the first scene onto the stack.
+
+ stageController = new dojox.mobile.app.StageController(rootNode);
+ var defaultInfo = {
+ id: "com.test.app",
+ version: "1.0.0",
+ initialScene: "main"
+ };
+
+ // If the application info has been defined, as it should be,
+ // use it.
+ if(dojo.global["appInfo"]){
+ dojo.mixin(defaultInfo, dojo.global["appInfo"]);
+ }
+ appInfo = dojox.mobile.app.info = defaultInfo;
+
+ // Set the document title from the app info title if it exists
+ if(appInfo.title){
+ var titleNode = dojo.query("head title")[0] ||
+ dojo.create("title", {},dojo.query("head")[0]);
+ document.title = appInfo.title;
+ }
+
+ stageController.pushScene(appInfo.initialScene);
+ };
+
+ var initBackButton = function(){
+ var hasNativeBack = false;
+ if(dojo.global.BackButton){
+ // Android phonegap support
+ BackButton.override();
+ dojo.connect(document, 'backKeyDown', function(e) {
+ dojo.publish("/dojox/mobile/app/goback");
+ });
+ hasNativeBack = true;
+ }else if(dojo.global.Mojo){
+ // TODO: add webOS support
+ }
+ if(hasNativeBack){
+ dojo.addClass(dojo.body(), "mblNativeBack");
+ }
+ };
+
+ dojo.mixin(dojox.mobile.app, {
+ init: function(node){
+ // summary:
+ // Initializes the mobile app. Creates the
+
+ rootNode = node || dojo.body();
+ dojox.mobile.app.STAGE_CONTROLLER_ACTIVE = true;
+
+ dojo.subscribe("/dojox/mobile/app/goback", function(){
+ stageController.popScene();
+ });
+
+ dojo.subscribe("/dojox/mobile/app/alert", function(params){
+ dojox.mobile.app.getActiveSceneController().showAlertDialog(params);
+ });
+
+ dojo.subscribe("/dojox/mobile/app/pushScene", function(sceneName, params){
+ stageController.pushScene(sceneName, params || {});
+ });
+
+ // Get the list of files to load per scene/view
+ dojo.xhrGet({
+ url: "view-resources.json",
+ load: function(data){
+ var resources = [];
+
+ if(data){
+ // Should be an array
+ sceneResources = data = dojo.fromJson(data);
+
+ // Get the list of files to load that have no scene
+ // specified, and therefore should be loaded on
+ // startup
+ for(var i = 0; i < data.length; i++){
+ if(!data[i].scene){
+ resources.push(data[i]);
+ }
+ }
+ }
+ if(resources.length > 0){
+ loadResources(resources, pushFirstScene);
+ }else{
+ pushFirstScene();
+ }
+ },
+ error: pushFirstScene
+ });
+
+ initBackButton();
+ },
+
+ getActiveSceneController: function(){
+ // summary:
+ // Gets the controller for the active scene.
+
+ return stageController.getActiveSceneController();
+ },
+
+ getStageController: function(){
+ // summary:
+ // Gets the stage controller.
+ return stageController;
+ },
+
+ loadResources: function(resources, callback){
+ loadResources(resources, callback);
+ },
+
+ loadResourcesForScene: function(sceneName, callback){
+ var resources = [];
+
+ // Get the list of files to load that have no scene
+ // specified, and therefore should be loaded on
+ // startup
+ for(var i = 0; i < sceneResources.length; i++){
+ if(sceneResources[i].scene == sceneName){
+ resources.push(sceneResources[i]);
+ }
+ }
+
+ if(resources.length > 0){
+ loadResources(resources, callback);
+ }else{
+ callback();
+ }
+ },
+
+ resolveTemplate: function(sceneName){
+ // summary:
+ // Given the name of a scene, returns the path to it's template
+ // file. For example, for a scene named 'main', the file
+ // returned is 'app/views/main/main-scene.html'
+ // This function can be overridden if it is desired to have
+ // a different name to file mapping.
+ return "app/views/" + sceneName + "/" + sceneName + "-scene.html";
+ },
+
+ resolveAssistant: function(sceneName){
+ // summary:
+ // Given the name of a scene, returns the path to it's assistant
+ // file. For example, for a scene named 'main', the file
+ // returned is 'app/assistants/main-assistant.js'
+ // This function can be overridden if it is desired to have
+ // a different name to file mapping.
+ return "app/assistants/" + sceneName + "-assistant.js";
+ }
+ });
+})();
+
+}
+
+}};});
diff --git a/js/dojo-1.6/dojox/mobile/app/_event.js b/js/dojo-1.6/dojox/mobile/app/_event.js
new file mode 100644
index 0000000..27f73d1
--- /dev/null
+++ b/js/dojo-1.6/dojox/mobile/app/_event.js
@@ -0,0 +1,131 @@
+/*
+ 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
+*/
+
+
+if(!dojo._hasResource["dojox.mobile.app._event"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.mobile.app._event"] = true;
+dojo.provide("dojox.mobile.app._event");
+dojo.experimental("dojox.mobile.app._event.js");
+
+dojo.mixin(dojox.mobile.app, {
+ eventMap: {},
+
+ connectFlick: function(target, context, method){
+ // summary:
+ // Listens for a flick event on a DOM node. If the mouse/touch
+ // moves more than 15 pixels in any given direction it is a flick.
+ // The synthetic event fired specifies the direction as
+ // <ul>
+ // <li><b>'ltr'</b> Left To Right</li>
+ // <li><b>'rtl'</b> Right To Left</li>
+ // <li><b>'ttb'</b> Top To Bottom</li>
+ // <li><b>'btt'</b> Bottom To Top</li>
+ // </ul>
+ // target: Node
+ // The DOM node to connect to
+
+ var startX;
+ var startY;
+ var isFlick = false;
+
+ var currentX;
+ var currentY;
+
+ var connMove;
+ var connUp;
+
+ var direction;
+
+ var time;
+
+ // Listen to to the mousedown/touchstart event
+ var connDown = dojo.connect("onmousedown", target, function(event){
+ isFlick = false;
+ startX = event.targetTouches ? event.targetTouches[0].clientX : event.clientX;
+ startY = event.targetTouches ? event.targetTouches[0].clientY : event.clientY;
+
+ time = (new Date()).getTime();
+
+ connMove = dojo.connect(target, "onmousemove", onMove);
+ connUp = dojo.connect(target, "onmouseup", onUp);
+ });
+
+ // The function that handles the mousemove/touchmove event
+ var onMove = function(event){
+ dojo.stopEvent(event);
+
+ currentX = event.targetTouches ? event.targetTouches[0].clientX : event.clientX;
+ currentY = event.targetTouches ? event.targetTouches[0].clientY : event.clientY;
+ if(Math.abs(Math.abs(currentX) - Math.abs(startX)) > 15){
+ isFlick = true;
+
+ direction = (currentX > startX) ? "ltr" : "rtl";
+ }else if(Math.abs(Math.abs(currentY) - Math.abs(startY)) > 15){
+ isFlick = true;
+
+ direction = (currentY > startY) ? "ttb" : "btt";
+ }
+ };
+
+ var onUp = function(event){
+ dojo.stopEvent(event);
+
+ connMove && dojo.disconnect(connMove);
+ connUp && dojo.disconnect(connUp);
+
+ if(isFlick){
+ var flickEvt = {
+ target: target,
+ direction: direction,
+ duration: (new Date()).getTime() - time
+ };
+ if(context && method){
+ context[method](flickEvt);
+ }else{
+ method(flickEvt);
+ }
+ }
+ };
+
+ }
+});
+
+dojox.mobile.app.isIPhone = (dojo.isSafari
+ && (navigator.userAgent.indexOf("iPhone") > -1 ||
+ navigator.userAgent.indexOf("iPod") > -1
+ ));
+dojox.mobile.app.isWebOS = (navigator.userAgent.indexOf("webOS") > -1);
+dojox.mobile.app.isAndroid = (navigator.userAgent.toLowerCase().indexOf("android") > -1);
+
+if(dojox.mobile.app.isIPhone || dojox.mobile.app.isAndroid){
+ // We are touchable.
+ // Override the dojo._connect function to replace mouse events with touch events
+
+ dojox.mobile.app.eventMap = {
+ onmousedown: "ontouchstart",
+ mousedown: "ontouchstart",
+ onmouseup: "ontouchend",
+ mouseup: "ontouchend",
+ onmousemove: "ontouchmove",
+ mousemove: "ontouchmove"
+ };
+
+}
+dojo._oldConnect = dojo._connect;
+dojo._connect = function(obj, event, context, method, dontFix){
+ event = dojox.mobile.app.eventMap[event] || event;
+ if(event == "flick" || event == "onflick"){
+ if(dojo.global["Mojo"]){
+ event = Mojo.Event.flick;
+ }else{
+ return dojox.mobile.app.connectFlick(obj, context, method);
+ }
+ }
+
+ return dojo._oldConnect(obj, event, context, method, dontFix);
+}
+
+}
diff --git a/js/dojo-1.6/dojox/mobile/app/_event.xd.js b/js/dojo-1.6/dojox/mobile/app/_event.xd.js
new file mode 100644
index 0000000..6079ed7
--- /dev/null
+++ b/js/dojo-1.6/dojox/mobile/app/_event.xd.js
@@ -0,0 +1,135 @@
+/*
+ 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
+*/
+
+
+dojo._xdResourceLoaded(function(dojo, dijit, dojox){
+return {depends: [["provide", "dojox.mobile.app._event"]],
+defineResource: function(dojo, dijit, dojox){if(!dojo._hasResource["dojox.mobile.app._event"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.mobile.app._event"] = true;
+dojo.provide("dojox.mobile.app._event");
+dojo.experimental("dojox.mobile.app._event.js");
+
+dojo.mixin(dojox.mobile.app, {
+ eventMap: {},
+
+ connectFlick: function(target, context, method){
+ // summary:
+ // Listens for a flick event on a DOM node. If the mouse/touch
+ // moves more than 15 pixels in any given direction it is a flick.
+ // The synthetic event fired specifies the direction as
+ // <ul>
+ // <li><b>'ltr'</b> Left To Right</li>
+ // <li><b>'rtl'</b> Right To Left</li>
+ // <li><b>'ttb'</b> Top To Bottom</li>
+ // <li><b>'btt'</b> Bottom To Top</li>
+ // </ul>
+ // target: Node
+ // The DOM node to connect to
+
+ var startX;
+ var startY;
+ var isFlick = false;
+
+ var currentX;
+ var currentY;
+
+ var connMove;
+ var connUp;
+
+ var direction;
+
+ var time;
+
+ // Listen to to the mousedown/touchstart event
+ var connDown = dojo.connect("onmousedown", target, function(event){
+ isFlick = false;
+ startX = event.targetTouches ? event.targetTouches[0].clientX : event.clientX;
+ startY = event.targetTouches ? event.targetTouches[0].clientY : event.clientY;
+
+ time = (new Date()).getTime();
+
+ connMove = dojo.connect(target, "onmousemove", onMove);
+ connUp = dojo.connect(target, "onmouseup", onUp);
+ });
+
+ // The function that handles the mousemove/touchmove event
+ var onMove = function(event){
+ dojo.stopEvent(event);
+
+ currentX = event.targetTouches ? event.targetTouches[0].clientX : event.clientX;
+ currentY = event.targetTouches ? event.targetTouches[0].clientY : event.clientY;
+ if(Math.abs(Math.abs(currentX) - Math.abs(startX)) > 15){
+ isFlick = true;
+
+ direction = (currentX > startX) ? "ltr" : "rtl";
+ }else if(Math.abs(Math.abs(currentY) - Math.abs(startY)) > 15){
+ isFlick = true;
+
+ direction = (currentY > startY) ? "ttb" : "btt";
+ }
+ };
+
+ var onUp = function(event){
+ dojo.stopEvent(event);
+
+ connMove && dojo.disconnect(connMove);
+ connUp && dojo.disconnect(connUp);
+
+ if(isFlick){
+ var flickEvt = {
+ target: target,
+ direction: direction,
+ duration: (new Date()).getTime() - time
+ };
+ if(context && method){
+ context[method](flickEvt);
+ }else{
+ method(flickEvt);
+ }
+ }
+ };
+
+ }
+});
+
+dojox.mobile.app.isIPhone = (dojo.isSafari
+ && (navigator.userAgent.indexOf("iPhone") > -1 ||
+ navigator.userAgent.indexOf("iPod") > -1
+ ));
+dojox.mobile.app.isWebOS = (navigator.userAgent.indexOf("webOS") > -1);
+dojox.mobile.app.isAndroid = (navigator.userAgent.toLowerCase().indexOf("android") > -1);
+
+if(dojox.mobile.app.isIPhone || dojox.mobile.app.isAndroid){
+ // We are touchable.
+ // Override the dojo._connect function to replace mouse events with touch events
+
+ dojox.mobile.app.eventMap = {
+ onmousedown: "ontouchstart",
+ mousedown: "ontouchstart",
+ onmouseup: "ontouchend",
+ mouseup: "ontouchend",
+ onmousemove: "ontouchmove",
+ mousemove: "ontouchmove"
+ };
+
+}
+dojo._oldConnect = dojo._connect;
+dojo._connect = function(obj, event, context, method, dontFix){
+ event = dojox.mobile.app.eventMap[event] || event;
+ if(event == "flick" || event == "onflick"){
+ if(dojo.global["Mojo"]){
+ event = Mojo.Event.flick;
+ }else{
+ return dojox.mobile.app.connectFlick(obj, context, method);
+ }
+ }
+
+ return dojo._oldConnect(obj, event, context, method, dontFix);
+}
+
+}
+
+}};});
diff --git a/js/dojo-1.6/dojox/mobile/app/compat.js b/js/dojo-1.6/dojox/mobile/app/compat.js
new file mode 100644
index 0000000..98507af
--- /dev/null
+++ b/js/dojo-1.6/dojox/mobile/app/compat.js
@@ -0,0 +1,14 @@
+/*
+ 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
+*/
+
+if(!dojo._hasResource["dojo.uacss"]){dojo._hasResource["dojo.uacss"]=true;dojo.provide("dojo.uacss");(function(){var d=dojo,_1=d.doc.documentElement,ie=d.isIE,_2=d.isOpera,_3=Math.floor,ff=d.isFF,_4=d.boxModel.replace(/-/,""),_5={dj_ie:ie,dj_ie6:_3(ie)==6,dj_ie7:_3(ie)==7,dj_ie8:_3(ie)==8,dj_ie9:_3(ie)==9,dj_quirks:d.isQuirks,dj_iequirks:ie&&d.isQuirks,dj_opera:_2,dj_khtml:d.isKhtml,dj_webkit:d.isWebKit,dj_safari:d.isSafari,dj_chrome:d.isChrome,dj_gecko:d.isMozilla,dj_ff3:_3(ff)==3};_5["dj_"+_4]=true;var _6="";for(var _7 in _5){if(_5[_7]){_6+=_7+" ";}}_1.className=d.trim(_1.className+" "+_6);dojo._loaders.unshift(function(){if(!dojo._isBodyLtr()){var _8="dj_rtl dijitRtl "+_6.replace(/ /g,"-rtl ");_1.className=d.trim(_1.className+" "+_8);}});})();}if(!dojo._hasResource["dijit._base.sniff"]){dojo._hasResource["dijit._base.sniff"]=true;dojo.provide("dijit._base.sniff");}if(!dojo._hasResource["dojo.fx.Toggler"]){dojo._hasResource["dojo.fx.Toggler"]=true;dojo.provide("dojo.fx.Toggler");dojo.declare("dojo.fx.Toggler",null,{node:null,showFunc:dojo.fadeIn,hideFunc:dojo.fadeOut,showDuration:200,hideDuration:200,constructor:function(_9){var _a=this;dojo.mixin(_a,_9);_a.node=_9.node;_a._showArgs=dojo.mixin({},_9);_a._showArgs.node=_a.node;_a._showArgs.duration=_a.showDuration;_a.showAnim=_a.showFunc(_a._showArgs);_a._hideArgs=dojo.mixin({},_9);_a._hideArgs.node=_a.node;_a._hideArgs.duration=_a.hideDuration;_a.hideAnim=_a.hideFunc(_a._hideArgs);dojo.connect(_a.showAnim,"beforeBegin",dojo.hitch(_a.hideAnim,"stop",true));dojo.connect(_a.hideAnim,"beforeBegin",dojo.hitch(_a.showAnim,"stop",true));},show:function(_b){return this.showAnim.play(_b||0);},hide:function(_c){return this.hideAnim.play(_c||0);}});}if(!dojo._hasResource["dojo.fx"]){dojo._hasResource["dojo.fx"]=true;dojo.provide("dojo.fx");(function(){var d=dojo,_d={_fire:function(_e,_f){if(this[_e]){this[_e].apply(this,_f||[]);}return this;}};var _10=function(_11){this._index=-1;this._animations=_11||[];this._current=this._onAnimateCtx=this._onEndCtx=null;this.duration=0;d.forEach(this._animations,function(a){this.duration+=a.duration;if(a.delay){this.duration+=a.delay;}},this);};d.extend(_10,{_onAnimate:function(){this._fire("onAnimate",arguments);},_onEnd:function(){d.disconnect(this._onAnimateCtx);d.disconnect(this._onEndCtx);this._onAnimateCtx=this._onEndCtx=null;if(this._index+1==this._animations.length){this._fire("onEnd");}else{this._current=this._animations[++this._index];this._onAnimateCtx=d.connect(this._current,"onAnimate",this,"_onAnimate");this._onEndCtx=d.connect(this._current,"onEnd",this,"_onEnd");this._current.play(0,true);}},play:function(_12,_13){if(!this._current){this._current=this._animations[this._index=0];}if(!_13&&this._current.status()=="playing"){return this;}var _14=d.connect(this._current,"beforeBegin",this,function(){this._fire("beforeBegin");}),_15=d.connect(this._current,"onBegin",this,function(arg){this._fire("onBegin",arguments);}),_16=d.connect(this._current,"onPlay",this,function(arg){this._fire("onPlay",arguments);d.disconnect(_14);d.disconnect(_15);d.disconnect(_16);});if(this._onAnimateCtx){d.disconnect(this._onAnimateCtx);}this._onAnimateCtx=d.connect(this._current,"onAnimate",this,"_onAnimate");if(this._onEndCtx){d.disconnect(this._onEndCtx);}this._onEndCtx=d.connect(this._current,"onEnd",this,"_onEnd");this._current.play.apply(this._current,arguments);return this;},pause:function(){if(this._current){var e=d.connect(this._current,"onPause",this,function(arg){this._fire("onPause",arguments);d.disconnect(e);});this._current.pause();}return this;},gotoPercent:function(_17,_18){this.pause();var _19=this.duration*_17;this._current=null;d.some(this._animations,function(a){if(a.duration<=_19){this._current=a;return true;}_19-=a.duration;return false;});if(this._current){this._current.gotoPercent(_19/this._current.duration,_18);}return this;},stop:function(_1a){if(this._current){if(_1a){for(;this._index+1<this._animations.length;++this._index){this._animations[this._index].stop(true);}this._current=this._animations[this._index];}var e=d.connect(this._current,"onStop",this,function(arg){this._fire("onStop",arguments);d.disconnect(e);});this._current.stop();}return this;},status:function(){return this._current?this._current.status():"stopped";},destroy:function(){if(this._onAnimateCtx){d.disconnect(this._onAnimateCtx);}if(this._onEndCtx){d.disconnect(this._onEndCtx);}}});d.extend(_10,_d);dojo.fx.chain=function(_1b){return new _10(_1b);};var _1c=function(_1d){this._animations=_1d||[];this._connects=[];this._finished=0;this.duration=0;d.forEach(_1d,function(a){var _1e=a.duration;if(a.delay){_1e+=a.delay;}if(this.duration<_1e){this.duration=_1e;}this._connects.push(d.connect(a,"onEnd",this,"_onEnd"));},this);this._pseudoAnimation=new d.Animation({curve:[0,1],duration:this.duration});var _1f=this;d.forEach(["beforeBegin","onBegin","onPlay","onAnimate","onPause","onStop","onEnd"],function(evt){_1f._connects.push(d.connect(_1f._pseudoAnimation,evt,function(){_1f._fire(evt,arguments);}));});};d.extend(_1c,{_doAction:function(_20,_21){d.forEach(this._animations,function(a){a[_20].apply(a,_21);});return this;},_onEnd:function(){if(++this._finished>this._animations.length){this._fire("onEnd");}},_call:function(_22,_23){var t=this._pseudoAnimation;t[_22].apply(t,_23);},play:function(_24,_25){this._finished=0;this._doAction("play",arguments);this._call("play",arguments);return this;},pause:function(){this._doAction("pause",arguments);this._call("pause",arguments);return this;},gotoPercent:function(_26,_27){var ms=this.duration*_26;d.forEach(this._animations,function(a){a.gotoPercent(a.duration<ms?1:(ms/a.duration),_27);});this._call("gotoPercent",arguments);return this;},stop:function(_28){this._doAction("stop",arguments);this._call("stop",arguments);return this;},status:function(){return this._pseudoAnimation.status();},destroy:function(){d.forEach(this._connects,dojo.disconnect);}});d.extend(_1c,_d);dojo.fx.combine=function(_29){return new _1c(_29);};dojo.fx.wipeIn=function(_2a){var _2b=_2a.node=d.byId(_2a.node),s=_2b.style,o;var _2c=d.animateProperty(d.mixin({properties:{height:{start:function(){o=s.overflow;s.overflow="hidden";if(s.visibility=="hidden"||s.display=="none"){s.height="1px";s.display="";s.visibility="";return 1;}else{var _2d=d.style(_2b,"height");return Math.max(_2d,1);}},end:function(){return _2b.scrollHeight;}}}},_2a));d.connect(_2c,"onEnd",function(){s.height="auto";s.overflow=o;});return _2c;};dojo.fx.wipeOut=function(_2e){var _2f=_2e.node=d.byId(_2e.node),s=_2f.style,o;var _30=d.animateProperty(d.mixin({properties:{height:{end:1}}},_2e));d.connect(_30,"beforeBegin",function(){o=s.overflow;s.overflow="hidden";s.display="";});d.connect(_30,"onEnd",function(){s.overflow=o;s.height="auto";s.display="none";});return _30;};dojo.fx.slideTo=function(_31){var _32=_31.node=d.byId(_31.node),top=null,_33=null;var _34=(function(n){return function(){var cs=d.getComputedStyle(n);var pos=cs.position;top=(pos=="absolute"?n.offsetTop:parseInt(cs.top)||0);_33=(pos=="absolute"?n.offsetLeft:parseInt(cs.left)||0);if(pos!="absolute"&&pos!="relative"){var ret=d.position(n,true);top=ret.y;_33=ret.x;n.style.position="absolute";n.style.top=top+"px";n.style.left=_33+"px";}};})(_32);_34();var _35=d.animateProperty(d.mixin({properties:{top:_31.top||0,left:_31.left||0}},_31));d.connect(_35,"beforeBegin",_35,_34);return _35;};})();}if(!dojo._hasResource["dojox.fx.flip"]){dojo._hasResource["dojox.fx.flip"]=true;dojo.provide("dojox.fx.flip");dojo.experimental("dojox.fx.flip");var borderConst="border",widthConst="Width",heightConst="Height",topConst="Top",rightConst="Right",leftConst="Left",bottomConst="Bottom";dojox.fx.flip=function(_36){var _37=dojo.create("div"),_38=_36.node=dojo.byId(_36.node),s=_38.style,_39=null,hs=null,pn=null,_3a=_36.lightColor||"#dddddd",_3b=_36.darkColor||"#555555",_3c=dojo.style(_38,"backgroundColor"),_3d=_36.endColor||_3c,_3e={},_3f=[],_40=_36.duration?_36.duration/2:250,dir=_36.dir||"left",_41=0.9,_42="transparent",_43=_36.whichAnim,_44=_36.axis||"center",_45=_36.depth;var _46=function(_47){return ((new dojo.Color(_47)).toHex()==="#000000")?"#000001":_47;};if(dojo.isIE<7){_3d=_46(_3d);_3a=_46(_3a);_3b=_46(_3b);_3c=_46(_3c);_42="black";_37.style.filter="chroma(color='#000000')";}var _48=(function(n){return function(){var ret=dojo.coords(n,true);_39={top:ret.y,left:ret.x,width:ret.w,height:ret.h};};})(_38);_48();hs={position:"absolute",top:_39["top"]+"px",left:_39["left"]+"px",height:"0",width:"0",zIndex:_36.zIndex||(s.zIndex||0),border:"0 solid "+_42,fontSize:"0",visibility:"hidden"};var _49=[{},{top:_39["top"],left:_39["left"]}];var _4a={left:[leftConst,rightConst,topConst,bottomConst,widthConst,heightConst,"end"+heightConst+"Min",leftConst,"end"+heightConst+"Max"],right:[rightConst,leftConst,topConst,bottomConst,widthConst,heightConst,"end"+heightConst+"Min",leftConst,"end"+heightConst+"Max"],top:[topConst,bottomConst,leftConst,rightConst,heightConst,widthConst,"end"+widthConst+"Min",topConst,"end"+widthConst+"Max"],bottom:[bottomConst,topConst,leftConst,rightConst,heightConst,widthConst,"end"+widthConst+"Min",topConst,"end"+widthConst+"Max"]};pn=_4a[dir];if(typeof _45!="undefined"){_45=Math.max(0,Math.min(1,_45))/2;_41=0.4+(0.5-_45);}else{_41=Math.min(0.9,Math.max(0.4,_39[pn[5].toLowerCase()]/_39[pn[4].toLowerCase()]));}var p0=_49[0];for(var i=4;i<6;i++){if(_44=="center"||_44=="cube"){_39["end"+pn[i]+"Min"]=_39[pn[i].toLowerCase()]*_41;_39["end"+pn[i]+"Max"]=_39[pn[i].toLowerCase()]/_41;}else{if(_44=="shortside"){_39["end"+pn[i]+"Min"]=_39[pn[i].toLowerCase()];_39["end"+pn[i]+"Max"]=_39[pn[i].toLowerCase()]/_41;}else{if(_44=="longside"){_39["end"+pn[i]+"Min"]=_39[pn[i].toLowerCase()]*_41;_39["end"+pn[i]+"Max"]=_39[pn[i].toLowerCase()];}}}}if(_44=="center"){p0[pn[2].toLowerCase()]=_39[pn[2].toLowerCase()]-(_39[pn[8]]-_39[pn[6]])/4;}else{if(_44=="shortside"){p0[pn[2].toLowerCase()]=_39[pn[2].toLowerCase()]-(_39[pn[8]]-_39[pn[6]])/2;}}_3e[pn[5].toLowerCase()]=_39[pn[5].toLowerCase()]+"px";_3e[pn[4].toLowerCase()]="0";_3e[borderConst+pn[1]+widthConst]=_39[pn[4].toLowerCase()]+"px";_3e[borderConst+pn[1]+"Color"]=_3c;p0[borderConst+pn[1]+widthConst]=0;p0[borderConst+pn[1]+"Color"]=_3b;p0[borderConst+pn[2]+widthConst]=p0[borderConst+pn[3]+widthConst]=_44!="cube"?(_39["end"+pn[5]+"Max"]-_39["end"+pn[5]+"Min"])/2:_39[pn[6]]/2;p0[pn[7].toLowerCase()]=_39[pn[7].toLowerCase()]+_39[pn[4].toLowerCase()]/2+(_36.shift||0);p0[pn[5].toLowerCase()]=_39[pn[6]];var p1=_49[1];p1[borderConst+pn[0]+"Color"]={start:_3a,end:_3d};p1[borderConst+pn[0]+widthConst]=_39[pn[4].toLowerCase()];p1[borderConst+pn[2]+widthConst]=0;p1[borderConst+pn[3]+widthConst]=0;p1[pn[5].toLowerCase()]={start:_39[pn[6]],end:_39[pn[5].toLowerCase()]};dojo.mixin(hs,_3e);dojo.style(_37,hs);dojo.body().appendChild(_37);var _4b=function(){dojo.destroy(_37);s.backgroundColor=_3d;s.visibility="visible";};if(_43=="last"){for(i in p0){p0[i]={start:p0[i]};}p0[borderConst+pn[1]+"Color"]={start:_3b,end:_3d};p1=p0;}if(!_43||_43=="first"){_3f.push(dojo.animateProperty({node:_37,duration:_40,properties:p0}));}if(!_43||_43=="last"){_3f.push(dojo.animateProperty({node:_37,duration:_40,properties:p1,onEnd:_4b}));}dojo.connect(_3f[0],"play",function(){_37.style.visibility="visible";s.visibility="hidden";});return dojo.fx.chain(_3f);};dojox.fx.flipCube=function(_4c){var _4d=[],mb=dojo.marginBox(_4c.node),_4e=mb.w/2,_4f=mb.h/2,_50={top:{pName:"height",args:[{whichAnim:"first",dir:"top",shift:-_4f},{whichAnim:"last",dir:"bottom",shift:_4f}]},right:{pName:"width",args:[{whichAnim:"first",dir:"right",shift:_4e},{whichAnim:"last",dir:"left",shift:-_4e}]},bottom:{pName:"height",args:[{whichAnim:"first",dir:"bottom",shift:_4f},{whichAnim:"last",dir:"top",shift:-_4f}]},left:{pName:"width",args:[{whichAnim:"first",dir:"left",shift:-_4e},{whichAnim:"last",dir:"right",shift:_4e}]}};var d=_50[_4c.dir||"left"],p=d.args;_4c.duration=_4c.duration?_4c.duration*2:500;_4c.depth=0.8;_4c.axis="cube";for(var i=p.length-1;i>=0;i--){dojo.mixin(_4c,p[i]);_4d.push(dojox.fx.flip(_4c));}return dojo.fx.combine(_4d);};dojox.fx.flipPage=function(_51){var n=_51.node,_52=dojo.coords(n,true),x=_52.x,y=_52.y,w=_52.w,h=_52.h,_53=dojo.style(n,"backgroundColor"),_54=_51.lightColor||"#dddddd",_55=_51.darkColor,_56=dojo.create("div"),_57=[],hn=[],dir=_51.dir||"right",pn={left:["left","right","x","w"],top:["top","bottom","y","h"],right:["left","left","x","w"],bottom:["top","top","y","h"]},_58={right:[1,-1],left:[-1,1],top:[-1,1],bottom:[1,-1]};dojo.style(_56,{position:"absolute",width:w+"px",height:h+"px",top:y+"px",left:x+"px",visibility:"hidden"});var hs=[];for(var i=0;i<2;i++){var r=i%2,d=r?pn[dir][1]:dir,wa=r?"last":"first",_59=r?_53:_54,_5a=r?_59:_51.startColor||n.style.backgroundColor;hn[i]=dojo.clone(_56);var _5b=function(x){return function(){dojo.destroy(hn[x]);};}(i);dojo.body().appendChild(hn[i]);hs[i]={backgroundColor:r?_5a:_53};hs[i][pn[dir][0]]=_52[pn[dir][2]]+_58[dir][0]*i*_52[pn[dir][3]]+"px";dojo.style(hn[i],hs[i]);_57.push(dojox.fx.flip({node:hn[i],dir:d,axis:"shortside",depth:_51.depth,duration:_51.duration/2,shift:_58[dir][i]*_52[pn[dir][3]]/2,darkColor:_55,lightColor:_54,whichAnim:wa,endColor:_59}));dojo.connect(_57[i],"onEnd",_5b);}return dojo.fx.chain(_57);};dojox.fx.flipGrid=function(_5c){var _5d=_5c.rows||4,_5e=_5c.cols||4,_5f=[],_60=dojo.create("div"),n=_5c.node,_61=dojo.coords(n,true),x=_61.x,y=_61.y,nw=_61.w,nh=_61.h,w=_61.w/_5e,h=_61.h/_5d,_62=[];dojo.style(_60,{position:"absolute",width:w+"px",height:h+"px",backgroundColor:dojo.style(n,"backgroundColor")});for(var i=0;i<_5d;i++){var r=i%2,d=r?"right":"left",_63=r?1:-1;var cn=dojo.clone(n);dojo.style(cn,{position:"absolute",width:nw+"px",height:nh+"px",top:y+"px",left:x+"px",clip:"rect("+i*h+"px,"+nw+"px,"+nh+"px,0)"});dojo.body().appendChild(cn);_5f[i]=[];for(var j=0;j<_5e;j++){var hn=dojo.clone(_60),l=r?j:_5e-(j+1);var _64=function(xn,_65,_66){return function(){if(!(_65%2)){dojo.style(xn,{clip:"rect("+_65*h+"px,"+(nw-(_66+1)*w)+"px,"+((_65+1)*h)+"px,0px)"});}else{dojo.style(xn,{clip:"rect("+_65*h+"px,"+nw+"px,"+((_65+1)*h)+"px,"+((_66+1)*w)+"px)"});}};}(cn,i,j);dojo.body().appendChild(hn);dojo.style(hn,{left:x+l*w+"px",top:y+i*h+"px",visibility:"hidden"});var a=dojox.fx.flipPage({node:hn,dir:d,duration:_5c.duration||900,shift:_63*w/2,depth:0.2,darkColor:_5c.darkColor,lightColor:_5c.lightColor,startColor:_5c.startColor||_5c.node.style.backgroundColor}),_67=function(xn){return function(){dojo.destroy(xn);};}(hn);dojo.connect(a,"play",this,_64);dojo.connect(a,"play",this,_67);_5f[i].push(a);}_62.push(dojo.fx.chain(_5f[i]));}dojo.connect(_62[0],"play",function(){dojo.style(n,{visibility:"hidden"});});return dojo.fx.combine(_62);};}if(!dojo._hasResource["dojox.mobile.compat"]){dojo._hasResource["dojox.mobile.compat"]=true;dojo.provide("dojox.mobile.compat");if(!dojo.isWebKit){dojo.extend(dojox.mobile.View,{_doTransition:function(_68,_69,_6a,dir){var _6b;this.wakeUp(_69);if(!_6a||_6a=="none"){_69.style.display="";_68.style.display="none";_69.style.left="0px";this.invokeCallback();}else{if(_6a=="slide"){var w=_68.offsetWidth;var s1=dojo.fx.slideTo({node:_68,duration:400,left:-w*dir,top:_68.offsetTop});var s2=dojo.fx.slideTo({node:_69,duration:400,left:0});_69.style.position="absolute";_69.style.left=w*dir+"px";_69.style.display="";_6b=dojo.fx.combine([s1,s2]);dojo.connect(_6b,"onEnd",this,function(){_68.style.display="none";_69.style.position="relative";this.invokeCallback();});_6b.play();}else{if(_6a=="flip"){_6b=dojox.fx.flip({node:_68,dir:"right",depth:0.5,duration:400});_69.style.position="absolute";_69.style.left="0px";dojo.connect(_6b,"onEnd",this,function(){_68.style.display="none";_69.style.position="relative";_69.style.display="";this.invokeCallback();});_6b.play();}else{if(_6a=="fade"){_6b=dojo.fx.chain([dojo.fadeOut({node:_68,duration:600}),dojo.fadeIn({node:_69,duration:600})]);_69.style.position="absolute";_69.style.left="0px";_69.style.display="";dojo.style(_69,"opacity",0);dojo.connect(_6b,"onEnd",this,function(){_68.style.display="none";_69.style.position="relative";dojo.style(_68,"opacity",1);this.invokeCallback();});_6b.play();}}}}},wakeUp:function(_6c){if(dojo.isIE&&!_6c._wokeup){_6c._wokeup=true;var _6d=_6c.style.display;_6c.style.display="";var _6e=_6c.getElementsByTagName("*");for(var i=0,len=_6e.length;i<len;i++){var val=_6e[i].style.display;_6e[i].style.display="none";_6e[i].style.display="";_6e[i].style.display=val;}_6c.style.display=_6d;}}});dojo.extend(dojox.mobile.Switch,{buildRendering:function(){this.domNode=this.srcNodeRef||dojo.doc.createElement("DIV");this.domNode.className="mblSwitch";this.domNode.innerHTML="<div class=\"mblSwitchInner\">"+"<div class=\"mblSwitchBg mblSwitchBgLeft\">"+"<div class=\"mblSwitchCorner mblSwitchCorner1T\"></div>"+"<div class=\"mblSwitchCorner mblSwitchCorner2T\"></div>"+"<div class=\"mblSwitchCorner mblSwitchCorner3T\"></div>"+"<div class=\"mblSwitchText mblSwitchTextLeft\">"+this.leftLabel+"</div>"+"<div class=\"mblSwitchCorner mblSwitchCorner1B\"></div>"+"<div class=\"mblSwitchCorner mblSwitchCorner2B\"></div>"+"<div class=\"mblSwitchCorner mblSwitchCorner3B\"></div>"+"</div>"+"<div class=\"mblSwitchBg mblSwitchBgRight\">"+"<div class=\"mblSwitchCorner mblSwitchCorner1T\"></div>"+"<div class=\"mblSwitchCorner mblSwitchCorner2T\"></div>"+"<div class=\"mblSwitchCorner mblSwitchCorner3T\"></div>"+"<div class=\"mblSwitchText mblSwitchTextRight\">"+this.rightLabel+"</div>"+"<div class=\"mblSwitchCorner mblSwitchCorner1B\"></div>"+"<div class=\"mblSwitchCorner mblSwitchCorner2B\"></div>"+"<div class=\"mblSwitchCorner mblSwitchCorner3B\"></div>"+"</div>"+"<div class=\"mblSwitchKnobContainer\">"+"<div class=\"mblSwitchCorner mblSwitchCorner1T\"></div>"+"<div class=\"mblSwitchCorner mblSwitchCorner2T\"></div>"+"<div class=\"mblSwitchCorner mblSwitchCorner3T\"></div>"+"<div class=\"mblSwitchKnob\"></div>"+"<div class=\"mblSwitchCorner mblSwitchCorner1B\"></div>"+"<div class=\"mblSwitchCorner mblSwitchCorner2B\"></div>"+"<div class=\"mblSwitchCorner mblSwitchCorner3B\"></div>"+"</div>"+"</div>";var n=this.inner=this.domNode.firstChild;this.left=n.childNodes[0];this.right=n.childNodes[1];this.knob=n.childNodes[2];dojo.addClass(this.domNode,(this.value=="on")?"mblSwitchOn":"mblSwitchOff");this[this.value=="off"?"left":"right"].style.display="none";},_changeState:function(_6f){if(!this.inner.parentNode||!this.inner.parentNode.tagName){dojo.addClass(this.domNode,(_6f=="on")?"mblSwitchOn":"mblSwitchOff");return;}var pos;if(this.inner.offsetLeft==0){if(_6f=="on"){return;}pos=-53;}else{if(_6f=="off"){return;}pos=0;}var a=dojo.fx.slideTo({node:this.inner,duration:500,left:pos});var _70=this;dojo.connect(a,"onEnd",function(){_70[_6f=="off"?"left":"right"].style.display="none";});a.play();}});if(dojo.isIE||dojo.isBB){dojo.extend(dojox.mobile.RoundRect,{buildRendering:function(){dojox.mobile.createRoundRect(this);this.domNode.className="mblRoundRect";}});dojox.mobile.RoundRectList._addChild=dojox.mobile.RoundRectList.prototype.addChild;dojo.extend(dojox.mobile.RoundRectList,{buildRendering:function(){dojox.mobile.createRoundRect(this,true);this.domNode.className="mblRoundRectList";},postCreate:function(){this.redrawBorders();},addChild:function(_71){dojox.mobile.RoundRectList._addChild.apply(this,arguments);this.redrawBorders();if(dojox.mobile.applyPngFilter){dojox.mobile.applyPngFilter(_71.domNode);}},redrawBorders:function(){var _72=false;for(var i=this.containerNode.childNodes.length-1;i>=0;i--){var c=this.containerNode.childNodes[i];if(c.tagName=="LI"){c.style.borderBottomStyle=_72?"solid":"none";_72=true;}}}});dojo.extend(dojox.mobile.EdgeToEdgeList,{buildRendering:function(){this.domNode=this.containerNode=this.srcNodeRef||dojo.doc.createElement("UL");this.domNode.className="mblEdgeToEdgeList";}});if(dojox.mobile.IconContainer){dojox.mobile.IconContainer._addChild=dojox.mobile.IconContainer.prototype.addChild;dojo.extend(dojox.mobile.IconContainer,{addChild:function(_73){dojox.mobile.IconContainer._addChild.apply(this,arguments);if(dojox.mobile.applyPngFilter){dojox.mobile.applyPngFilter(_73.domNode);}}});}dojo.mixin(dojox.mobile,{createRoundRect:function(_74,_75){var i;_74.domNode=dojo.doc.createElement("DIV");_74.domNode.style.padding="0px";_74.domNode.style.backgroundColor="transparent";_74.domNode.style.borderStyle="none";_74.containerNode=dojo.doc.createElement(_75?"UL":"DIV");_74.containerNode.className="mblRoundRectContainer";if(_74.srcNodeRef){_74.srcNodeRef.parentNode.replaceChild(_74.domNode,_74.srcNodeRef);for(i=0,len=_74.srcNodeRef.childNodes.length;i<len;i++){_74.containerNode.appendChild(_74.srcNodeRef.removeChild(_74.srcNodeRef.firstChild));}_74.srcNodeRef=null;}_74.domNode.appendChild(_74.containerNode);for(i=0;i<=5;i++){var top=dojo.create("DIV");top.className="mblRoundCorner mblRoundCorner"+i+"T";_74.domNode.insertBefore(top,_74.containerNode);var _76=dojo.create("DIV");_76.className="mblRoundCorner mblRoundCorner"+i+"B";_74.domNode.appendChild(_76);}}});if(dojox.mobile.ScrollableView){dojo.extend(dojox.mobile.ScrollableView,{postCreate:function(){var _77=dojo.create("DIV",{className:"mblDummyForIE",innerHTML:"&nbsp;"},this.containerNode,"first");dojo.style(_77,{position:"relative",marginBottom:"-2px",fontSize:"1px"});}});}}if(dojo.isIE<=6){dojox.mobile.applyPngFilter=function(_78){_78=_78||dojo.body();var _79=_78.getElementsByTagName("IMG");var _7a=dojo.moduleUrl("dojo","resources/blank.gif");for(var i=0,len=_79.length;i<len;i++){var img=_79[i];var w=img.offsetWidth;var h=img.offsetHeight;if(w===0||h===0){if(dojo.style(img,"display")!="none"){continue;}img.style.display="";w=img.offsetWidth;h=img.offsetHeight;img.style.display="none";if(w===0||h===0){continue;}}var src=img.src;if(src.indexOf("resources/blank.gif")!=-1){continue;}img.src=_7a;img.runtimeStyle.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+src+"')";img.style.width=w+"px";img.style.height=h+"px";}};}dojox.mobile.loadCss=function(_7b){if(!dojo.global._loadedCss){var obj={};dojo.forEach(dojox.mobile.getCssPaths(),function(_7c){obj[_7c]=true;});dojo.global._loadedCss=obj;}if(!dojo.isArray(_7b)){_7b=[_7b];}for(var i=0;i<_7b.length;i++){var _7d=_7b[i];if(!dojo.global._loadedCss[_7d]){dojo.global._loadedCss[_7d]=true;if(dojo.doc.createStyleSheet){setTimeout(function(_7e){return function(){dojo.doc.createStyleSheet(_7e);};}(_7d),0);}else{var _7f=dojo.doc.createElement("link");_7f.href=_7d;_7f.type="text/css";_7f.rel="stylesheet";var _80=dojo.doc.getElementsByTagName("head")[0];_80.appendChild(_7f);}}}};dojox.mobile.getCssPaths=function(){var _81=[];var i,j;var s=dojo.doc.styleSheets;for(i=0;i<s.length;i++){var r=s[i].cssRules||s[i].imports;if(!r){continue;}for(j=0;j<r.length;j++){if(r[j].href){_81.push(r[j].href);}}}var _82=dojo.doc.getElementsByTagName("link");for(i=0,len=_82.length;i<len;i++){if(_82[i].href){_81.push(_82[i].href);}}return _81;};dojox.mobile.loadCompatPattern=/\/themes\/(domButtons|buttons|iphone|android).*\.css$/;dojox.mobile.loadCompatCssFiles=function(){var _83=dojox.mobile.getCssPaths();for(var i=0;i<_83.length;i++){var _84=_83[i];if(_84.match(dojox.mobile.loadCompatPattern)&&_84.indexOf("-compat.css")==-1){var _85=_84.substring(0,_84.length-4)+"-compat.css";dojox.mobile.loadCss(_85);}}};dojox.mobile.hideAddressBar=function(){};dojo.addOnLoad(function(){if(dojo.config["mblLoadCompatCssFiles"]!==false){dojox.mobile.loadCompatCssFiles();}if(dojox.mobile.applyPngFilter){dojox.mobile.applyPngFilter();}});}}if(!dojo._hasResource["dojox.mobile.app.compat"]){dojo._hasResource["dojox.mobile.app.compat"]=true;dojo.provide("dojox.mobile.app.compat");dojo.extend(dojox.mobile.app.AlertDialog,{_doTransition:function(dir){var h=dojo.marginBox(this.domNode.firstChild).h;var _86=this.controller.getWindowSize().h;var _87=_86-h;var low=_86;var _88=dojo.fx.slideTo({node:this.domNode,duration:400,top:{start:dir<0?_87:low,end:dir<0?low:_87}});var _89=dojo[dir<0?"fadeOut":"fadeIn"]({node:this.mask,duration:400});var _8a=dojo.fx.combine([_88,_89]);var _8b=this;dojo.connect(_8a,"onEnd",this,function(){if(dir<0){_8b.domNode.style.display="none";dojo.destroy(_8b.domNode);dojo.destroy(_8b.mask);}});_8a.play();}});dojo.extend(dojox.mobile.app.List,{deleteRow:function(){var row=this._selectedRow;dojo.style(row,{visibility:"hidden",minHeight:"0px"});dojo.removeClass(row,"hold");var _8c=dojo.contentBox(row).h;dojo.animateProperty({node:row,duration:800,properties:{height:{start:_8c,end:1},paddingTop:{end:0},paddingBottom:{end:0}},onEnd:this._postDeleteAnim}).play();}});if(dojox.mobile.app.ImageView&&!dojo.create("canvas").getContext){dojo.extend(dojox.mobile.app.ImageView,{buildRendering:function(){this.domNode.innerHTML="ImageView widget is not supported on this browser."+"Please try again with a modern browser, e.g. "+"Safari, Chrome or Firefox";this.canvas={};},postCreate:function(){}});}if(dojox.mobile.app.ImageThumbView){dojo.extend(dojox.mobile.app.ImageThumbView,{place:function(_8d,x,y){dojo.style(_8d,{top:y+"px",left:x+"px",visibility:"visible"});}});}}
diff --git a/js/dojo-1.6/dojox/mobile/app/compat.js.uncompressed.js b/js/dojo-1.6/dojox/mobile/app/compat.js.uncompressed.js
new file mode 100644
index 0000000..ce3f28a
--- /dev/null
+++ b/js/dojo-1.6/dojox/mobile/app/compat.js.uncompressed.js
@@ -0,0 +1,1700 @@
+/*
+ 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
+*/
+
+if(!dojo._hasResource["dojo.uacss"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.uacss"] = true;
+dojo.provide("dojo.uacss");
+
+
+
+(function(){
+ // summary:
+ // Applies pre-set CSS classes to the top-level HTML node, based on:
+ // - browser (ex: dj_ie)
+ // - browser version (ex: dj_ie6)
+ // - box model (ex: dj_contentBox)
+ // - text direction (ex: dijitRtl)
+ //
+ // In addition, browser, browser version, and box model are
+ // combined with an RTL flag when browser text is RTL. ex: dj_ie-rtl.
+
+ var d = dojo,
+ html = d.doc.documentElement,
+ ie = d.isIE,
+ opera = d.isOpera,
+ maj = Math.floor,
+ ff = d.isFF,
+ boxModel = d.boxModel.replace(/-/,''),
+
+ classes = {
+ dj_ie: ie,
+ dj_ie6: maj(ie) == 6,
+ dj_ie7: maj(ie) == 7,
+ dj_ie8: maj(ie) == 8,
+ dj_ie9: maj(ie) == 9,
+ dj_quirks: d.isQuirks,
+ dj_iequirks: ie && d.isQuirks,
+
+ // NOTE: Opera not supported by dijit
+ dj_opera: opera,
+
+ dj_khtml: d.isKhtml,
+
+ dj_webkit: d.isWebKit,
+ dj_safari: d.isSafari,
+ dj_chrome: d.isChrome,
+
+ dj_gecko: d.isMozilla,
+ dj_ff3: maj(ff) == 3
+ }; // no dojo unsupported browsers
+
+ classes["dj_" + boxModel] = true;
+
+ // apply browser, browser version, and box model class names
+ var classStr = "";
+ for(var clz in classes){
+ if(classes[clz]){
+ classStr += clz + " ";
+ }
+ }
+ html.className = d.trim(html.className + " " + classStr);
+
+ // If RTL mode, then add dj_rtl flag plus repeat existing classes with -rtl extension.
+ // We can't run the code below until the <body> tag has loaded (so we can check for dir=rtl).
+ // Unshift() is to run sniff code before the parser.
+ dojo._loaders.unshift(function(){
+ if(!dojo._isBodyLtr()){
+ var rtlClassStr = "dj_rtl dijitRtl " + classStr.replace(/ /g, "-rtl ")
+ html.className = d.trim(html.className + " " + rtlClassStr);
+ }
+ });
+})();
+
+}
+
+if(!dojo._hasResource["dijit._base.sniff"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._base.sniff"] = true;
+dojo.provide("dijit._base.sniff");
+
+
+
+
+// summary:
+// Applies pre-set CSS classes to the top-level HTML node, see
+// `dojo.uacss` for details.
+//
+// Simply doing a require on this module will
+// establish this CSS. Modified version of Morris' CSS hack.
+
+}
+
+if(!dojo._hasResource["dojo.fx.Toggler"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.fx.Toggler"] = true;
+dojo.provide("dojo.fx.Toggler");
+
+
+
+dojo.declare("dojo.fx.Toggler", null, {
+ // summary:
+ // A simple `dojo.Animation` toggler API.
+ //
+ // description:
+ // class constructor for an animation toggler. It accepts a packed
+ // set of arguments about what type of animation to use in each
+ // direction, duration, etc. All available members are mixed into
+ // these animations from the constructor (for example, `node`,
+ // `showDuration`, `hideDuration`).
+ //
+ // example:
+ // | var t = new dojo.fx.Toggler({
+ // | node: "nodeId",
+ // | showDuration: 500,
+ // | // hideDuration will default to "200"
+ // | showFunc: dojo.fx.wipeIn,
+ // | // hideFunc will default to "fadeOut"
+ // | });
+ // | t.show(100); // delay showing for 100ms
+ // | // ...time passes...
+ // | t.hide();
+
+ // node: DomNode
+ // the node to target for the showing and hiding animations
+ node: null,
+
+ // showFunc: Function
+ // The function that returns the `dojo.Animation` to show the node
+ showFunc: dojo.fadeIn,
+
+ // hideFunc: Function
+ // The function that returns the `dojo.Animation` to hide the node
+ hideFunc: dojo.fadeOut,
+
+ // showDuration:
+ // Time in milliseconds to run the show Animation
+ showDuration: 200,
+
+ // hideDuration:
+ // Time in milliseconds to run the hide Animation
+ hideDuration: 200,
+
+ // FIXME: need a policy for where the toggler should "be" the next
+ // time show/hide are called if we're stopped somewhere in the
+ // middle.
+ // FIXME: also would be nice to specify individual showArgs/hideArgs mixed into
+ // each animation individually.
+ // FIXME: also would be nice to have events from the animations exposed/bridged
+
+ /*=====
+ _showArgs: null,
+ _showAnim: null,
+
+ _hideArgs: null,
+ _hideAnim: null,
+
+ _isShowing: false,
+ _isHiding: false,
+ =====*/
+
+ constructor: function(args){
+ var _t = this;
+
+ dojo.mixin(_t, args);
+ _t.node = args.node;
+ _t._showArgs = dojo.mixin({}, args);
+ _t._showArgs.node = _t.node;
+ _t._showArgs.duration = _t.showDuration;
+ _t.showAnim = _t.showFunc(_t._showArgs);
+
+ _t._hideArgs = dojo.mixin({}, args);
+ _t._hideArgs.node = _t.node;
+ _t._hideArgs.duration = _t.hideDuration;
+ _t.hideAnim = _t.hideFunc(_t._hideArgs);
+
+ dojo.connect(_t.showAnim, "beforeBegin", dojo.hitch(_t.hideAnim, "stop", true));
+ dojo.connect(_t.hideAnim, "beforeBegin", dojo.hitch(_t.showAnim, "stop", true));
+ },
+
+ show: function(delay){
+ // summary: Toggle the node to showing
+ // delay: Integer?
+ // Ammount of time to stall playing the show animation
+ return this.showAnim.play(delay || 0);
+ },
+
+ hide: function(delay){
+ // summary: Toggle the node to hidden
+ // delay: Integer?
+ // Ammount of time to stall playing the hide animation
+ return this.hideAnim.play(delay || 0);
+ }
+});
+
+}
+
+if(!dojo._hasResource["dojo.fx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.fx"] = true;
+dojo.provide("dojo.fx");
+
+
+
+
+/*=====
+dojo.fx = {
+ // summary: Effects library on top of Base animations
+};
+=====*/
+(function(){
+
+ var d = dojo,
+ _baseObj = {
+ _fire: function(evt, args){
+ if(this[evt]){
+ this[evt].apply(this, args||[]);
+ }
+ return this;
+ }
+ };
+
+ var _chain = function(animations){
+ this._index = -1;
+ this._animations = animations||[];
+ this._current = this._onAnimateCtx = this._onEndCtx = null;
+
+ this.duration = 0;
+ d.forEach(this._animations, function(a){
+ this.duration += a.duration;
+ if(a.delay){ this.duration += a.delay; }
+ }, this);
+ };
+ d.extend(_chain, {
+ _onAnimate: function(){
+ this._fire("onAnimate", arguments);
+ },
+ _onEnd: function(){
+ d.disconnect(this._onAnimateCtx);
+ d.disconnect(this._onEndCtx);
+ this._onAnimateCtx = this._onEndCtx = null;
+ if(this._index + 1 == this._animations.length){
+ this._fire("onEnd");
+ }else{
+ // switch animations
+ this._current = this._animations[++this._index];
+ this._onAnimateCtx = d.connect(this._current, "onAnimate", this, "_onAnimate");
+ this._onEndCtx = d.connect(this._current, "onEnd", this, "_onEnd");
+ this._current.play(0, true);
+ }
+ },
+ play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){
+ if(!this._current){ this._current = this._animations[this._index = 0]; }
+ if(!gotoStart && this._current.status() == "playing"){ return this; }
+ var beforeBegin = d.connect(this._current, "beforeBegin", this, function(){
+ this._fire("beforeBegin");
+ }),
+ onBegin = d.connect(this._current, "onBegin", this, function(arg){
+ this._fire("onBegin", arguments);
+ }),
+ onPlay = d.connect(this._current, "onPlay", this, function(arg){
+ this._fire("onPlay", arguments);
+ d.disconnect(beforeBegin);
+ d.disconnect(onBegin);
+ d.disconnect(onPlay);
+ });
+ if(this._onAnimateCtx){
+ d.disconnect(this._onAnimateCtx);
+ }
+ this._onAnimateCtx = d.connect(this._current, "onAnimate", this, "_onAnimate");
+ if(this._onEndCtx){
+ d.disconnect(this._onEndCtx);
+ }
+ this._onEndCtx = d.connect(this._current, "onEnd", this, "_onEnd");
+ this._current.play.apply(this._current, arguments);
+ return this;
+ },
+ pause: function(){
+ if(this._current){
+ var e = d.connect(this._current, "onPause", this, function(arg){
+ this._fire("onPause", arguments);
+ d.disconnect(e);
+ });
+ this._current.pause();
+ }
+ return this;
+ },
+ gotoPercent: function(/*Decimal*/percent, /*Boolean?*/ andPlay){
+ this.pause();
+ var offset = this.duration * percent;
+ this._current = null;
+ d.some(this._animations, function(a){
+ if(a.duration <= offset){
+ this._current = a;
+ return true;
+ }
+ offset -= a.duration;
+ return false;
+ });
+ if(this._current){
+ this._current.gotoPercent(offset / this._current.duration, andPlay);
+ }
+ return this;
+ },
+ stop: function(/*boolean?*/ gotoEnd){
+ if(this._current){
+ if(gotoEnd){
+ for(; this._index + 1 < this._animations.length; ++this._index){
+ this._animations[this._index].stop(true);
+ }
+ this._current = this._animations[this._index];
+ }
+ var e = d.connect(this._current, "onStop", this, function(arg){
+ this._fire("onStop", arguments);
+ d.disconnect(e);
+ });
+ this._current.stop();
+ }
+ return this;
+ },
+ status: function(){
+ return this._current ? this._current.status() : "stopped";
+ },
+ destroy: function(){
+ if(this._onAnimateCtx){ d.disconnect(this._onAnimateCtx); }
+ if(this._onEndCtx){ d.disconnect(this._onEndCtx); }
+ }
+ });
+ d.extend(_chain, _baseObj);
+
+ dojo.fx.chain = function(/*dojo.Animation[]*/ animations){
+ // summary:
+ // Chain a list of `dojo.Animation`s to run in sequence
+ //
+ // description:
+ // Return a `dojo.Animation` which will play all passed
+ // `dojo.Animation` instances in sequence, firing its own
+ // synthesized events simulating a single animation. (eg:
+ // onEnd of this animation means the end of the chain,
+ // not the individual animations within)
+ //
+ // example:
+ // Once `node` is faded out, fade in `otherNode`
+ // | dojo.fx.chain([
+ // | dojo.fadeIn({ node:node }),
+ // | dojo.fadeOut({ node:otherNode })
+ // | ]).play();
+ //
+ return new _chain(animations) // dojo.Animation
+ };
+
+ var _combine = function(animations){
+ this._animations = animations||[];
+ this._connects = [];
+ this._finished = 0;
+
+ this.duration = 0;
+ d.forEach(animations, function(a){
+ var duration = a.duration;
+ if(a.delay){ duration += a.delay; }
+ if(this.duration < duration){ this.duration = duration; }
+ this._connects.push(d.connect(a, "onEnd", this, "_onEnd"));
+ }, this);
+
+ this._pseudoAnimation = new d.Animation({curve: [0, 1], duration: this.duration});
+ var self = this;
+ d.forEach(["beforeBegin", "onBegin", "onPlay", "onAnimate", "onPause", "onStop", "onEnd"],
+ function(evt){
+ self._connects.push(d.connect(self._pseudoAnimation, evt,
+ function(){ self._fire(evt, arguments); }
+ ));
+ }
+ );
+ };
+ d.extend(_combine, {
+ _doAction: function(action, args){
+ d.forEach(this._animations, function(a){
+ a[action].apply(a, args);
+ });
+ return this;
+ },
+ _onEnd: function(){
+ if(++this._finished > this._animations.length){
+ this._fire("onEnd");
+ }
+ },
+ _call: function(action, args){
+ var t = this._pseudoAnimation;
+ t[action].apply(t, args);
+ },
+ play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){
+ this._finished = 0;
+ this._doAction("play", arguments);
+ this._call("play", arguments);
+ return this;
+ },
+ pause: function(){
+ this._doAction("pause", arguments);
+ this._call("pause", arguments);
+ return this;
+ },
+ gotoPercent: function(/*Decimal*/percent, /*Boolean?*/ andPlay){
+ var ms = this.duration * percent;
+ d.forEach(this._animations, function(a){
+ a.gotoPercent(a.duration < ms ? 1 : (ms / a.duration), andPlay);
+ });
+ this._call("gotoPercent", arguments);
+ return this;
+ },
+ stop: function(/*boolean?*/ gotoEnd){
+ this._doAction("stop", arguments);
+ this._call("stop", arguments);
+ return this;
+ },
+ status: function(){
+ return this._pseudoAnimation.status();
+ },
+ destroy: function(){
+ d.forEach(this._connects, dojo.disconnect);
+ }
+ });
+ d.extend(_combine, _baseObj);
+
+ dojo.fx.combine = function(/*dojo.Animation[]*/ animations){
+ // summary:
+ // Combine a list of `dojo.Animation`s to run in parallel
+ //
+ // description:
+ // Combine an array of `dojo.Animation`s to run in parallel,
+ // providing a new `dojo.Animation` instance encompasing each
+ // animation, firing standard animation events.
+ //
+ // example:
+ // Fade out `node` while fading in `otherNode` simultaneously
+ // | dojo.fx.combine([
+ // | dojo.fadeIn({ node:node }),
+ // | dojo.fadeOut({ node:otherNode })
+ // | ]).play();
+ //
+ // example:
+ // When the longest animation ends, execute a function:
+ // | var anim = dojo.fx.combine([
+ // | dojo.fadeIn({ node: n, duration:700 }),
+ // | dojo.fadeOut({ node: otherNode, duration: 300 })
+ // | ]);
+ // | dojo.connect(anim, "onEnd", function(){
+ // | // overall animation is done.
+ // | });
+ // | anim.play(); // play the animation
+ //
+ return new _combine(animations); // dojo.Animation
+ };
+
+ dojo.fx.wipeIn = function(/*Object*/ args){
+ // summary:
+ // Expand a node to it's natural height.
+ //
+ // description:
+ // Returns an animation that will expand the
+ // node defined in 'args' object from it's current height to
+ // it's natural height (with no scrollbar).
+ // Node must have no margin/border/padding.
+ //
+ // args: Object
+ // A hash-map of standard `dojo.Animation` constructor properties
+ // (such as easing: node: duration: and so on)
+ //
+ // example:
+ // | dojo.fx.wipeIn({
+ // | node:"someId"
+ // | }).play()
+ var node = args.node = d.byId(args.node), s = node.style, o;
+
+ var anim = d.animateProperty(d.mixin({
+ properties: {
+ height: {
+ // wrapped in functions so we wait till the last second to query (in case value has changed)
+ start: function(){
+ // start at current [computed] height, but use 1px rather than 0
+ // because 0 causes IE to display the whole panel
+ o = s.overflow;
+ s.overflow = "hidden";
+ if(s.visibility == "hidden" || s.display == "none"){
+ s.height = "1px";
+ s.display = "";
+ s.visibility = "";
+ return 1;
+ }else{
+ var height = d.style(node, "height");
+ return Math.max(height, 1);
+ }
+ },
+ end: function(){
+ return node.scrollHeight;
+ }
+ }
+ }
+ }, args));
+
+ d.connect(anim, "onEnd", function(){
+ s.height = "auto";
+ s.overflow = o;
+ });
+
+ return anim; // dojo.Animation
+ };
+
+ dojo.fx.wipeOut = function(/*Object*/ args){
+ // summary:
+ // Shrink a node to nothing and hide it.
+ //
+ // description:
+ // Returns an animation that will shrink node defined in "args"
+ // from it's current height to 1px, and then hide it.
+ //
+ // args: Object
+ // A hash-map of standard `dojo.Animation` constructor properties
+ // (such as easing: node: duration: and so on)
+ //
+ // example:
+ // | dojo.fx.wipeOut({ node:"someId" }).play()
+
+ var node = args.node = d.byId(args.node), s = node.style, o;
+
+ var anim = d.animateProperty(d.mixin({
+ properties: {
+ height: {
+ end: 1 // 0 causes IE to display the whole panel
+ }
+ }
+ }, args));
+
+ d.connect(anim, "beforeBegin", function(){
+ o = s.overflow;
+ s.overflow = "hidden";
+ s.display = "";
+ });
+ d.connect(anim, "onEnd", function(){
+ s.overflow = o;
+ s.height = "auto";
+ s.display = "none";
+ });
+
+ return anim; // dojo.Animation
+ };
+
+ dojo.fx.slideTo = function(/*Object*/ args){
+ // summary:
+ // Slide a node to a new top/left position
+ //
+ // description:
+ // Returns an animation that will slide "node"
+ // defined in args Object from its current position to
+ // the position defined by (args.left, args.top).
+ //
+ // args: Object
+ // A hash-map of standard `dojo.Animation` constructor properties
+ // (such as easing: node: duration: and so on). Special args members
+ // are `top` and `left`, which indicate the new position to slide to.
+ //
+ // example:
+ // | dojo.fx.slideTo({ node: node, left:"40", top:"50", units:"px" }).play()
+
+ var node = args.node = d.byId(args.node),
+ top = null, left = null;
+
+ var init = (function(n){
+ return function(){
+ var cs = d.getComputedStyle(n);
+ var pos = cs.position;
+ top = (pos == 'absolute' ? n.offsetTop : parseInt(cs.top) || 0);
+ left = (pos == 'absolute' ? n.offsetLeft : parseInt(cs.left) || 0);
+ if(pos != 'absolute' && pos != 'relative'){
+ var ret = d.position(n, true);
+ top = ret.y;
+ left = ret.x;
+ n.style.position="absolute";
+ n.style.top=top+"px";
+ n.style.left=left+"px";
+ }
+ };
+ })(node);
+ init();
+
+ var anim = d.animateProperty(d.mixin({
+ properties: {
+ top: args.top || 0,
+ left: args.left || 0
+ }
+ }, args));
+ d.connect(anim, "beforeBegin", anim, init);
+
+ return anim; // dojo.Animation
+ };
+
+})();
+
+}
+
+if(!dojo._hasResource["dojox.fx.flip"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.fx.flip"] = true;
+dojo.provide("dojox.fx.flip");
+
+
+
+
+ dojo.experimental("dojox.fx.flip");
+ // because ShrinkSafe will eat this up:
+ var borderConst = "border",
+ widthConst = "Width",
+ heightConst = "Height",
+ topConst = "Top",
+ rightConst = "Right",
+ leftConst = "Left",
+ bottomConst = "Bottom"
+ ;
+
+ dojox.fx.flip = function(/*Object*/ args){
+ // summary: Animate a node flipping following a specific direction
+ //
+ // description:
+ // Returns an animation that will flip the
+ // node around a central axis:
+ // if args.dir is "left" or "right" --> y axis
+ // if args.dir is "top" or "bottom" --> x axis
+ //
+ // This effect is obtained using a border distorsion applied to a helper node.
+ //
+ // The user can specify three background colors for the helper node:
+ // darkColor: the darkest color reached during the animation
+ // lightColor: the brightest color
+ // endColor: the final backgroundColor for the node
+ //
+ // depth: Float
+ // 0 <= depth <= 1 overrides the computed "depth"
+ // (0: min distorsion, 1: max distorsion)
+ //
+ // whichAnim: String
+ // "first" : the first half animation
+ // "last" : the second one
+ // "both" (default) : both
+ //
+ // axis: String
+ // "center" (default) : the node is flipped around his center
+ // "shortside" : the node is flipped around his "short" (in perspective) side
+ // "longside" : the node is flipped around his "long" (in perspective) side
+ // "cube" : the node flips around the central axis of the cube
+ //
+ // shift: Integer
+ // node translation, perpendicular to the rotation axis
+ //
+ // example:
+ // | var anim = dojox.fx.flip({
+ // | node: dojo.byId("nodeId"),
+ // | dir: "top",
+ // | darkColor: "#555555",
+ // | lightColor: "#dddddd",
+ // | endColor: "#666666",
+ // | depth: .5,
+ // | shift: 50,
+ // | duration:300
+ // | });
+
+ var helperNode = dojo.create("div"),
+ node = args.node = dojo.byId(args.node),
+ s = node.style,
+ dims = null,
+ hs = null,
+ pn = null,
+ lightColor = args.lightColor || "#dddddd",
+ darkColor = args.darkColor || "#555555",
+ bgColor = dojo.style(node, "backgroundColor"),
+ endColor = args.endColor || bgColor,
+ staticProps = {},
+ anims = [],
+ duration = args.duration ? args.duration / 2 : 250,
+ dir = args.dir || "left",
+ pConst = .9,
+ transparentColor = "transparent",
+ whichAnim = args.whichAnim,
+ axis = args.axis || "center",
+ depth = args.depth
+ ;
+ // IE6 workaround: IE6 doesn't support transparent borders
+ var convertColor = function(color){
+ return ((new dojo.Color(color)).toHex() === "#000000") ? "#000001" : color;
+ };
+
+ if(dojo.isIE < 7){
+ endColor = convertColor(endColor);
+ lightColor = convertColor(lightColor);
+ darkColor = convertColor(darkColor);
+ bgColor = convertColor(bgColor);
+ transparentColor = "black";
+ helperNode.style.filter = "chroma(color='#000000')";
+ }
+
+ var init = (function(n){
+ return function(){
+ var ret = dojo.coords(n, true);
+ dims = {
+ top: ret.y,
+ left: ret.x,
+ width: ret.w,
+ height: ret.h
+ };
+ }
+ })(node);
+ init();
+ // helperNode initialization
+ hs = {
+ position: "absolute",
+ top: dims["top"] + "px",
+ left: dims["left"] + "px",
+ height: "0",
+ width: "0",
+ zIndex: args.zIndex || (s.zIndex || 0),
+ border: "0 solid " + transparentColor,
+ fontSize: "0",
+ visibility: "hidden"
+ };
+ var props = [ {},
+ {
+ top: dims["top"],
+ left: dims["left"]
+ }
+ ];
+ var dynProperties = {
+ left: [leftConst, rightConst, topConst, bottomConst, widthConst, heightConst, "end" + heightConst + "Min", leftConst, "end" + heightConst + "Max"],
+ right: [rightConst, leftConst, topConst, bottomConst, widthConst, heightConst, "end" + heightConst + "Min", leftConst, "end" + heightConst + "Max"],
+ top: [topConst, bottomConst, leftConst, rightConst, heightConst, widthConst, "end" + widthConst + "Min", topConst, "end" + widthConst + "Max"],
+ bottom: [bottomConst, topConst, leftConst, rightConst, heightConst, widthConst, "end" + widthConst + "Min", topConst, "end" + widthConst + "Max"]
+ };
+ // property names
+ pn = dynProperties[dir];
+
+ // .4 <= pConst <= .9
+ if(typeof depth != "undefined"){
+ depth = Math.max(0, Math.min(1, depth)) / 2;
+ pConst = .4 + (.5 - depth);
+ }else{
+ pConst = Math.min(.9, Math.max(.4, dims[pn[5].toLowerCase()] / dims[pn[4].toLowerCase()]));
+ }
+ var p0 = props[0];
+ for(var i = 4; i < 6; i++){
+ if(axis == "center" || axis == "cube"){ // find a better name for "cube"
+ dims["end" + pn[i] + "Min"] = dims[pn[i].toLowerCase()] * pConst;
+ dims["end" + pn[i] + "Max"] = dims[pn[i].toLowerCase()] / pConst;
+ }else if(axis == "shortside"){
+ dims["end" + pn[i] + "Min"] = dims[pn[i].toLowerCase()];
+ dims["end" + pn[i] + "Max"] = dims[pn[i].toLowerCase()] / pConst;
+ }else if(axis == "longside"){
+ dims["end" + pn[i] + "Min"] = dims[pn[i].toLowerCase()] * pConst;
+ dims["end" + pn[i] + "Max"] = dims[pn[i].toLowerCase()];
+ }
+ }
+ if(axis == "center"){
+ p0[pn[2].toLowerCase()] = dims[pn[2].toLowerCase()] - (dims[pn[8]] - dims[pn[6]]) / 4;
+ }else if(axis == "shortside"){
+ p0[pn[2].toLowerCase()] = dims[pn[2].toLowerCase()] - (dims[pn[8]] - dims[pn[6]]) / 2;
+ }
+
+ staticProps[pn[5].toLowerCase()] = dims[pn[5].toLowerCase()] + "px";
+ staticProps[pn[4].toLowerCase()] = "0";
+ staticProps[borderConst + pn[1] + widthConst] = dims[pn[4].toLowerCase()] + "px";
+ staticProps[borderConst + pn[1] + "Color"] = bgColor;
+
+ p0[borderConst + pn[1] + widthConst] = 0;
+ p0[borderConst + pn[1] + "Color"] = darkColor;
+ p0[borderConst + pn[2] + widthConst] = p0[borderConst + pn[3] + widthConst] = axis != "cube"
+ ? (dims["end" + pn[5] + "Max"] - dims["end" + pn[5] + "Min"]) / 2
+ : dims[pn[6]] / 2
+ ;
+ p0[pn[7].toLowerCase()] = dims[pn[7].toLowerCase()] + dims[pn[4].toLowerCase()] / 2 + (args.shift || 0);
+ p0[pn[5].toLowerCase()] = dims[pn[6]];
+
+ var p1 = props[1];
+ p1[borderConst + pn[0] + "Color"] = { start: lightColor, end: endColor };
+ p1[borderConst + pn[0] + widthConst] = dims[pn[4].toLowerCase()];
+ p1[borderConst + pn[2] + widthConst] = 0;
+ p1[borderConst + pn[3] + widthConst] = 0;
+ p1[pn[5].toLowerCase()] = { start: dims[pn[6]], end: dims[pn[5].toLowerCase()] };
+
+ dojo.mixin(hs, staticProps);
+ dojo.style(helperNode, hs);
+ dojo.body().appendChild(helperNode);
+
+ var finalize = function(){
+// helperNode.parentNode.removeChild(helperNode);
+ dojo.destroy(helperNode);
+ // fixes a flicker when the animation ends
+ s.backgroundColor = endColor;
+ s.visibility = "visible";
+ };
+ if(whichAnim == "last"){
+ for(i in p0){
+ p0[i] = { start: p0[i] };
+ }
+ p0[borderConst + pn[1] + "Color"] = { start: darkColor, end: endColor };
+ p1 = p0;
+ }
+ if(!whichAnim || whichAnim == "first"){
+ anims.push(dojo.animateProperty({
+ node: helperNode,
+ duration: duration,
+ properties: p0
+ }));
+ }
+ if(!whichAnim || whichAnim == "last"){
+ anims.push(dojo.animateProperty({
+ node: helperNode,
+ duration: duration,
+ properties: p1,
+ onEnd: finalize
+ }));
+ }
+
+ // hide the original node
+ dojo.connect(anims[0], "play", function(){
+ helperNode.style.visibility = "visible";
+ s.visibility = "hidden";
+ });
+
+ return dojo.fx.chain(anims); // dojo.Animation
+
+ }
+
+ dojox.fx.flipCube = function(/*Object*/ args){
+ // summary: An extension to `dojox.fx.flip` providing a more 3d-like rotation
+ //
+ // description:
+ // An extension to `dojox.fx.flip` providing a more 3d-like rotation.
+ // Behaves the same as `dojox.fx.flip`, using the same attributes and
+ // other standard `dojo.Animation` properties.
+ //
+ // example:
+ // See `dojox.fx.flip`
+ var anims = [],
+ mb = dojo.marginBox(args.node),
+ shiftX = mb.w / 2,
+ shiftY = mb.h / 2,
+ dims = {
+ top: {
+ pName: "height",
+ args:[
+ {
+ whichAnim: "first",
+ dir: "top",
+ shift: -shiftY
+ },
+ {
+ whichAnim: "last",
+ dir: "bottom",
+ shift: shiftY
+ }
+ ]
+ },
+ right: {
+ pName: "width",
+ args:[
+ {
+ whichAnim: "first",
+ dir: "right",
+ shift: shiftX
+ },
+ {
+ whichAnim: "last",
+ dir: "left",
+ shift: -shiftX
+ }
+ ]
+ },
+ bottom: {
+ pName: "height",
+ args:[
+ {
+ whichAnim: "first",
+ dir: "bottom",
+ shift: shiftY
+ },
+ {
+ whichAnim: "last",
+ dir: "top",
+ shift: -shiftY
+ }
+ ]
+ },
+ left: {
+ pName: "width",
+ args:[
+ {
+ whichAnim: "first",
+ dir: "left",
+ shift: -shiftX
+ },
+ {
+ whichAnim: "last",
+ dir: "right",
+ shift: shiftX
+ }
+ ]
+ }
+ }
+ ;
+ var d = dims[args.dir || "left"],
+ p = d.args
+ ;
+ args.duration = args.duration ? args.duration * 2 : 500;
+ args.depth = .8;
+ args.axis = "cube";
+ for(var i = p.length - 1; i >= 0; i--){
+ dojo.mixin(args, p[i]);
+ anims.push(dojox.fx.flip(args));
+ }
+ return dojo.fx.combine(anims);
+ };
+
+ dojox.fx.flipPage = function(/*Object*/ args){
+ // summary: An extension to `dojox.fx.flip` providing a page flip like animation.
+ //
+ // description:
+ // An extension to `dojox.fx.flip` providing a page flip effect.
+ // Behaves the same as `dojox.fx.flip`, using the same attributes and
+ // other standard `dojo.Animation` properties.
+ //
+ // example:
+ // See `dojox.fx.flip`
+ var n = args.node,
+ coords = dojo.coords(n, true),
+ x = coords.x,
+ y = coords.y,
+ w = coords.w,
+ h = coords.h,
+ bgColor = dojo.style(n, "backgroundColor"),
+ lightColor = args.lightColor || "#dddddd",
+ darkColor = args.darkColor,
+ helperNode = dojo.create("div"),
+ anims = [],
+ hn = [],
+ dir = args.dir || "right",
+ pn = {
+ left: ["left", "right", "x", "w"],
+ top: ["top", "bottom", "y", "h"],
+ right: ["left", "left", "x", "w"],
+ bottom: ["top", "top", "y", "h"]
+ },
+ shiftMultiplier = {
+ right: [1, -1],
+ left: [-1, 1],
+ top: [-1, 1],
+ bottom: [1, -1]
+ }
+ ;
+ dojo.style(helperNode, {
+ position: "absolute",
+ width : w + "px",
+ height : h + "px",
+ top : y + "px",
+ left : x + "px",
+ visibility: "hidden"
+ });
+ var hs = [];
+ for(var i = 0; i < 2; i++){
+ var r = i % 2,
+ d = r ? pn[dir][1] : dir,
+ wa = r ? "last" : "first",
+ endColor = r ? bgColor : lightColor,
+ startColor = r ? endColor : args.startColor || n.style.backgroundColor
+ ;
+ hn[i] = dojo.clone(helperNode);
+ var finalize = function(x){
+ return function(){
+ dojo.destroy(hn[x]);
+ }
+ }(i)
+ ;
+ dojo.body().appendChild(hn[i]);
+ hs[i] = {
+ backgroundColor: r ? startColor : bgColor
+ };
+
+ hs[i][pn[dir][0]] = coords[pn[dir][2]] + shiftMultiplier[dir][0] * i * coords[pn[dir][3]] + "px";
+ dojo.style(hn[i], hs[i]);
+ anims.push(dojox.fx.flip({
+ node: hn[i],
+ dir: d,
+ axis: "shortside",
+ depth: args.depth,
+ duration: args.duration / 2,
+ shift: shiftMultiplier[dir][i] * coords[pn[dir][3]] / 2,
+ darkColor: darkColor,
+ lightColor: lightColor,
+ whichAnim: wa,
+ endColor: endColor
+ }));
+ dojo.connect(anims[i], "onEnd", finalize);
+ }
+ return dojo.fx.chain(anims);
+ };
+
+
+ dojox.fx.flipGrid = function(/*Object*/ args){
+ // summary: An extension to `dojox.fx.flip` providing a decomposition in rows * cols flipping elements
+ //
+ // description:
+ // An extension to `dojox.fx.flip` providing a page flip effect.
+ // Behaves the same as `dojox.fx.flip`, using the same attributes and
+ // other standard `dojo.Animation` properties and
+ //
+ // cols: Integer columns
+ // rows: Integer rows
+ //
+ // duration: the single flip duration
+ //
+ // example:
+ // See `dojox.fx.flip`
+ var rows = args.rows || 4,
+ cols = args.cols || 4,
+ anims = [],
+ helperNode = dojo.create("div"),
+ n = args.node,
+ coords = dojo.coords(n, true),
+ x = coords.x,
+ y = coords.y,
+ nw = coords.w,
+ nh = coords.h,
+ w = coords.w / cols,
+ h = coords.h / rows,
+ cAnims = []
+ ;
+ dojo.style(helperNode, {
+ position: "absolute",
+ width: w + "px",
+ height: h + "px",
+ backgroundColor: dojo.style(n, "backgroundColor")
+ });
+ for(var i = 0; i < rows; i++){
+ var r = i % 2,
+ d = r ? "right" : "left",
+ signum = r ? 1 : -1
+ ;
+ // cloning
+ var cn = dojo.clone(n);
+ dojo.style(cn, {
+ position: "absolute",
+ width: nw + "px",
+ height: nh + "px",
+ top: y + "px",
+ left: x + "px",
+ clip: "rect(" + i * h + "px," + nw + "px," + nh + "px,0)"
+ });
+ dojo.body().appendChild(cn);
+ anims[i] = [];
+ for(var j = 0; j < cols; j++){
+ var hn = dojo.clone(helperNode),
+ l = r ? j : cols - (j + 1)
+ ;
+ var adjustClip = function(xn, yCounter, xCounter){
+ return function(){
+ if(!(yCounter % 2)){
+ dojo.style(xn, {
+ clip: "rect(" + yCounter * h + "px," + (nw - (xCounter + 1) * w ) + "px," + ((yCounter + 1) * h) + "px,0px)"
+ });
+ }else{
+ dojo.style(xn, {
+ clip: "rect(" + yCounter * h + "px," + nw + "px," + ((yCounter + 1) * h) + "px," + ((xCounter + 1) * w) + "px)"
+ });
+ }
+ }
+ }(cn, i, j);
+ dojo.body().appendChild(hn);
+ dojo.style(hn, {
+ left: x + l * w + "px",
+ top: y + i * h + "px",
+ visibility: "hidden"
+ });
+ var a = dojox.fx.flipPage({
+ node: hn,
+ dir: d,
+ duration: args.duration || 900,
+ shift: signum * w/2,
+ depth: .2,
+ darkColor: args.darkColor,
+ lightColor: args.lightColor,
+ startColor: args.startColor || args.node.style.backgroundColor
+ }),
+ removeHelper = function(xn){
+ return function(){
+ dojo.destroy(xn);
+ }
+ }(hn)
+ ;
+ dojo.connect(a, "play", this, adjustClip);
+ dojo.connect(a, "play", this, removeHelper);
+ anims[i].push(a);
+ }
+ cAnims.push(dojo.fx.chain(anims[i]));
+
+ }
+ dojo.connect(cAnims[0], "play", function(){
+ dojo.style(n, {visibility: "hidden"});
+ });
+ return dojo.fx.combine(cAnims);
+ };
+
+}
+
+if(!dojo._hasResource["dojox.mobile.compat"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.mobile.compat"] = true;
+dojo.provide("dojox.mobile.compat");
+
+
+
+
+
+// summary:
+// CSS3 compatibility module
+// description:
+// This module provides support for some of the CSS3 features to dojox.mobile
+// for non-CSS3 browsers, such as IE or Firefox.
+// If you load this module, it directly replaces some of the methods of
+// dojox.mobile instead of subclassing. This way, html pages remains the same
+// regardless of whether this compatibility module is used or not.
+// Recommended usage is as follows. the code below loads dojox.mobile.compat
+// only when isWebKit is true.
+//
+// dojo.require("dojox.mobile");
+//
+//
+// This module also loads compatibility CSS files, which has -compat.css
+// suffix. You can use either the <link> tag or @import to load theme
+// CSS files. Then, this module searches for the loaded CSS files and loads
+// compatibility CSS files. For example, if you load iphone.css in a page,
+// this module automatically loads iphone-compat.css.
+// If you explicitly load iphone-compat.css with <link> or @import,
+// this module will not load the already loaded file.
+
+if(!dojo.isWebKit){
+
+dojo.extend(dojox.mobile.View, {
+ _doTransition: function(fromNode, toNode, transition, dir){
+ var anim;
+ this.wakeUp(toNode);
+ if(!transition || transition == "none"){
+ toNode.style.display = "";
+ fromNode.style.display = "none";
+ toNode.style.left = "0px";
+ this.invokeCallback();
+ }else if(transition == "slide"){
+ var w = fromNode.offsetWidth;
+ var s1 = dojo.fx.slideTo({
+ node: fromNode,
+ duration: 400,
+ left: -w*dir,
+ top: fromNode.offsetTop
+ });
+ var s2 = dojo.fx.slideTo({
+ node: toNode,
+ duration: 400,
+ left: 0
+ });
+ toNode.style.position = "absolute";
+ toNode.style.left = w*dir + "px";
+ toNode.style.display = "";
+ anim = dojo.fx.combine([s1,s2]);
+ dojo.connect(anim, "onEnd", this, function(){
+ fromNode.style.display = "none";
+ toNode.style.position = "relative";
+ this.invokeCallback();
+ });
+ anim.play();
+ }else if(transition == "flip"){
+ anim = dojox.fx.flip({
+ node: fromNode,
+ dir: "right",
+ depth: 0.5,
+ duration: 400
+ });
+ toNode.style.position = "absolute";
+ toNode.style.left = "0px";
+ dojo.connect(anim, "onEnd", this, function(){
+ fromNode.style.display = "none";
+ toNode.style.position = "relative";
+ toNode.style.display = "";
+ this.invokeCallback();
+ });
+ anim.play();
+ }else if(transition == "fade"){
+ anim = dojo.fx.chain([
+ dojo.fadeOut({
+ node: fromNode,
+ duration: 600
+ }),
+ dojo.fadeIn({
+ node: toNode,
+ duration: 600
+ })
+ ]);
+ toNode.style.position = "absolute";
+ toNode.style.left = "0px";
+ toNode.style.display = "";
+ dojo.style(toNode, "opacity", 0);
+ dojo.connect(anim, "onEnd", this, function(){
+ fromNode.style.display = "none";
+ toNode.style.position = "relative";
+ dojo.style(fromNode, "opacity", 1);
+ this.invokeCallback();
+ });
+ anim.play();
+ }
+ },
+
+ wakeUp: function(node){
+ // summary:
+ // Function to force IE to redraw a node since its layout code tends to misrender
+ // in partial draws.
+ // node:
+ // The node to forcibly redraw.
+ // tags:
+ // public
+ if(dojo.isIE && !node._wokeup){
+ node._wokeup = true;
+ var disp = node.style.display;
+ node.style.display = "";
+ var nodes = node.getElementsByTagName("*");
+ for(var i = 0, len = nodes.length; i < len; i++){
+ var val = nodes[i].style.display;
+ nodes[i].style.display = "none";
+ nodes[i].style.display = "";
+ nodes[i].style.display = val;
+ }
+ node.style.display = disp;
+ }
+ }
+});
+
+dojo.extend(dojox.mobile.Switch, {
+ buildRendering: function(){
+ // summary:
+ // Function to simulate the mobile device style switches on
+ // browsers such as IE and FireFox.
+ // tags:
+ // protected
+ this.domNode = this.srcNodeRef || dojo.doc.createElement("DIV");
+ this.domNode.className = "mblSwitch";
+ this.domNode.innerHTML =
+ '<div class="mblSwitchInner">'
+ + '<div class="mblSwitchBg mblSwitchBgLeft">'
+ + '<div class="mblSwitchCorner mblSwitchCorner1T"></div>'
+ + '<div class="mblSwitchCorner mblSwitchCorner2T"></div>'
+ + '<div class="mblSwitchCorner mblSwitchCorner3T"></div>'
+ + '<div class="mblSwitchText mblSwitchTextLeft">'+this.leftLabel+'</div>'
+ + '<div class="mblSwitchCorner mblSwitchCorner1B"></div>'
+ + '<div class="mblSwitchCorner mblSwitchCorner2B"></div>'
+ + '<div class="mblSwitchCorner mblSwitchCorner3B"></div>'
+ + '</div>'
+ + '<div class="mblSwitchBg mblSwitchBgRight">'
+ + '<div class="mblSwitchCorner mblSwitchCorner1T"></div>'
+ + '<div class="mblSwitchCorner mblSwitchCorner2T"></div>'
+ + '<div class="mblSwitchCorner mblSwitchCorner3T"></div>'
+ + '<div class="mblSwitchText mblSwitchTextRight">'+this.rightLabel+'</div>'
+ + '<div class="mblSwitchCorner mblSwitchCorner1B"></div>'
+ + '<div class="mblSwitchCorner mblSwitchCorner2B"></div>'
+ + '<div class="mblSwitchCorner mblSwitchCorner3B"></div>'
+ + '</div>'
+ + '<div class="mblSwitchKnobContainer">'
+ + '<div class="mblSwitchCorner mblSwitchCorner1T"></div>'
+ + '<div class="mblSwitchCorner mblSwitchCorner2T"></div>'
+ + '<div class="mblSwitchCorner mblSwitchCorner3T"></div>'
+ + '<div class="mblSwitchKnob"></div>'
+ + '<div class="mblSwitchCorner mblSwitchCorner1B"></div>'
+ + '<div class="mblSwitchCorner mblSwitchCorner2B"></div>'
+ + '<div class="mblSwitchCorner mblSwitchCorner3B"></div>'
+ + '</div>'
+ + '</div>';
+ var n = this.inner = this.domNode.firstChild;
+ this.left = n.childNodes[0];
+ this.right = n.childNodes[1];
+ this.knob = n.childNodes[2];
+
+ dojo.addClass(this.domNode, (this.value == "on") ? "mblSwitchOn" : "mblSwitchOff");
+ this[this.value == "off" ? "left" : "right"].style.display = "none";
+ },
+
+ _changeState: function(/*String*/state){
+ // summary:
+ // Function to toggle the switch state on the switch
+ // state:
+ // Thhe state to toggle, switch 'on' or 'off'
+ // tags:
+ // private
+ if(!this.inner.parentNode || !this.inner.parentNode.tagName){
+ dojo.addClass(this.domNode, (state == "on") ? "mblSwitchOn" : "mblSwitchOff");
+ return;
+ }
+ var pos;
+ if(this.inner.offsetLeft == 0){ // currently ON
+ if(state == "on"){ return; }
+ pos = -53;
+ }else{ // currently OFF
+ if(state == "off"){ return; }
+ pos = 0;
+ }
+
+ var a = dojo.fx.slideTo({
+ node: this.inner,
+ duration: 500,
+ left: pos
+ });
+ var _this = this;
+ dojo.connect(a, "onEnd", function(){
+ _this[state == "off" ? "left" : "right"].style.display = "none";
+ });
+ a.play();
+ }
+});
+
+if(dojo.isIE || dojo.isBB){
+
+dojo.extend(dojox.mobile.RoundRect, {
+ buildRendering: function(){
+ // summary:
+ // Function to simulate the borderRadius appearance on IE, since
+ // IE does not support this CSS style.
+ // tags:
+ // protected
+ dojox.mobile.createRoundRect(this);
+ this.domNode.className = "mblRoundRect";
+ }
+});
+
+dojox.mobile.RoundRectList._addChild = dojox.mobile.RoundRectList.prototype.addChild;
+dojo.extend(dojox.mobile.RoundRectList, {
+ buildRendering: function(){
+ // summary:
+ // Function to simulate the borderRadius appearance on IE, since
+ // IE does not support this CSS style.
+ // tags:
+ // protected
+ dojox.mobile.createRoundRect(this, true);
+ this.domNode.className = "mblRoundRectList";
+ },
+
+ postCreate: function(){
+ this.redrawBorders();
+ },
+
+ addChild: function(widget){
+ dojox.mobile.RoundRectList._addChild.apply(this, arguments);
+ this.redrawBorders();
+ if(dojox.mobile.applyPngFilter){
+ dojox.mobile.applyPngFilter(widget.domNode);
+ }
+ },
+
+ redrawBorders: function(){
+ // summary:
+ // Function to adjust the creation of RoundRectLists on IE.
+ // Removed undesired styles.
+ // tags:
+ // public
+
+ // Remove a border of the last ListItem.
+ // This is for browsers that do not support the last-child CSS pseudo-class.
+
+ var lastChildFound = false;
+ for(var i = this.containerNode.childNodes.length - 1; i >= 0; i--){
+ var c = this.containerNode.childNodes[i];
+ if(c.tagName == "LI"){
+ c.style.borderBottomStyle = lastChildFound ? "solid" : "none";
+ lastChildFound = true;
+ }
+ }
+ }
+});
+
+dojo.extend(dojox.mobile.EdgeToEdgeList, {
+ buildRendering: function(){
+ this.domNode = this.containerNode = this.srcNodeRef || dojo.doc.createElement("UL");
+ this.domNode.className = "mblEdgeToEdgeList";
+ }
+});
+
+if(dojox.mobile.IconContainer){
+
+dojox.mobile.IconContainer._addChild = dojox.mobile.IconContainer.prototype.addChild;
+dojo.extend(dojox.mobile.IconContainer, {
+ addChild: function(widget){
+ dojox.mobile.IconContainer._addChild.apply(this, arguments);
+ if(dojox.mobile.applyPngFilter){
+ dojox.mobile.applyPngFilter(widget.domNode);
+ }
+ }
+});
+
+} // if(dojox.mobile.IconContainer)
+
+dojo.mixin(dojox.mobile, {
+ createRoundRect: function(_this, isList){
+ // summary:
+ // Function to adjust the creation of rounded rectangles on IE.
+ // Deals with IE's lack of borderRadius support
+ // tags:
+ // public
+ var i;
+ _this.domNode = dojo.doc.createElement("DIV");
+ _this.domNode.style.padding = "0px";
+ _this.domNode.style.backgroundColor = "transparent";
+ _this.domNode.style.borderStyle = "none";
+ _this.containerNode = dojo.doc.createElement(isList?"UL":"DIV");
+ _this.containerNode.className = "mblRoundRectContainer";
+ if(_this.srcNodeRef){
+ _this.srcNodeRef.parentNode.replaceChild(_this.domNode, _this.srcNodeRef);
+ for(i = 0, len = _this.srcNodeRef.childNodes.length; i < len; i++){
+ _this.containerNode.appendChild(_this.srcNodeRef.removeChild(_this.srcNodeRef.firstChild));
+ }
+ _this.srcNodeRef = null;
+ }
+ _this.domNode.appendChild(_this.containerNode);
+
+ for(i = 0; i <= 5; i++){
+ var top = dojo.create("DIV");
+ top.className = "mblRoundCorner mblRoundCorner"+i+"T";
+ _this.domNode.insertBefore(top, _this.containerNode);
+
+ var bottom = dojo.create("DIV");
+ bottom.className = "mblRoundCorner mblRoundCorner"+i+"B";
+ _this.domNode.appendChild(bottom);
+ }
+ }
+});
+
+if(dojox.mobile.ScrollableView){
+
+dojo.extend(dojox.mobile.ScrollableView, {
+ postCreate: function(){
+ // On IE, margin-top of the first child does not seem to be effective,
+ // probably because padding-top is specified for containerNode
+ // to make room for a fixed header. This dummy node is a workaround for that.
+ var dummy = dojo.create("DIV", {className:"mblDummyForIE", innerHTML:"&nbsp;"}, this.containerNode, "first");
+ dojo.style(dummy, {
+ position: "relative",
+ marginBottom: "-2px",
+ fontSize: "1px"
+ });
+ }
+});
+
+} // if(dojox.mobile.ScrollableView)
+
+} // if(dojo.isIE)
+
+if(dojo.isIE <= 6){
+ dojox.mobile.applyPngFilter = function(root){
+ root = root || dojo.body();
+ var nodes = root.getElementsByTagName("IMG");
+ var blank = dojo.moduleUrl("dojo", "resources/blank.gif");
+ for(var i = 0, len = nodes.length; i < len; i++){
+ var img = nodes[i];
+ var w = img.offsetWidth;
+ var h = img.offsetHeight;
+ if(w === 0 || h === 0){
+ // The reason why the image has no width/height may be because
+ // display is "none". If that is the case, let's change the
+ // display to "" temporarily and see if the image returns them.
+ if(dojo.style(img, "display") != "none"){ continue; }
+ img.style.display = "";
+ w = img.offsetWidth;
+ h = img.offsetHeight;
+ img.style.display = "none";
+ if(w === 0 || h === 0){ continue; }
+ }
+ var src = img.src;
+ if(src.indexOf("resources/blank.gif") != -1){ continue; }
+ img.src = blank;
+ img.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + src+"')";
+ img.style.width = w + "px";
+ img.style.height = h + "px";
+ }
+ };
+} // if(dojo.isIE <= 6)
+
+dojox.mobile.loadCss = function(/*String|Array*/files){
+ // summary:
+ // Function to load and register CSS files with the page
+ // files: String|Array
+ // The CSS files to load and register with the page.
+ // tags:
+ // private
+ if(!dojo.global._loadedCss){
+ var obj = {};
+ dojo.forEach(dojox.mobile.getCssPaths(), function(path){
+ obj[path] = true;
+ });
+ dojo.global._loadedCss = obj;
+ }
+ if(!dojo.isArray(files)){ files = [files]; }
+ for(var i = 0; i < files.length; i++){
+ var file = files[i];
+ if(!dojo.global._loadedCss[file]){
+ dojo.global._loadedCss[file] = true;
+ if(dojo.doc.createStyleSheet){
+ // for some reason, IE hangs when you try to load
+ // multiple css files almost at once.
+ setTimeout(function(file){
+ return function(){
+ dojo.doc.createStyleSheet(file);
+ };
+ }(file), 0);
+ }else{
+ var link = dojo.doc.createElement("link");
+ link.href = file;
+ link.type = "text/css";
+ link.rel = "stylesheet";
+ var head = dojo.doc.getElementsByTagName('head')[0];
+ head.appendChild(link);
+ }
+ }
+ }
+};
+
+dojox.mobile.getCssPaths = function(){
+ var paths = [];
+ var i, j;
+
+ // find @import
+ var s = dojo.doc.styleSheets;
+ for(i = 0; i < s.length; i++){
+ var r = s[i].cssRules || s[i].imports;
+ if(!r){ continue; }
+ for(j = 0; j < r.length; j++){
+ if(r[j].href){
+ paths.push(r[j].href);
+ }
+ }
+ }
+
+ // find <link>
+ var elems = dojo.doc.getElementsByTagName("link");
+ for(i = 0, len = elems.length; i < len; i++){
+ if(elems[i].href){
+ paths.push(elems[i].href);
+ }
+ }
+ return paths;
+};
+
+dojox.mobile.loadCompatPattern = /\/themes\/(domButtons|buttons|iphone|android).*\.css$/;
+
+dojox.mobile.loadCompatCssFiles = function(){
+ // summary:
+ // Function to perform page-level adjustments on browsers such as
+ // IE and firefox. It loads compat specific css files into the
+ // page header.
+ var paths = dojox.mobile.getCssPaths();
+ for(var i = 0; i < paths.length; i++){
+ var href = paths[i];
+ if(href.match(dojox.mobile.loadCompatPattern) && href.indexOf("-compat.css") == -1){
+ var compatCss = href.substring(0, href.length-4)+"-compat.css";
+ dojox.mobile.loadCss(compatCss);
+ }
+ }
+};
+
+dojox.mobile.hideAddressBar = function(){
+ // nop
+};
+
+dojo.addOnLoad(function(){
+ if(dojo.config["mblLoadCompatCssFiles"] !== false){
+ dojox.mobile.loadCompatCssFiles();
+ }
+ if(dojox.mobile.applyPngFilter){
+ dojox.mobile.applyPngFilter();
+ }
+});
+
+} // end of if(!dojo.isWebKit){
+
+}
+
+if(!dojo._hasResource["dojox.mobile.app.compat"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.mobile.app.compat"] = true;
+dojo.provide("dojox.mobile.app.compat");
+
+
+// summary:
+// CSS3 compatibility module for apps
+// description:
+// This module provides support for some of the CSS3 features to djMobile
+// for non-CSS3 browsers, such as IE or Firefox.
+// If you load this module, it directly replaces some of the methods of
+// djMobile instead of subclassing. This way, html pages remains the same
+// regardless of whether this compatibility module is used or not.
+// Recommended usage is as follows. the code below loads dojox.mobile.compat
+// only when isWebKit is true.
+//
+// dojo.require("dojox.mobile");
+// dojo.requireIf(!dojo.isWebKit, "dojox.mobile.appCompat");
+
+dojo.extend(dojox.mobile.app.AlertDialog, {
+ _doTransition: function(dir){
+ console.log("in _doTransition and this = ", this);
+
+ var h = dojo.marginBox(this.domNode.firstChild).h;
+
+ var bodyHeight = this.controller.getWindowSize().h;
+
+ var high = bodyHeight - h;
+ var low = bodyHeight;
+
+ var anim1 = dojo.fx.slideTo({
+ node: this.domNode,
+ duration: 400,
+ top: {start: dir < 0 ? high : low, end: dir < 0 ? low: high}
+ });
+
+ var anim2 = dojo[dir < 0 ? "fadeOut" : "fadeIn"]({
+ node: this.mask,
+ duration: 400
+ });
+
+ var anim = dojo.fx.combine([anim1, anim2]);
+
+ var _this = this;
+
+ dojo.connect(anim, "onEnd", this, function(){
+ if(dir < 0){
+ _this.domNode.style.display = "none";
+ dojo.destroy(_this.domNode);
+ dojo.destroy(_this.mask);
+ }
+ });
+ anim.play();
+ }
+});
+
+dojo.extend(dojox.mobile.app.List, {
+ deleteRow: function(){
+ console.log("deleteRow in compat mode", row);
+
+ var row = this._selectedRow;
+ // First make the row invisible
+ // Put it back where it came from
+ dojo.style(row, {
+ visibility: "hidden",
+ minHeight: "0px"
+ });
+ dojo.removeClass(row, "hold");
+
+
+ // Animate reducing it's height to zero, then delete the data from the
+ // array
+ var height = dojo.contentBox(row).h;
+ dojo.animateProperty({
+ node: row,
+ duration: 800,
+ properties: {
+ height: {start: height, end: 1},
+ paddingTop: {end: 0},
+ paddingBottom: {end: 0}
+ },
+ onEnd: this._postDeleteAnim
+ }).play();
+ }
+});
+
+if(dojox.mobile.app.ImageView && !dojo.create("canvas").getContext){
+ dojo.extend(dojox.mobile.app.ImageView, {
+ buildRendering: function(){
+ this.domNode.innerHTML =
+ "ImageView widget is not supported on this browser."
+ + "Please try again with a modern browser, e.g. "
+ + "Safari, Chrome or Firefox";
+ this.canvas = {};
+ },
+
+ postCreate: function(){}
+ });
+}
+
+if(dojox.mobile.app.ImageThumbView){
+ dojo.extend(dojox.mobile.app.ImageThumbView, {
+ place: function(node, x, y){
+ dojo.style(node, {
+ top: y + "px",
+ left: x + "px",
+ visibility: "visible"
+ });
+ }
+ })
+}
+
+}
+
diff --git a/js/dojo-1.6/dojox/mobile/app/compat.xd.js b/js/dojo-1.6/dojox/mobile/app/compat.xd.js
new file mode 100644
index 0000000..60c026b
--- /dev/null
+++ b/js/dojo-1.6/dojox/mobile/app/compat.xd.js
@@ -0,0 +1,14 @@
+/*
+ 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
+*/
+
+dojo._xdResourceLoaded(function(_1,_2,_3){return {depends:[["provide","dojo.uacss"],["provide","dijit._base.sniff"],["provide","dojo.fx.Toggler"],["provide","dojo.fx"],["provide","dojox.fx.flip"],["provide","dojox.mobile.compat"],["provide","dojox.mobile.app.compat"]],defineResource:function(_4,_5,_6){if(!_4._hasResource["dojo.uacss"]){_4._hasResource["dojo.uacss"]=true;_4.provide("dojo.uacss");(function(){var d=_4,_7=d.doc.documentElement,ie=d.isIE,_8=d.isOpera,_9=Math.floor,ff=d.isFF,_a=d.boxModel.replace(/-/,""),_b={dj_ie:ie,dj_ie6:_9(ie)==6,dj_ie7:_9(ie)==7,dj_ie8:_9(ie)==8,dj_ie9:_9(ie)==9,dj_quirks:d.isQuirks,dj_iequirks:ie&&d.isQuirks,dj_opera:_8,dj_khtml:d.isKhtml,dj_webkit:d.isWebKit,dj_safari:d.isSafari,dj_chrome:d.isChrome,dj_gecko:d.isMozilla,dj_ff3:_9(ff)==3};_b["dj_"+_a]=true;var _c="";for(var _d in _b){if(_b[_d]){_c+=_d+" ";}}_7.className=d.trim(_7.className+" "+_c);_4._loaders.unshift(function(){if(!_4._isBodyLtr()){var _e="dj_rtl dijitRtl "+_c.replace(/ /g,"-rtl ");_7.className=d.trim(_7.className+" "+_e);}});})();}if(!_4._hasResource["dijit._base.sniff"]){_4._hasResource["dijit._base.sniff"]=true;_4.provide("dijit._base.sniff");}if(!_4._hasResource["dojo.fx.Toggler"]){_4._hasResource["dojo.fx.Toggler"]=true;_4.provide("dojo.fx.Toggler");_4.declare("dojo.fx.Toggler",null,{node:null,showFunc:_4.fadeIn,hideFunc:_4.fadeOut,showDuration:200,hideDuration:200,constructor:function(_f){var _10=this;_4.mixin(_10,_f);_10.node=_f.node;_10._showArgs=_4.mixin({},_f);_10._showArgs.node=_10.node;_10._showArgs.duration=_10.showDuration;_10.showAnim=_10.showFunc(_10._showArgs);_10._hideArgs=_4.mixin({},_f);_10._hideArgs.node=_10.node;_10._hideArgs.duration=_10.hideDuration;_10.hideAnim=_10.hideFunc(_10._hideArgs);_4.connect(_10.showAnim,"beforeBegin",_4.hitch(_10.hideAnim,"stop",true));_4.connect(_10.hideAnim,"beforeBegin",_4.hitch(_10.showAnim,"stop",true));},show:function(_11){return this.showAnim.play(_11||0);},hide:function(_12){return this.hideAnim.play(_12||0);}});}if(!_4._hasResource["dojo.fx"]){_4._hasResource["dojo.fx"]=true;_4.provide("dojo.fx");(function(){var d=_4,_13={_fire:function(evt,_14){if(this[evt]){this[evt].apply(this,_14||[]);}return this;}};var _15=function(_16){this._index=-1;this._animations=_16||[];this._current=this._onAnimateCtx=this._onEndCtx=null;this.duration=0;d.forEach(this._animations,function(a){this.duration+=a.duration;if(a.delay){this.duration+=a.delay;}},this);};d.extend(_15,{_onAnimate:function(){this._fire("onAnimate",arguments);},_onEnd:function(){d.disconnect(this._onAnimateCtx);d.disconnect(this._onEndCtx);this._onAnimateCtx=this._onEndCtx=null;if(this._index+1==this._animations.length){this._fire("onEnd");}else{this._current=this._animations[++this._index];this._onAnimateCtx=d.connect(this._current,"onAnimate",this,"_onAnimate");this._onEndCtx=d.connect(this._current,"onEnd",this,"_onEnd");this._current.play(0,true);}},play:function(_17,_18){if(!this._current){this._current=this._animations[this._index=0];}if(!_18&&this._current.status()=="playing"){return this;}var _19=d.connect(this._current,"beforeBegin",this,function(){this._fire("beforeBegin");}),_1a=d.connect(this._current,"onBegin",this,function(arg){this._fire("onBegin",arguments);}),_1b=d.connect(this._current,"onPlay",this,function(arg){this._fire("onPlay",arguments);d.disconnect(_19);d.disconnect(_1a);d.disconnect(_1b);});if(this._onAnimateCtx){d.disconnect(this._onAnimateCtx);}this._onAnimateCtx=d.connect(this._current,"onAnimate",this,"_onAnimate");if(this._onEndCtx){d.disconnect(this._onEndCtx);}this._onEndCtx=d.connect(this._current,"onEnd",this,"_onEnd");this._current.play.apply(this._current,arguments);return this;},pause:function(){if(this._current){var e=d.connect(this._current,"onPause",this,function(arg){this._fire("onPause",arguments);d.disconnect(e);});this._current.pause();}return this;},gotoPercent:function(_1c,_1d){this.pause();var _1e=this.duration*_1c;this._current=null;d.some(this._animations,function(a){if(a.duration<=_1e){this._current=a;return true;}_1e-=a.duration;return false;});if(this._current){this._current.gotoPercent(_1e/this._current.duration,_1d);}return this;},stop:function(_1f){if(this._current){if(_1f){for(;this._index+1<this._animations.length;++this._index){this._animations[this._index].stop(true);}this._current=this._animations[this._index];}var e=d.connect(this._current,"onStop",this,function(arg){this._fire("onStop",arguments);d.disconnect(e);});this._current.stop();}return this;},status:function(){return this._current?this._current.status():"stopped";},destroy:function(){if(this._onAnimateCtx){d.disconnect(this._onAnimateCtx);}if(this._onEndCtx){d.disconnect(this._onEndCtx);}}});d.extend(_15,_13);_4.fx.chain=function(_20){return new _15(_20);};var _21=function(_22){this._animations=_22||[];this._connects=[];this._finished=0;this.duration=0;d.forEach(_22,function(a){var _23=a.duration;if(a.delay){_23+=a.delay;}if(this.duration<_23){this.duration=_23;}this._connects.push(d.connect(a,"onEnd",this,"_onEnd"));},this);this._pseudoAnimation=new d.Animation({curve:[0,1],duration:this.duration});var _24=this;d.forEach(["beforeBegin","onBegin","onPlay","onAnimate","onPause","onStop","onEnd"],function(evt){_24._connects.push(d.connect(_24._pseudoAnimation,evt,function(){_24._fire(evt,arguments);}));});};d.extend(_21,{_doAction:function(_25,_26){d.forEach(this._animations,function(a){a[_25].apply(a,_26);});return this;},_onEnd:function(){if(++this._finished>this._animations.length){this._fire("onEnd");}},_call:function(_27,_28){var t=this._pseudoAnimation;t[_27].apply(t,_28);},play:function(_29,_2a){this._finished=0;this._doAction("play",arguments);this._call("play",arguments);return this;},pause:function(){this._doAction("pause",arguments);this._call("pause",arguments);return this;},gotoPercent:function(_2b,_2c){var ms=this.duration*_2b;d.forEach(this._animations,function(a){a.gotoPercent(a.duration<ms?1:(ms/a.duration),_2c);});this._call("gotoPercent",arguments);return this;},stop:function(_2d){this._doAction("stop",arguments);this._call("stop",arguments);return this;},status:function(){return this._pseudoAnimation.status();},destroy:function(){d.forEach(this._connects,_4.disconnect);}});d.extend(_21,_13);_4.fx.combine=function(_2e){return new _21(_2e);};_4.fx.wipeIn=function(_2f){var _30=_2f.node=d.byId(_2f.node),s=_30.style,o;var _31=d.animateProperty(d.mixin({properties:{height:{start:function(){o=s.overflow;s.overflow="hidden";if(s.visibility=="hidden"||s.display=="none"){s.height="1px";s.display="";s.visibility="";return 1;}else{var _32=d.style(_30,"height");return Math.max(_32,1);}},end:function(){return _30.scrollHeight;}}}},_2f));d.connect(_31,"onEnd",function(){s.height="auto";s.overflow=o;});return _31;};_4.fx.wipeOut=function(_33){var _34=_33.node=d.byId(_33.node),s=_34.style,o;var _35=d.animateProperty(d.mixin({properties:{height:{end:1}}},_33));d.connect(_35,"beforeBegin",function(){o=s.overflow;s.overflow="hidden";s.display="";});d.connect(_35,"onEnd",function(){s.overflow=o;s.height="auto";s.display="none";});return _35;};_4.fx.slideTo=function(_36){var _37=_36.node=d.byId(_36.node),top=null,_38=null;var _39=(function(n){return function(){var cs=d.getComputedStyle(n);var pos=cs.position;top=(pos=="absolute"?n.offsetTop:parseInt(cs.top)||0);_38=(pos=="absolute"?n.offsetLeft:parseInt(cs.left)||0);if(pos!="absolute"&&pos!="relative"){var ret=d.position(n,true);top=ret.y;_38=ret.x;n.style.position="absolute";n.style.top=top+"px";n.style.left=_38+"px";}};})(_37);_39();var _3a=d.animateProperty(d.mixin({properties:{top:_36.top||0,left:_36.left||0}},_36));d.connect(_3a,"beforeBegin",_3a,_39);return _3a;};})();}if(!_4._hasResource["dojox.fx.flip"]){_4._hasResource["dojox.fx.flip"]=true;_4.provide("dojox.fx.flip");_4.experimental("dojox.fx.flip");var _3b="border",_3c="Width",_3d="Height",_3e="Top",_3f="Right",_40="Left",_41="Bottom";_6.fx.flip=function(_42){var _43=_4.create("div"),_44=_42.node=_4.byId(_42.node),s=_44.style,_45=null,hs=null,pn=null,_46=_42.lightColor||"#dddddd",_47=_42.darkColor||"#555555",_48=_4.style(_44,"backgroundColor"),_49=_42.endColor||_48,_4a={},_4b=[],_4c=_42.duration?_42.duration/2:250,dir=_42.dir||"left",_4d=0.9,_4e="transparent",_4f=_42.whichAnim,_50=_42.axis||"center",_51=_42.depth;var _52=function(_53){return ((new _4.Color(_53)).toHex()==="#000000")?"#000001":_53;};if(_4.isIE<7){_49=_52(_49);_46=_52(_46);_47=_52(_47);_48=_52(_48);_4e="black";_43.style.filter="chroma(color='#000000')";}var _54=(function(n){return function(){var ret=_4.coords(n,true);_45={top:ret.y,left:ret.x,width:ret.w,height:ret.h};};})(_44);_54();hs={position:"absolute",top:_45["top"]+"px",left:_45["left"]+"px",height:"0",width:"0",zIndex:_42.zIndex||(s.zIndex||0),border:"0 solid "+_4e,fontSize:"0",visibility:"hidden"};var _55=[{},{top:_45["top"],left:_45["left"]}];var _56={left:[_40,_3f,_3e,_41,_3c,_3d,"end"+_3d+"Min",_40,"end"+_3d+"Max"],right:[_3f,_40,_3e,_41,_3c,_3d,"end"+_3d+"Min",_40,"end"+_3d+"Max"],top:[_3e,_41,_40,_3f,_3d,_3c,"end"+_3c+"Min",_3e,"end"+_3c+"Max"],bottom:[_41,_3e,_40,_3f,_3d,_3c,"end"+_3c+"Min",_3e,"end"+_3c+"Max"]};pn=_56[dir];if(typeof _51!="undefined"){_51=Math.max(0,Math.min(1,_51))/2;_4d=0.4+(0.5-_51);}else{_4d=Math.min(0.9,Math.max(0.4,_45[pn[5].toLowerCase()]/_45[pn[4].toLowerCase()]));}var p0=_55[0];for(var i=4;i<6;i++){if(_50=="center"||_50=="cube"){_45["end"+pn[i]+"Min"]=_45[pn[i].toLowerCase()]*_4d;_45["end"+pn[i]+"Max"]=_45[pn[i].toLowerCase()]/_4d;}else{if(_50=="shortside"){_45["end"+pn[i]+"Min"]=_45[pn[i].toLowerCase()];_45["end"+pn[i]+"Max"]=_45[pn[i].toLowerCase()]/_4d;}else{if(_50=="longside"){_45["end"+pn[i]+"Min"]=_45[pn[i].toLowerCase()]*_4d;_45["end"+pn[i]+"Max"]=_45[pn[i].toLowerCase()];}}}}if(_50=="center"){p0[pn[2].toLowerCase()]=_45[pn[2].toLowerCase()]-(_45[pn[8]]-_45[pn[6]])/4;}else{if(_50=="shortside"){p0[pn[2].toLowerCase()]=_45[pn[2].toLowerCase()]-(_45[pn[8]]-_45[pn[6]])/2;}}_4a[pn[5].toLowerCase()]=_45[pn[5].toLowerCase()]+"px";_4a[pn[4].toLowerCase()]="0";_4a[_3b+pn[1]+_3c]=_45[pn[4].toLowerCase()]+"px";_4a[_3b+pn[1]+"Color"]=_48;p0[_3b+pn[1]+_3c]=0;p0[_3b+pn[1]+"Color"]=_47;p0[_3b+pn[2]+_3c]=p0[_3b+pn[3]+_3c]=_50!="cube"?(_45["end"+pn[5]+"Max"]-_45["end"+pn[5]+"Min"])/2:_45[pn[6]]/2;p0[pn[7].toLowerCase()]=_45[pn[7].toLowerCase()]+_45[pn[4].toLowerCase()]/2+(_42.shift||0);p0[pn[5].toLowerCase()]=_45[pn[6]];var p1=_55[1];p1[_3b+pn[0]+"Color"]={start:_46,end:_49};p1[_3b+pn[0]+_3c]=_45[pn[4].toLowerCase()];p1[_3b+pn[2]+_3c]=0;p1[_3b+pn[3]+_3c]=0;p1[pn[5].toLowerCase()]={start:_45[pn[6]],end:_45[pn[5].toLowerCase()]};_4.mixin(hs,_4a);_4.style(_43,hs);_4.body().appendChild(_43);var _57=function(){_4.destroy(_43);s.backgroundColor=_49;s.visibility="visible";};if(_4f=="last"){for(i in p0){p0[i]={start:p0[i]};}p0[_3b+pn[1]+"Color"]={start:_47,end:_49};p1=p0;}if(!_4f||_4f=="first"){_4b.push(_4.animateProperty({node:_43,duration:_4c,properties:p0}));}if(!_4f||_4f=="last"){_4b.push(_4.animateProperty({node:_43,duration:_4c,properties:p1,onEnd:_57}));}_4.connect(_4b[0],"play",function(){_43.style.visibility="visible";s.visibility="hidden";});return _4.fx.chain(_4b);};_6.fx.flipCube=function(_58){var _59=[],mb=_4.marginBox(_58.node),_5a=mb.w/2,_5b=mb.h/2,_5c={top:{pName:"height",args:[{whichAnim:"first",dir:"top",shift:-_5b},{whichAnim:"last",dir:"bottom",shift:_5b}]},right:{pName:"width",args:[{whichAnim:"first",dir:"right",shift:_5a},{whichAnim:"last",dir:"left",shift:-_5a}]},bottom:{pName:"height",args:[{whichAnim:"first",dir:"bottom",shift:_5b},{whichAnim:"last",dir:"top",shift:-_5b}]},left:{pName:"width",args:[{whichAnim:"first",dir:"left",shift:-_5a},{whichAnim:"last",dir:"right",shift:_5a}]}};var d=_5c[_58.dir||"left"],p=d.args;_58.duration=_58.duration?_58.duration*2:500;_58.depth=0.8;_58.axis="cube";for(var i=p.length-1;i>=0;i--){_4.mixin(_58,p[i]);_59.push(_6.fx.flip(_58));}return _4.fx.combine(_59);};_6.fx.flipPage=function(_5d){var n=_5d.node,_5e=_4.coords(n,true),x=_5e.x,y=_5e.y,w=_5e.w,h=_5e.h,_5f=_4.style(n,"backgroundColor"),_60=_5d.lightColor||"#dddddd",_61=_5d.darkColor,_62=_4.create("div"),_63=[],hn=[],dir=_5d.dir||"right",pn={left:["left","right","x","w"],top:["top","bottom","y","h"],right:["left","left","x","w"],bottom:["top","top","y","h"]},_64={right:[1,-1],left:[-1,1],top:[-1,1],bottom:[1,-1]};_4.style(_62,{position:"absolute",width:w+"px",height:h+"px",top:y+"px",left:x+"px",visibility:"hidden"});var hs=[];for(var i=0;i<2;i++){var r=i%2,d=r?pn[dir][1]:dir,wa=r?"last":"first",_65=r?_5f:_60,_66=r?_65:_5d.startColor||n.style.backgroundColor;hn[i]=_4.clone(_62);var _67=function(x){return function(){_4.destroy(hn[x]);};}(i);_4.body().appendChild(hn[i]);hs[i]={backgroundColor:r?_66:_5f};hs[i][pn[dir][0]]=_5e[pn[dir][2]]+_64[dir][0]*i*_5e[pn[dir][3]]+"px";_4.style(hn[i],hs[i]);_63.push(_6.fx.flip({node:hn[i],dir:d,axis:"shortside",depth:_5d.depth,duration:_5d.duration/2,shift:_64[dir][i]*_5e[pn[dir][3]]/2,darkColor:_61,lightColor:_60,whichAnim:wa,endColor:_65}));_4.connect(_63[i],"onEnd",_67);}return _4.fx.chain(_63);};_6.fx.flipGrid=function(_68){var _69=_68.rows||4,_6a=_68.cols||4,_6b=[],_6c=_4.create("div"),n=_68.node,_6d=_4.coords(n,true),x=_6d.x,y=_6d.y,nw=_6d.w,nh=_6d.h,w=_6d.w/_6a,h=_6d.h/_69,_6e=[];_4.style(_6c,{position:"absolute",width:w+"px",height:h+"px",backgroundColor:_4.style(n,"backgroundColor")});for(var i=0;i<_69;i++){var r=i%2,d=r?"right":"left",_6f=r?1:-1;var cn=_4.clone(n);_4.style(cn,{position:"absolute",width:nw+"px",height:nh+"px",top:y+"px",left:x+"px",clip:"rect("+i*h+"px,"+nw+"px,"+nh+"px,0)"});_4.body().appendChild(cn);_6b[i]=[];for(var j=0;j<_6a;j++){var hn=_4.clone(_6c),l=r?j:_6a-(j+1);var _70=function(xn,_71,_72){return function(){if(!(_71%2)){_4.style(xn,{clip:"rect("+_71*h+"px,"+(nw-(_72+1)*w)+"px,"+((_71+1)*h)+"px,0px)"});}else{_4.style(xn,{clip:"rect("+_71*h+"px,"+nw+"px,"+((_71+1)*h)+"px,"+((_72+1)*w)+"px)"});}};}(cn,i,j);_4.body().appendChild(hn);_4.style(hn,{left:x+l*w+"px",top:y+i*h+"px",visibility:"hidden"});var a=_6.fx.flipPage({node:hn,dir:d,duration:_68.duration||900,shift:_6f*w/2,depth:0.2,darkColor:_68.darkColor,lightColor:_68.lightColor,startColor:_68.startColor||_68.node.style.backgroundColor}),_73=function(xn){return function(){_4.destroy(xn);};}(hn);_4.connect(a,"play",this,_70);_4.connect(a,"play",this,_73);_6b[i].push(a);}_6e.push(_4.fx.chain(_6b[i]));}_4.connect(_6e[0],"play",function(){_4.style(n,{visibility:"hidden"});});return _4.fx.combine(_6e);};}if(!_4._hasResource["dojox.mobile.compat"]){_4._hasResource["dojox.mobile.compat"]=true;_4.provide("dojox.mobile.compat");if(!_4.isWebKit){_4.extend(_6.mobile.View,{_doTransition:function(_74,_75,_76,dir){var _77;this.wakeUp(_75);if(!_76||_76=="none"){_75.style.display="";_74.style.display="none";_75.style.left="0px";this.invokeCallback();}else{if(_76=="slide"){var w=_74.offsetWidth;var s1=_4.fx.slideTo({node:_74,duration:400,left:-w*dir,top:_74.offsetTop});var s2=_4.fx.slideTo({node:_75,duration:400,left:0});_75.style.position="absolute";_75.style.left=w*dir+"px";_75.style.display="";_77=_4.fx.combine([s1,s2]);_4.connect(_77,"onEnd",this,function(){_74.style.display="none";_75.style.position="relative";this.invokeCallback();});_77.play();}else{if(_76=="flip"){_77=_6.fx.flip({node:_74,dir:"right",depth:0.5,duration:400});_75.style.position="absolute";_75.style.left="0px";_4.connect(_77,"onEnd",this,function(){_74.style.display="none";_75.style.position="relative";_75.style.display="";this.invokeCallback();});_77.play();}else{if(_76=="fade"){_77=_4.fx.chain([_4.fadeOut({node:_74,duration:600}),_4.fadeIn({node:_75,duration:600})]);_75.style.position="absolute";_75.style.left="0px";_75.style.display="";_4.style(_75,"opacity",0);_4.connect(_77,"onEnd",this,function(){_74.style.display="none";_75.style.position="relative";_4.style(_74,"opacity",1);this.invokeCallback();});_77.play();}}}}},wakeUp:function(_78){if(_4.isIE&&!_78._wokeup){_78._wokeup=true;var _79=_78.style.display;_78.style.display="";var _7a=_78.getElementsByTagName("*");for(var i=0,len=_7a.length;i<len;i++){var val=_7a[i].style.display;_7a[i].style.display="none";_7a[i].style.display="";_7a[i].style.display=val;}_78.style.display=_79;}}});_4.extend(_6.mobile.Switch,{buildRendering:function(){this.domNode=this.srcNodeRef||_4.doc.createElement("DIV");this.domNode.className="mblSwitch";this.domNode.innerHTML="<div class=\"mblSwitchInner\">"+"<div class=\"mblSwitchBg mblSwitchBgLeft\">"+"<div class=\"mblSwitchCorner mblSwitchCorner1T\"></div>"+"<div class=\"mblSwitchCorner mblSwitchCorner2T\"></div>"+"<div class=\"mblSwitchCorner mblSwitchCorner3T\"></div>"+"<div class=\"mblSwitchText mblSwitchTextLeft\">"+this.leftLabel+"</div>"+"<div class=\"mblSwitchCorner mblSwitchCorner1B\"></div>"+"<div class=\"mblSwitchCorner mblSwitchCorner2B\"></div>"+"<div class=\"mblSwitchCorner mblSwitchCorner3B\"></div>"+"</div>"+"<div class=\"mblSwitchBg mblSwitchBgRight\">"+"<div class=\"mblSwitchCorner mblSwitchCorner1T\"></div>"+"<div class=\"mblSwitchCorner mblSwitchCorner2T\"></div>"+"<div class=\"mblSwitchCorner mblSwitchCorner3T\"></div>"+"<div class=\"mblSwitchText mblSwitchTextRight\">"+this.rightLabel+"</div>"+"<div class=\"mblSwitchCorner mblSwitchCorner1B\"></div>"+"<div class=\"mblSwitchCorner mblSwitchCorner2B\"></div>"+"<div class=\"mblSwitchCorner mblSwitchCorner3B\"></div>"+"</div>"+"<div class=\"mblSwitchKnobContainer\">"+"<div class=\"mblSwitchCorner mblSwitchCorner1T\"></div>"+"<div class=\"mblSwitchCorner mblSwitchCorner2T\"></div>"+"<div class=\"mblSwitchCorner mblSwitchCorner3T\"></div>"+"<div class=\"mblSwitchKnob\"></div>"+"<div class=\"mblSwitchCorner mblSwitchCorner1B\"></div>"+"<div class=\"mblSwitchCorner mblSwitchCorner2B\"></div>"+"<div class=\"mblSwitchCorner mblSwitchCorner3B\"></div>"+"</div>"+"</div>";var n=this.inner=this.domNode.firstChild;this.left=n.childNodes[0];this.right=n.childNodes[1];this.knob=n.childNodes[2];_4.addClass(this.domNode,(this.value=="on")?"mblSwitchOn":"mblSwitchOff");this[this.value=="off"?"left":"right"].style.display="none";},_changeState:function(_7b){if(!this.inner.parentNode||!this.inner.parentNode.tagName){_4.addClass(this.domNode,(_7b=="on")?"mblSwitchOn":"mblSwitchOff");return;}var pos;if(this.inner.offsetLeft==0){if(_7b=="on"){return;}pos=-53;}else{if(_7b=="off"){return;}pos=0;}var a=_4.fx.slideTo({node:this.inner,duration:500,left:pos});var _7c=this;_4.connect(a,"onEnd",function(){_7c[_7b=="off"?"left":"right"].style.display="none";});a.play();}});if(_4.isIE||_4.isBB){_4.extend(_6.mobile.RoundRect,{buildRendering:function(){_6.mobile.createRoundRect(this);this.domNode.className="mblRoundRect";}});_6.mobile.RoundRectList._addChild=_6.mobile.RoundRectList.prototype.addChild;_4.extend(_6.mobile.RoundRectList,{buildRendering:function(){_6.mobile.createRoundRect(this,true);this.domNode.className="mblRoundRectList";},postCreate:function(){this.redrawBorders();},addChild:function(_7d){_6.mobile.RoundRectList._addChild.apply(this,arguments);this.redrawBorders();if(_6.mobile.applyPngFilter){_6.mobile.applyPngFilter(_7d.domNode);}},redrawBorders:function(){var _7e=false;for(var i=this.containerNode.childNodes.length-1;i>=0;i--){var c=this.containerNode.childNodes[i];if(c.tagName=="LI"){c.style.borderBottomStyle=_7e?"solid":"none";_7e=true;}}}});_4.extend(_6.mobile.EdgeToEdgeList,{buildRendering:function(){this.domNode=this.containerNode=this.srcNodeRef||_4.doc.createElement("UL");this.domNode.className="mblEdgeToEdgeList";}});if(_6.mobile.IconContainer){_6.mobile.IconContainer._addChild=_6.mobile.IconContainer.prototype.addChild;_4.extend(_6.mobile.IconContainer,{addChild:function(_7f){_6.mobile.IconContainer._addChild.apply(this,arguments);if(_6.mobile.applyPngFilter){_6.mobile.applyPngFilter(_7f.domNode);}}});}_4.mixin(_6.mobile,{createRoundRect:function(_80,_81){var i;_80.domNode=_4.doc.createElement("DIV");_80.domNode.style.padding="0px";_80.domNode.style.backgroundColor="transparent";_80.domNode.style.borderStyle="none";_80.containerNode=_4.doc.createElement(_81?"UL":"DIV");_80.containerNode.className="mblRoundRectContainer";if(_80.srcNodeRef){_80.srcNodeRef.parentNode.replaceChild(_80.domNode,_80.srcNodeRef);for(i=0,len=_80.srcNodeRef.childNodes.length;i<len;i++){_80.containerNode.appendChild(_80.srcNodeRef.removeChild(_80.srcNodeRef.firstChild));}_80.srcNodeRef=null;}_80.domNode.appendChild(_80.containerNode);for(i=0;i<=5;i++){var top=_4.create("DIV");top.className="mblRoundCorner mblRoundCorner"+i+"T";_80.domNode.insertBefore(top,_80.containerNode);var _82=_4.create("DIV");_82.className="mblRoundCorner mblRoundCorner"+i+"B";_80.domNode.appendChild(_82);}}});if(_6.mobile.ScrollableView){_4.extend(_6.mobile.ScrollableView,{postCreate:function(){var _83=_4.create("DIV",{className:"mblDummyForIE",innerHTML:"&nbsp;"},this.containerNode,"first");_4.style(_83,{position:"relative",marginBottom:"-2px",fontSize:"1px"});}});}}if(_4.isIE<=6){_6.mobile.applyPngFilter=function(_84){_84=_84||_4.body();var _85=_84.getElementsByTagName("IMG");var _86=_4.moduleUrl("dojo","resources/blank.gif");for(var i=0,len=_85.length;i<len;i++){var img=_85[i];var w=img.offsetWidth;var h=img.offsetHeight;if(w===0||h===0){if(_4.style(img,"display")!="none"){continue;}img.style.display="";w=img.offsetWidth;h=img.offsetHeight;img.style.display="none";if(w===0||h===0){continue;}}var src=img.src;if(src.indexOf("resources/blank.gif")!=-1){continue;}img.src=_86;img.runtimeStyle.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+src+"')";img.style.width=w+"px";img.style.height=h+"px";}};}_6.mobile.loadCss=function(_87){if(!_4.global._loadedCss){var obj={};_4.forEach(_6.mobile.getCssPaths(),function(_88){obj[_88]=true;});_4.global._loadedCss=obj;}if(!_4.isArray(_87)){_87=[_87];}for(var i=0;i<_87.length;i++){var _89=_87[i];if(!_4.global._loadedCss[_89]){_4.global._loadedCss[_89]=true;if(_4.doc.createStyleSheet){setTimeout(function(_8a){return function(){_4.doc.createStyleSheet(_8a);};}(_89),0);}else{var _8b=_4.doc.createElement("link");_8b.href=_89;_8b.type="text/css";_8b.rel="stylesheet";var _8c=_4.doc.getElementsByTagName("head")[0];_8c.appendChild(_8b);}}}};_6.mobile.getCssPaths=function(){var _8d=[];var i,j;var s=_4.doc.styleSheets;for(i=0;i<s.length;i++){var r=s[i].cssRules||s[i].imports;if(!r){continue;}for(j=0;j<r.length;j++){if(r[j].href){_8d.push(r[j].href);}}}var _8e=_4.doc.getElementsByTagName("link");for(i=0,len=_8e.length;i<len;i++){if(_8e[i].href){_8d.push(_8e[i].href);}}return _8d;};_6.mobile.loadCompatPattern=/\/themes\/(domButtons|buttons|iphone|android).*\.css$/;_6.mobile.loadCompatCssFiles=function(){var _8f=_6.mobile.getCssPaths();for(var i=0;i<_8f.length;i++){var _90=_8f[i];if(_90.match(_6.mobile.loadCompatPattern)&&_90.indexOf("-compat.css")==-1){var _91=_90.substring(0,_90.length-4)+"-compat.css";_6.mobile.loadCss(_91);}}};_6.mobile.hideAddressBar=function(){};_4.addOnLoad(function(){if(_4.config["mblLoadCompatCssFiles"]!==false){_6.mobile.loadCompatCssFiles();}if(_6.mobile.applyPngFilter){_6.mobile.applyPngFilter();}});}}if(!_4._hasResource["dojox.mobile.app.compat"]){_4._hasResource["dojox.mobile.app.compat"]=true;_4.provide("dojox.mobile.app.compat");_4.extend(_6.mobile.app.AlertDialog,{_doTransition:function(dir){var h=_4.marginBox(this.domNode.firstChild).h;var _92=this.controller.getWindowSize().h;var _93=_92-h;var low=_92;var _94=_4.fx.slideTo({node:this.domNode,duration:400,top:{start:dir<0?_93:low,end:dir<0?low:_93}});var _95=_4[dir<0?"fadeOut":"fadeIn"]({node:this.mask,duration:400});var _96=_4.fx.combine([_94,_95]);var _97=this;_4.connect(_96,"onEnd",this,function(){if(dir<0){_97.domNode.style.display="none";_4.destroy(_97.domNode);_4.destroy(_97.mask);}});_96.play();}});_4.extend(_6.mobile.app.List,{deleteRow:function(){var row=this._selectedRow;_4.style(row,{visibility:"hidden",minHeight:"0px"});_4.removeClass(row,"hold");var _98=_4.contentBox(row).h;_4.animateProperty({node:row,duration:800,properties:{height:{start:_98,end:1},paddingTop:{end:0},paddingBottom:{end:0}},onEnd:this._postDeleteAnim}).play();}});if(_6.mobile.app.ImageView&&!_4.create("canvas").getContext){_4.extend(_6.mobile.app.ImageView,{buildRendering:function(){this.domNode.innerHTML="ImageView widget is not supported on this browser."+"Please try again with a modern browser, e.g. "+"Safari, Chrome or Firefox";this.canvas={};},postCreate:function(){}});}if(_6.mobile.app.ImageThumbView){_4.extend(_6.mobile.app.ImageThumbView,{place:function(_99,x,y){_4.style(_99,{top:y+"px",left:x+"px",visibility:"visible"});}});}}}};});
diff --git a/js/dojo-1.6/dojox/mobile/app/compat.xd.js.uncompressed.js b/js/dojo-1.6/dojox/mobile/app/compat.xd.js.uncompressed.js
new file mode 100644
index 0000000..81822b7
--- /dev/null
+++ b/js/dojo-1.6/dojox/mobile/app/compat.xd.js.uncompressed.js
@@ -0,0 +1,1710 @@
+dojo._xdResourceLoaded(function(dojo, dijit, dojox){
+return {depends: [["provide", "dojo.uacss"],
+["provide", "dijit._base.sniff"],
+["provide", "dojo.fx.Toggler"],
+["provide", "dojo.fx"],
+["provide", "dojox.fx.flip"],
+["provide", "dojox.mobile.compat"],
+["provide", "dojox.mobile.app.compat"]],
+defineResource: function(dojo, dijit, dojox){/*
+ 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
+*/
+
+if(!dojo._hasResource["dojo.uacss"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.uacss"] = true;
+dojo.provide("dojo.uacss");
+
+
+
+(function(){
+ // summary:
+ // Applies pre-set CSS classes to the top-level HTML node, based on:
+ // - browser (ex: dj_ie)
+ // - browser version (ex: dj_ie6)
+ // - box model (ex: dj_contentBox)
+ // - text direction (ex: dijitRtl)
+ //
+ // In addition, browser, browser version, and box model are
+ // combined with an RTL flag when browser text is RTL. ex: dj_ie-rtl.
+
+ var d = dojo,
+ html = d.doc.documentElement,
+ ie = d.isIE,
+ opera = d.isOpera,
+ maj = Math.floor,
+ ff = d.isFF,
+ boxModel = d.boxModel.replace(/-/,''),
+
+ classes = {
+ dj_ie: ie,
+ dj_ie6: maj(ie) == 6,
+ dj_ie7: maj(ie) == 7,
+ dj_ie8: maj(ie) == 8,
+ dj_ie9: maj(ie) == 9,
+ dj_quirks: d.isQuirks,
+ dj_iequirks: ie && d.isQuirks,
+
+ // NOTE: Opera not supported by dijit
+ dj_opera: opera,
+
+ dj_khtml: d.isKhtml,
+
+ dj_webkit: d.isWebKit,
+ dj_safari: d.isSafari,
+ dj_chrome: d.isChrome,
+
+ dj_gecko: d.isMozilla,
+ dj_ff3: maj(ff) == 3
+ }; // no dojo unsupported browsers
+
+ classes["dj_" + boxModel] = true;
+
+ // apply browser, browser version, and box model class names
+ var classStr = "";
+ for(var clz in classes){
+ if(classes[clz]){
+ classStr += clz + " ";
+ }
+ }
+ html.className = d.trim(html.className + " " + classStr);
+
+ // If RTL mode, then add dj_rtl flag plus repeat existing classes with -rtl extension.
+ // We can't run the code below until the <body> tag has loaded (so we can check for dir=rtl).
+ // Unshift() is to run sniff code before the parser.
+ dojo._loaders.unshift(function(){
+ if(!dojo._isBodyLtr()){
+ var rtlClassStr = "dj_rtl dijitRtl " + classStr.replace(/ /g, "-rtl ")
+ html.className = d.trim(html.className + " " + rtlClassStr);
+ }
+ });
+})();
+
+}
+
+if(!dojo._hasResource["dijit._base.sniff"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._base.sniff"] = true;
+dojo.provide("dijit._base.sniff");
+
+
+
+
+// summary:
+// Applies pre-set CSS classes to the top-level HTML node, see
+// `dojo.uacss` for details.
+//
+// Simply doing a require on this module will
+// establish this CSS. Modified version of Morris' CSS hack.
+
+}
+
+if(!dojo._hasResource["dojo.fx.Toggler"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.fx.Toggler"] = true;
+dojo.provide("dojo.fx.Toggler");
+
+
+
+dojo.declare("dojo.fx.Toggler", null, {
+ // summary:
+ // A simple `dojo.Animation` toggler API.
+ //
+ // description:
+ // class constructor for an animation toggler. It accepts a packed
+ // set of arguments about what type of animation to use in each
+ // direction, duration, etc. All available members are mixed into
+ // these animations from the constructor (for example, `node`,
+ // `showDuration`, `hideDuration`).
+ //
+ // example:
+ // | var t = new dojo.fx.Toggler({
+ // | node: "nodeId",
+ // | showDuration: 500,
+ // | // hideDuration will default to "200"
+ // | showFunc: dojo.fx.wipeIn,
+ // | // hideFunc will default to "fadeOut"
+ // | });
+ // | t.show(100); // delay showing for 100ms
+ // | // ...time passes...
+ // | t.hide();
+
+ // node: DomNode
+ // the node to target for the showing and hiding animations
+ node: null,
+
+ // showFunc: Function
+ // The function that returns the `dojo.Animation` to show the node
+ showFunc: dojo.fadeIn,
+
+ // hideFunc: Function
+ // The function that returns the `dojo.Animation` to hide the node
+ hideFunc: dojo.fadeOut,
+
+ // showDuration:
+ // Time in milliseconds to run the show Animation
+ showDuration: 200,
+
+ // hideDuration:
+ // Time in milliseconds to run the hide Animation
+ hideDuration: 200,
+
+ // FIXME: need a policy for where the toggler should "be" the next
+ // time show/hide are called if we're stopped somewhere in the
+ // middle.
+ // FIXME: also would be nice to specify individual showArgs/hideArgs mixed into
+ // each animation individually.
+ // FIXME: also would be nice to have events from the animations exposed/bridged
+
+ /*=====
+ _showArgs: null,
+ _showAnim: null,
+
+ _hideArgs: null,
+ _hideAnim: null,
+
+ _isShowing: false,
+ _isHiding: false,
+ =====*/
+
+ constructor: function(args){
+ var _t = this;
+
+ dojo.mixin(_t, args);
+ _t.node = args.node;
+ _t._showArgs = dojo.mixin({}, args);
+ _t._showArgs.node = _t.node;
+ _t._showArgs.duration = _t.showDuration;
+ _t.showAnim = _t.showFunc(_t._showArgs);
+
+ _t._hideArgs = dojo.mixin({}, args);
+ _t._hideArgs.node = _t.node;
+ _t._hideArgs.duration = _t.hideDuration;
+ _t.hideAnim = _t.hideFunc(_t._hideArgs);
+
+ dojo.connect(_t.showAnim, "beforeBegin", dojo.hitch(_t.hideAnim, "stop", true));
+ dojo.connect(_t.hideAnim, "beforeBegin", dojo.hitch(_t.showAnim, "stop", true));
+ },
+
+ show: function(delay){
+ // summary: Toggle the node to showing
+ // delay: Integer?
+ // Ammount of time to stall playing the show animation
+ return this.showAnim.play(delay || 0);
+ },
+
+ hide: function(delay){
+ // summary: Toggle the node to hidden
+ // delay: Integer?
+ // Ammount of time to stall playing the hide animation
+ return this.hideAnim.play(delay || 0);
+ }
+});
+
+}
+
+if(!dojo._hasResource["dojo.fx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.fx"] = true;
+dojo.provide("dojo.fx");
+
+
+
+
+/*=====
+dojo.fx = {
+ // summary: Effects library on top of Base animations
+};
+=====*/
+(function(){
+
+ var d = dojo,
+ _baseObj = {
+ _fire: function(evt, args){
+ if(this[evt]){
+ this[evt].apply(this, args||[]);
+ }
+ return this;
+ }
+ };
+
+ var _chain = function(animations){
+ this._index = -1;
+ this._animations = animations||[];
+ this._current = this._onAnimateCtx = this._onEndCtx = null;
+
+ this.duration = 0;
+ d.forEach(this._animations, function(a){
+ this.duration += a.duration;
+ if(a.delay){ this.duration += a.delay; }
+ }, this);
+ };
+ d.extend(_chain, {
+ _onAnimate: function(){
+ this._fire("onAnimate", arguments);
+ },
+ _onEnd: function(){
+ d.disconnect(this._onAnimateCtx);
+ d.disconnect(this._onEndCtx);
+ this._onAnimateCtx = this._onEndCtx = null;
+ if(this._index + 1 == this._animations.length){
+ this._fire("onEnd");
+ }else{
+ // switch animations
+ this._current = this._animations[++this._index];
+ this._onAnimateCtx = d.connect(this._current, "onAnimate", this, "_onAnimate");
+ this._onEndCtx = d.connect(this._current, "onEnd", this, "_onEnd");
+ this._current.play(0, true);
+ }
+ },
+ play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){
+ if(!this._current){ this._current = this._animations[this._index = 0]; }
+ if(!gotoStart && this._current.status() == "playing"){ return this; }
+ var beforeBegin = d.connect(this._current, "beforeBegin", this, function(){
+ this._fire("beforeBegin");
+ }),
+ onBegin = d.connect(this._current, "onBegin", this, function(arg){
+ this._fire("onBegin", arguments);
+ }),
+ onPlay = d.connect(this._current, "onPlay", this, function(arg){
+ this._fire("onPlay", arguments);
+ d.disconnect(beforeBegin);
+ d.disconnect(onBegin);
+ d.disconnect(onPlay);
+ });
+ if(this._onAnimateCtx){
+ d.disconnect(this._onAnimateCtx);
+ }
+ this._onAnimateCtx = d.connect(this._current, "onAnimate", this, "_onAnimate");
+ if(this._onEndCtx){
+ d.disconnect(this._onEndCtx);
+ }
+ this._onEndCtx = d.connect(this._current, "onEnd", this, "_onEnd");
+ this._current.play.apply(this._current, arguments);
+ return this;
+ },
+ pause: function(){
+ if(this._current){
+ var e = d.connect(this._current, "onPause", this, function(arg){
+ this._fire("onPause", arguments);
+ d.disconnect(e);
+ });
+ this._current.pause();
+ }
+ return this;
+ },
+ gotoPercent: function(/*Decimal*/percent, /*Boolean?*/ andPlay){
+ this.pause();
+ var offset = this.duration * percent;
+ this._current = null;
+ d.some(this._animations, function(a){
+ if(a.duration <= offset){
+ this._current = a;
+ return true;
+ }
+ offset -= a.duration;
+ return false;
+ });
+ if(this._current){
+ this._current.gotoPercent(offset / this._current.duration, andPlay);
+ }
+ return this;
+ },
+ stop: function(/*boolean?*/ gotoEnd){
+ if(this._current){
+ if(gotoEnd){
+ for(; this._index + 1 < this._animations.length; ++this._index){
+ this._animations[this._index].stop(true);
+ }
+ this._current = this._animations[this._index];
+ }
+ var e = d.connect(this._current, "onStop", this, function(arg){
+ this._fire("onStop", arguments);
+ d.disconnect(e);
+ });
+ this._current.stop();
+ }
+ return this;
+ },
+ status: function(){
+ return this._current ? this._current.status() : "stopped";
+ },
+ destroy: function(){
+ if(this._onAnimateCtx){ d.disconnect(this._onAnimateCtx); }
+ if(this._onEndCtx){ d.disconnect(this._onEndCtx); }
+ }
+ });
+ d.extend(_chain, _baseObj);
+
+ dojo.fx.chain = function(/*dojo.Animation[]*/ animations){
+ // summary:
+ // Chain a list of `dojo.Animation`s to run in sequence
+ //
+ // description:
+ // Return a `dojo.Animation` which will play all passed
+ // `dojo.Animation` instances in sequence, firing its own
+ // synthesized events simulating a single animation. (eg:
+ // onEnd of this animation means the end of the chain,
+ // not the individual animations within)
+ //
+ // example:
+ // Once `node` is faded out, fade in `otherNode`
+ // | dojo.fx.chain([
+ // | dojo.fadeIn({ node:node }),
+ // | dojo.fadeOut({ node:otherNode })
+ // | ]).play();
+ //
+ return new _chain(animations) // dojo.Animation
+ };
+
+ var _combine = function(animations){
+ this._animations = animations||[];
+ this._connects = [];
+ this._finished = 0;
+
+ this.duration = 0;
+ d.forEach(animations, function(a){
+ var duration = a.duration;
+ if(a.delay){ duration += a.delay; }
+ if(this.duration < duration){ this.duration = duration; }
+ this._connects.push(d.connect(a, "onEnd", this, "_onEnd"));
+ }, this);
+
+ this._pseudoAnimation = new d.Animation({curve: [0, 1], duration: this.duration});
+ var self = this;
+ d.forEach(["beforeBegin", "onBegin", "onPlay", "onAnimate", "onPause", "onStop", "onEnd"],
+ function(evt){
+ self._connects.push(d.connect(self._pseudoAnimation, evt,
+ function(){ self._fire(evt, arguments); }
+ ));
+ }
+ );
+ };
+ d.extend(_combine, {
+ _doAction: function(action, args){
+ d.forEach(this._animations, function(a){
+ a[action].apply(a, args);
+ });
+ return this;
+ },
+ _onEnd: function(){
+ if(++this._finished > this._animations.length){
+ this._fire("onEnd");
+ }
+ },
+ _call: function(action, args){
+ var t = this._pseudoAnimation;
+ t[action].apply(t, args);
+ },
+ play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){
+ this._finished = 0;
+ this._doAction("play", arguments);
+ this._call("play", arguments);
+ return this;
+ },
+ pause: function(){
+ this._doAction("pause", arguments);
+ this._call("pause", arguments);
+ return this;
+ },
+ gotoPercent: function(/*Decimal*/percent, /*Boolean?*/ andPlay){
+ var ms = this.duration * percent;
+ d.forEach(this._animations, function(a){
+ a.gotoPercent(a.duration < ms ? 1 : (ms / a.duration), andPlay);
+ });
+ this._call("gotoPercent", arguments);
+ return this;
+ },
+ stop: function(/*boolean?*/ gotoEnd){
+ this._doAction("stop", arguments);
+ this._call("stop", arguments);
+ return this;
+ },
+ status: function(){
+ return this._pseudoAnimation.status();
+ },
+ destroy: function(){
+ d.forEach(this._connects, dojo.disconnect);
+ }
+ });
+ d.extend(_combine, _baseObj);
+
+ dojo.fx.combine = function(/*dojo.Animation[]*/ animations){
+ // summary:
+ // Combine a list of `dojo.Animation`s to run in parallel
+ //
+ // description:
+ // Combine an array of `dojo.Animation`s to run in parallel,
+ // providing a new `dojo.Animation` instance encompasing each
+ // animation, firing standard animation events.
+ //
+ // example:
+ // Fade out `node` while fading in `otherNode` simultaneously
+ // | dojo.fx.combine([
+ // | dojo.fadeIn({ node:node }),
+ // | dojo.fadeOut({ node:otherNode })
+ // | ]).play();
+ //
+ // example:
+ // When the longest animation ends, execute a function:
+ // | var anim = dojo.fx.combine([
+ // | dojo.fadeIn({ node: n, duration:700 }),
+ // | dojo.fadeOut({ node: otherNode, duration: 300 })
+ // | ]);
+ // | dojo.connect(anim, "onEnd", function(){
+ // | // overall animation is done.
+ // | });
+ // | anim.play(); // play the animation
+ //
+ return new _combine(animations); // dojo.Animation
+ };
+
+ dojo.fx.wipeIn = function(/*Object*/ args){
+ // summary:
+ // Expand a node to it's natural height.
+ //
+ // description:
+ // Returns an animation that will expand the
+ // node defined in 'args' object from it's current height to
+ // it's natural height (with no scrollbar).
+ // Node must have no margin/border/padding.
+ //
+ // args: Object
+ // A hash-map of standard `dojo.Animation` constructor properties
+ // (such as easing: node: duration: and so on)
+ //
+ // example:
+ // | dojo.fx.wipeIn({
+ // | node:"someId"
+ // | }).play()
+ var node = args.node = d.byId(args.node), s = node.style, o;
+
+ var anim = d.animateProperty(d.mixin({
+ properties: {
+ height: {
+ // wrapped in functions so we wait till the last second to query (in case value has changed)
+ start: function(){
+ // start at current [computed] height, but use 1px rather than 0
+ // because 0 causes IE to display the whole panel
+ o = s.overflow;
+ s.overflow = "hidden";
+ if(s.visibility == "hidden" || s.display == "none"){
+ s.height = "1px";
+ s.display = "";
+ s.visibility = "";
+ return 1;
+ }else{
+ var height = d.style(node, "height");
+ return Math.max(height, 1);
+ }
+ },
+ end: function(){
+ return node.scrollHeight;
+ }
+ }
+ }
+ }, args));
+
+ d.connect(anim, "onEnd", function(){
+ s.height = "auto";
+ s.overflow = o;
+ });
+
+ return anim; // dojo.Animation
+ };
+
+ dojo.fx.wipeOut = function(/*Object*/ args){
+ // summary:
+ // Shrink a node to nothing and hide it.
+ //
+ // description:
+ // Returns an animation that will shrink node defined in "args"
+ // from it's current height to 1px, and then hide it.
+ //
+ // args: Object
+ // A hash-map of standard `dojo.Animation` constructor properties
+ // (such as easing: node: duration: and so on)
+ //
+ // example:
+ // | dojo.fx.wipeOut({ node:"someId" }).play()
+
+ var node = args.node = d.byId(args.node), s = node.style, o;
+
+ var anim = d.animateProperty(d.mixin({
+ properties: {
+ height: {
+ end: 1 // 0 causes IE to display the whole panel
+ }
+ }
+ }, args));
+
+ d.connect(anim, "beforeBegin", function(){
+ o = s.overflow;
+ s.overflow = "hidden";
+ s.display = "";
+ });
+ d.connect(anim, "onEnd", function(){
+ s.overflow = o;
+ s.height = "auto";
+ s.display = "none";
+ });
+
+ return anim; // dojo.Animation
+ };
+
+ dojo.fx.slideTo = function(/*Object*/ args){
+ // summary:
+ // Slide a node to a new top/left position
+ //
+ // description:
+ // Returns an animation that will slide "node"
+ // defined in args Object from its current position to
+ // the position defined by (args.left, args.top).
+ //
+ // args: Object
+ // A hash-map of standard `dojo.Animation` constructor properties
+ // (such as easing: node: duration: and so on). Special args members
+ // are `top` and `left`, which indicate the new position to slide to.
+ //
+ // example:
+ // | dojo.fx.slideTo({ node: node, left:"40", top:"50", units:"px" }).play()
+
+ var node = args.node = d.byId(args.node),
+ top = null, left = null;
+
+ var init = (function(n){
+ return function(){
+ var cs = d.getComputedStyle(n);
+ var pos = cs.position;
+ top = (pos == 'absolute' ? n.offsetTop : parseInt(cs.top) || 0);
+ left = (pos == 'absolute' ? n.offsetLeft : parseInt(cs.left) || 0);
+ if(pos != 'absolute' && pos != 'relative'){
+ var ret = d.position(n, true);
+ top = ret.y;
+ left = ret.x;
+ n.style.position="absolute";
+ n.style.top=top+"px";
+ n.style.left=left+"px";
+ }
+ };
+ })(node);
+ init();
+
+ var anim = d.animateProperty(d.mixin({
+ properties: {
+ top: args.top || 0,
+ left: args.left || 0
+ }
+ }, args));
+ d.connect(anim, "beforeBegin", anim, init);
+
+ return anim; // dojo.Animation
+ };
+
+})();
+
+}
+
+if(!dojo._hasResource["dojox.fx.flip"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.fx.flip"] = true;
+dojo.provide("dojox.fx.flip");
+
+
+
+
+ dojo.experimental("dojox.fx.flip");
+ // because ShrinkSafe will eat this up:
+ var borderConst = "border",
+ widthConst = "Width",
+ heightConst = "Height",
+ topConst = "Top",
+ rightConst = "Right",
+ leftConst = "Left",
+ bottomConst = "Bottom"
+ ;
+
+ dojox.fx.flip = function(/*Object*/ args){
+ // summary: Animate a node flipping following a specific direction
+ //
+ // description:
+ // Returns an animation that will flip the
+ // node around a central axis:
+ // if args.dir is "left" or "right" --> y axis
+ // if args.dir is "top" or "bottom" --> x axis
+ //
+ // This effect is obtained using a border distorsion applied to a helper node.
+ //
+ // The user can specify three background colors for the helper node:
+ // darkColor: the darkest color reached during the animation
+ // lightColor: the brightest color
+ // endColor: the final backgroundColor for the node
+ //
+ // depth: Float
+ // 0 <= depth <= 1 overrides the computed "depth"
+ // (0: min distorsion, 1: max distorsion)
+ //
+ // whichAnim: String
+ // "first" : the first half animation
+ // "last" : the second one
+ // "both" (default) : both
+ //
+ // axis: String
+ // "center" (default) : the node is flipped around his center
+ // "shortside" : the node is flipped around his "short" (in perspective) side
+ // "longside" : the node is flipped around his "long" (in perspective) side
+ // "cube" : the node flips around the central axis of the cube
+ //
+ // shift: Integer
+ // node translation, perpendicular to the rotation axis
+ //
+ // example:
+ // | var anim = dojox.fx.flip({
+ // | node: dojo.byId("nodeId"),
+ // | dir: "top",
+ // | darkColor: "#555555",
+ // | lightColor: "#dddddd",
+ // | endColor: "#666666",
+ // | depth: .5,
+ // | shift: 50,
+ // | duration:300
+ // | });
+
+ var helperNode = dojo.create("div"),
+ node = args.node = dojo.byId(args.node),
+ s = node.style,
+ dims = null,
+ hs = null,
+ pn = null,
+ lightColor = args.lightColor || "#dddddd",
+ darkColor = args.darkColor || "#555555",
+ bgColor = dojo.style(node, "backgroundColor"),
+ endColor = args.endColor || bgColor,
+ staticProps = {},
+ anims = [],
+ duration = args.duration ? args.duration / 2 : 250,
+ dir = args.dir || "left",
+ pConst = .9,
+ transparentColor = "transparent",
+ whichAnim = args.whichAnim,
+ axis = args.axis || "center",
+ depth = args.depth
+ ;
+ // IE6 workaround: IE6 doesn't support transparent borders
+ var convertColor = function(color){
+ return ((new dojo.Color(color)).toHex() === "#000000") ? "#000001" : color;
+ };
+
+ if(dojo.isIE < 7){
+ endColor = convertColor(endColor);
+ lightColor = convertColor(lightColor);
+ darkColor = convertColor(darkColor);
+ bgColor = convertColor(bgColor);
+ transparentColor = "black";
+ helperNode.style.filter = "chroma(color='#000000')";
+ }
+
+ var init = (function(n){
+ return function(){
+ var ret = dojo.coords(n, true);
+ dims = {
+ top: ret.y,
+ left: ret.x,
+ width: ret.w,
+ height: ret.h
+ };
+ }
+ })(node);
+ init();
+ // helperNode initialization
+ hs = {
+ position: "absolute",
+ top: dims["top"] + "px",
+ left: dims["left"] + "px",
+ height: "0",
+ width: "0",
+ zIndex: args.zIndex || (s.zIndex || 0),
+ border: "0 solid " + transparentColor,
+ fontSize: "0",
+ visibility: "hidden"
+ };
+ var props = [ {},
+ {
+ top: dims["top"],
+ left: dims["left"]
+ }
+ ];
+ var dynProperties = {
+ left: [leftConst, rightConst, topConst, bottomConst, widthConst, heightConst, "end" + heightConst + "Min", leftConst, "end" + heightConst + "Max"],
+ right: [rightConst, leftConst, topConst, bottomConst, widthConst, heightConst, "end" + heightConst + "Min", leftConst, "end" + heightConst + "Max"],
+ top: [topConst, bottomConst, leftConst, rightConst, heightConst, widthConst, "end" + widthConst + "Min", topConst, "end" + widthConst + "Max"],
+ bottom: [bottomConst, topConst, leftConst, rightConst, heightConst, widthConst, "end" + widthConst + "Min", topConst, "end" + widthConst + "Max"]
+ };
+ // property names
+ pn = dynProperties[dir];
+
+ // .4 <= pConst <= .9
+ if(typeof depth != "undefined"){
+ depth = Math.max(0, Math.min(1, depth)) / 2;
+ pConst = .4 + (.5 - depth);
+ }else{
+ pConst = Math.min(.9, Math.max(.4, dims[pn[5].toLowerCase()] / dims[pn[4].toLowerCase()]));
+ }
+ var p0 = props[0];
+ for(var i = 4; i < 6; i++){
+ if(axis == "center" || axis == "cube"){ // find a better name for "cube"
+ dims["end" + pn[i] + "Min"] = dims[pn[i].toLowerCase()] * pConst;
+ dims["end" + pn[i] + "Max"] = dims[pn[i].toLowerCase()] / pConst;
+ }else if(axis == "shortside"){
+ dims["end" + pn[i] + "Min"] = dims[pn[i].toLowerCase()];
+ dims["end" + pn[i] + "Max"] = dims[pn[i].toLowerCase()] / pConst;
+ }else if(axis == "longside"){
+ dims["end" + pn[i] + "Min"] = dims[pn[i].toLowerCase()] * pConst;
+ dims["end" + pn[i] + "Max"] = dims[pn[i].toLowerCase()];
+ }
+ }
+ if(axis == "center"){
+ p0[pn[2].toLowerCase()] = dims[pn[2].toLowerCase()] - (dims[pn[8]] - dims[pn[6]]) / 4;
+ }else if(axis == "shortside"){
+ p0[pn[2].toLowerCase()] = dims[pn[2].toLowerCase()] - (dims[pn[8]] - dims[pn[6]]) / 2;
+ }
+
+ staticProps[pn[5].toLowerCase()] = dims[pn[5].toLowerCase()] + "px";
+ staticProps[pn[4].toLowerCase()] = "0";
+ staticProps[borderConst + pn[1] + widthConst] = dims[pn[4].toLowerCase()] + "px";
+ staticProps[borderConst + pn[1] + "Color"] = bgColor;
+
+ p0[borderConst + pn[1] + widthConst] = 0;
+ p0[borderConst + pn[1] + "Color"] = darkColor;
+ p0[borderConst + pn[2] + widthConst] = p0[borderConst + pn[3] + widthConst] = axis != "cube"
+ ? (dims["end" + pn[5] + "Max"] - dims["end" + pn[5] + "Min"]) / 2
+ : dims[pn[6]] / 2
+ ;
+ p0[pn[7].toLowerCase()] = dims[pn[7].toLowerCase()] + dims[pn[4].toLowerCase()] / 2 + (args.shift || 0);
+ p0[pn[5].toLowerCase()] = dims[pn[6]];
+
+ var p1 = props[1];
+ p1[borderConst + pn[0] + "Color"] = { start: lightColor, end: endColor };
+ p1[borderConst + pn[0] + widthConst] = dims[pn[4].toLowerCase()];
+ p1[borderConst + pn[2] + widthConst] = 0;
+ p1[borderConst + pn[3] + widthConst] = 0;
+ p1[pn[5].toLowerCase()] = { start: dims[pn[6]], end: dims[pn[5].toLowerCase()] };
+
+ dojo.mixin(hs, staticProps);
+ dojo.style(helperNode, hs);
+ dojo.body().appendChild(helperNode);
+
+ var finalize = function(){
+// helperNode.parentNode.removeChild(helperNode);
+ dojo.destroy(helperNode);
+ // fixes a flicker when the animation ends
+ s.backgroundColor = endColor;
+ s.visibility = "visible";
+ };
+ if(whichAnim == "last"){
+ for(i in p0){
+ p0[i] = { start: p0[i] };
+ }
+ p0[borderConst + pn[1] + "Color"] = { start: darkColor, end: endColor };
+ p1 = p0;
+ }
+ if(!whichAnim || whichAnim == "first"){
+ anims.push(dojo.animateProperty({
+ node: helperNode,
+ duration: duration,
+ properties: p0
+ }));
+ }
+ if(!whichAnim || whichAnim == "last"){
+ anims.push(dojo.animateProperty({
+ node: helperNode,
+ duration: duration,
+ properties: p1,
+ onEnd: finalize
+ }));
+ }
+
+ // hide the original node
+ dojo.connect(anims[0], "play", function(){
+ helperNode.style.visibility = "visible";
+ s.visibility = "hidden";
+ });
+
+ return dojo.fx.chain(anims); // dojo.Animation
+
+ }
+
+ dojox.fx.flipCube = function(/*Object*/ args){
+ // summary: An extension to `dojox.fx.flip` providing a more 3d-like rotation
+ //
+ // description:
+ // An extension to `dojox.fx.flip` providing a more 3d-like rotation.
+ // Behaves the same as `dojox.fx.flip`, using the same attributes and
+ // other standard `dojo.Animation` properties.
+ //
+ // example:
+ // See `dojox.fx.flip`
+ var anims = [],
+ mb = dojo.marginBox(args.node),
+ shiftX = mb.w / 2,
+ shiftY = mb.h / 2,
+ dims = {
+ top: {
+ pName: "height",
+ args:[
+ {
+ whichAnim: "first",
+ dir: "top",
+ shift: -shiftY
+ },
+ {
+ whichAnim: "last",
+ dir: "bottom",
+ shift: shiftY
+ }
+ ]
+ },
+ right: {
+ pName: "width",
+ args:[
+ {
+ whichAnim: "first",
+ dir: "right",
+ shift: shiftX
+ },
+ {
+ whichAnim: "last",
+ dir: "left",
+ shift: -shiftX
+ }
+ ]
+ },
+ bottom: {
+ pName: "height",
+ args:[
+ {
+ whichAnim: "first",
+ dir: "bottom",
+ shift: shiftY
+ },
+ {
+ whichAnim: "last",
+ dir: "top",
+ shift: -shiftY
+ }
+ ]
+ },
+ left: {
+ pName: "width",
+ args:[
+ {
+ whichAnim: "first",
+ dir: "left",
+ shift: -shiftX
+ },
+ {
+ whichAnim: "last",
+ dir: "right",
+ shift: shiftX
+ }
+ ]
+ }
+ }
+ ;
+ var d = dims[args.dir || "left"],
+ p = d.args
+ ;
+ args.duration = args.duration ? args.duration * 2 : 500;
+ args.depth = .8;
+ args.axis = "cube";
+ for(var i = p.length - 1; i >= 0; i--){
+ dojo.mixin(args, p[i]);
+ anims.push(dojox.fx.flip(args));
+ }
+ return dojo.fx.combine(anims);
+ };
+
+ dojox.fx.flipPage = function(/*Object*/ args){
+ // summary: An extension to `dojox.fx.flip` providing a page flip like animation.
+ //
+ // description:
+ // An extension to `dojox.fx.flip` providing a page flip effect.
+ // Behaves the same as `dojox.fx.flip`, using the same attributes and
+ // other standard `dojo.Animation` properties.
+ //
+ // example:
+ // See `dojox.fx.flip`
+ var n = args.node,
+ coords = dojo.coords(n, true),
+ x = coords.x,
+ y = coords.y,
+ w = coords.w,
+ h = coords.h,
+ bgColor = dojo.style(n, "backgroundColor"),
+ lightColor = args.lightColor || "#dddddd",
+ darkColor = args.darkColor,
+ helperNode = dojo.create("div"),
+ anims = [],
+ hn = [],
+ dir = args.dir || "right",
+ pn = {
+ left: ["left", "right", "x", "w"],
+ top: ["top", "bottom", "y", "h"],
+ right: ["left", "left", "x", "w"],
+ bottom: ["top", "top", "y", "h"]
+ },
+ shiftMultiplier = {
+ right: [1, -1],
+ left: [-1, 1],
+ top: [-1, 1],
+ bottom: [1, -1]
+ }
+ ;
+ dojo.style(helperNode, {
+ position: "absolute",
+ width : w + "px",
+ height : h + "px",
+ top : y + "px",
+ left : x + "px",
+ visibility: "hidden"
+ });
+ var hs = [];
+ for(var i = 0; i < 2; i++){
+ var r = i % 2,
+ d = r ? pn[dir][1] : dir,
+ wa = r ? "last" : "first",
+ endColor = r ? bgColor : lightColor,
+ startColor = r ? endColor : args.startColor || n.style.backgroundColor
+ ;
+ hn[i] = dojo.clone(helperNode);
+ var finalize = function(x){
+ return function(){
+ dojo.destroy(hn[x]);
+ }
+ }(i)
+ ;
+ dojo.body().appendChild(hn[i]);
+ hs[i] = {
+ backgroundColor: r ? startColor : bgColor
+ };
+
+ hs[i][pn[dir][0]] = coords[pn[dir][2]] + shiftMultiplier[dir][0] * i * coords[pn[dir][3]] + "px";
+ dojo.style(hn[i], hs[i]);
+ anims.push(dojox.fx.flip({
+ node: hn[i],
+ dir: d,
+ axis: "shortside",
+ depth: args.depth,
+ duration: args.duration / 2,
+ shift: shiftMultiplier[dir][i] * coords[pn[dir][3]] / 2,
+ darkColor: darkColor,
+ lightColor: lightColor,
+ whichAnim: wa,
+ endColor: endColor
+ }));
+ dojo.connect(anims[i], "onEnd", finalize);
+ }
+ return dojo.fx.chain(anims);
+ };
+
+
+ dojox.fx.flipGrid = function(/*Object*/ args){
+ // summary: An extension to `dojox.fx.flip` providing a decomposition in rows * cols flipping elements
+ //
+ // description:
+ // An extension to `dojox.fx.flip` providing a page flip effect.
+ // Behaves the same as `dojox.fx.flip`, using the same attributes and
+ // other standard `dojo.Animation` properties and
+ //
+ // cols: Integer columns
+ // rows: Integer rows
+ //
+ // duration: the single flip duration
+ //
+ // example:
+ // See `dojox.fx.flip`
+ var rows = args.rows || 4,
+ cols = args.cols || 4,
+ anims = [],
+ helperNode = dojo.create("div"),
+ n = args.node,
+ coords = dojo.coords(n, true),
+ x = coords.x,
+ y = coords.y,
+ nw = coords.w,
+ nh = coords.h,
+ w = coords.w / cols,
+ h = coords.h / rows,
+ cAnims = []
+ ;
+ dojo.style(helperNode, {
+ position: "absolute",
+ width: w + "px",
+ height: h + "px",
+ backgroundColor: dojo.style(n, "backgroundColor")
+ });
+ for(var i = 0; i < rows; i++){
+ var r = i % 2,
+ d = r ? "right" : "left",
+ signum = r ? 1 : -1
+ ;
+ // cloning
+ var cn = dojo.clone(n);
+ dojo.style(cn, {
+ position: "absolute",
+ width: nw + "px",
+ height: nh + "px",
+ top: y + "px",
+ left: x + "px",
+ clip: "rect(" + i * h + "px," + nw + "px," + nh + "px,0)"
+ });
+ dojo.body().appendChild(cn);
+ anims[i] = [];
+ for(var j = 0; j < cols; j++){
+ var hn = dojo.clone(helperNode),
+ l = r ? j : cols - (j + 1)
+ ;
+ var adjustClip = function(xn, yCounter, xCounter){
+ return function(){
+ if(!(yCounter % 2)){
+ dojo.style(xn, {
+ clip: "rect(" + yCounter * h + "px," + (nw - (xCounter + 1) * w ) + "px," + ((yCounter + 1) * h) + "px,0px)"
+ });
+ }else{
+ dojo.style(xn, {
+ clip: "rect(" + yCounter * h + "px," + nw + "px," + ((yCounter + 1) * h) + "px," + ((xCounter + 1) * w) + "px)"
+ });
+ }
+ }
+ }(cn, i, j);
+ dojo.body().appendChild(hn);
+ dojo.style(hn, {
+ left: x + l * w + "px",
+ top: y + i * h + "px",
+ visibility: "hidden"
+ });
+ var a = dojox.fx.flipPage({
+ node: hn,
+ dir: d,
+ duration: args.duration || 900,
+ shift: signum * w/2,
+ depth: .2,
+ darkColor: args.darkColor,
+ lightColor: args.lightColor,
+ startColor: args.startColor || args.node.style.backgroundColor
+ }),
+ removeHelper = function(xn){
+ return function(){
+ dojo.destroy(xn);
+ }
+ }(hn)
+ ;
+ dojo.connect(a, "play", this, adjustClip);
+ dojo.connect(a, "play", this, removeHelper);
+ anims[i].push(a);
+ }
+ cAnims.push(dojo.fx.chain(anims[i]));
+
+ }
+ dojo.connect(cAnims[0], "play", function(){
+ dojo.style(n, {visibility: "hidden"});
+ });
+ return dojo.fx.combine(cAnims);
+ };
+
+}
+
+if(!dojo._hasResource["dojox.mobile.compat"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.mobile.compat"] = true;
+dojo.provide("dojox.mobile.compat");
+
+
+
+
+
+// summary:
+// CSS3 compatibility module
+// description:
+// This module provides support for some of the CSS3 features to dojox.mobile
+// for non-CSS3 browsers, such as IE or Firefox.
+// If you load this module, it directly replaces some of the methods of
+// dojox.mobile instead of subclassing. This way, html pages remains the same
+// regardless of whether this compatibility module is used or not.
+// Recommended usage is as follows. the code below loads dojox.mobile.compat
+// only when isWebKit is true.
+//
+// dojo.require("dojox.mobile");
+//
+//
+// This module also loads compatibility CSS files, which has -compat.css
+// suffix. You can use either the <link> tag or @import to load theme
+// CSS files. Then, this module searches for the loaded CSS files and loads
+// compatibility CSS files. For example, if you load iphone.css in a page,
+// this module automatically loads iphone-compat.css.
+// If you explicitly load iphone-compat.css with <link> or @import,
+// this module will not load the already loaded file.
+
+if(!dojo.isWebKit){
+
+dojo.extend(dojox.mobile.View, {
+ _doTransition: function(fromNode, toNode, transition, dir){
+ var anim;
+ this.wakeUp(toNode);
+ if(!transition || transition == "none"){
+ toNode.style.display = "";
+ fromNode.style.display = "none";
+ toNode.style.left = "0px";
+ this.invokeCallback();
+ }else if(transition == "slide"){
+ var w = fromNode.offsetWidth;
+ var s1 = dojo.fx.slideTo({
+ node: fromNode,
+ duration: 400,
+ left: -w*dir,
+ top: fromNode.offsetTop
+ });
+ var s2 = dojo.fx.slideTo({
+ node: toNode,
+ duration: 400,
+ left: 0
+ });
+ toNode.style.position = "absolute";
+ toNode.style.left = w*dir + "px";
+ toNode.style.display = "";
+ anim = dojo.fx.combine([s1,s2]);
+ dojo.connect(anim, "onEnd", this, function(){
+ fromNode.style.display = "none";
+ toNode.style.position = "relative";
+ this.invokeCallback();
+ });
+ anim.play();
+ }else if(transition == "flip"){
+ anim = dojox.fx.flip({
+ node: fromNode,
+ dir: "right",
+ depth: 0.5,
+ duration: 400
+ });
+ toNode.style.position = "absolute";
+ toNode.style.left = "0px";
+ dojo.connect(anim, "onEnd", this, function(){
+ fromNode.style.display = "none";
+ toNode.style.position = "relative";
+ toNode.style.display = "";
+ this.invokeCallback();
+ });
+ anim.play();
+ }else if(transition == "fade"){
+ anim = dojo.fx.chain([
+ dojo.fadeOut({
+ node: fromNode,
+ duration: 600
+ }),
+ dojo.fadeIn({
+ node: toNode,
+ duration: 600
+ })
+ ]);
+ toNode.style.position = "absolute";
+ toNode.style.left = "0px";
+ toNode.style.display = "";
+ dojo.style(toNode, "opacity", 0);
+ dojo.connect(anim, "onEnd", this, function(){
+ fromNode.style.display = "none";
+ toNode.style.position = "relative";
+ dojo.style(fromNode, "opacity", 1);
+ this.invokeCallback();
+ });
+ anim.play();
+ }
+ },
+
+ wakeUp: function(node){
+ // summary:
+ // Function to force IE to redraw a node since its layout code tends to misrender
+ // in partial draws.
+ // node:
+ // The node to forcibly redraw.
+ // tags:
+ // public
+ if(dojo.isIE && !node._wokeup){
+ node._wokeup = true;
+ var disp = node.style.display;
+ node.style.display = "";
+ var nodes = node.getElementsByTagName("*");
+ for(var i = 0, len = nodes.length; i < len; i++){
+ var val = nodes[i].style.display;
+ nodes[i].style.display = "none";
+ nodes[i].style.display = "";
+ nodes[i].style.display = val;
+ }
+ node.style.display = disp;
+ }
+ }
+});
+
+dojo.extend(dojox.mobile.Switch, {
+ buildRendering: function(){
+ // summary:
+ // Function to simulate the mobile device style switches on
+ // browsers such as IE and FireFox.
+ // tags:
+ // protected
+ this.domNode = this.srcNodeRef || dojo.doc.createElement("DIV");
+ this.domNode.className = "mblSwitch";
+ this.domNode.innerHTML =
+ '<div class="mblSwitchInner">'
+ + '<div class="mblSwitchBg mblSwitchBgLeft">'
+ + '<div class="mblSwitchCorner mblSwitchCorner1T"></div>'
+ + '<div class="mblSwitchCorner mblSwitchCorner2T"></div>'
+ + '<div class="mblSwitchCorner mblSwitchCorner3T"></div>'
+ + '<div class="mblSwitchText mblSwitchTextLeft">'+this.leftLabel+'</div>'
+ + '<div class="mblSwitchCorner mblSwitchCorner1B"></div>'
+ + '<div class="mblSwitchCorner mblSwitchCorner2B"></div>'
+ + '<div class="mblSwitchCorner mblSwitchCorner3B"></div>'
+ + '</div>'
+ + '<div class="mblSwitchBg mblSwitchBgRight">'
+ + '<div class="mblSwitchCorner mblSwitchCorner1T"></div>'
+ + '<div class="mblSwitchCorner mblSwitchCorner2T"></div>'
+ + '<div class="mblSwitchCorner mblSwitchCorner3T"></div>'
+ + '<div class="mblSwitchText mblSwitchTextRight">'+this.rightLabel+'</div>'
+ + '<div class="mblSwitchCorner mblSwitchCorner1B"></div>'
+ + '<div class="mblSwitchCorner mblSwitchCorner2B"></div>'
+ + '<div class="mblSwitchCorner mblSwitchCorner3B"></div>'
+ + '</div>'
+ + '<div class="mblSwitchKnobContainer">'
+ + '<div class="mblSwitchCorner mblSwitchCorner1T"></div>'
+ + '<div class="mblSwitchCorner mblSwitchCorner2T"></div>'
+ + '<div class="mblSwitchCorner mblSwitchCorner3T"></div>'
+ + '<div class="mblSwitchKnob"></div>'
+ + '<div class="mblSwitchCorner mblSwitchCorner1B"></div>'
+ + '<div class="mblSwitchCorner mblSwitchCorner2B"></div>'
+ + '<div class="mblSwitchCorner mblSwitchCorner3B"></div>'
+ + '</div>'
+ + '</div>';
+ var n = this.inner = this.domNode.firstChild;
+ this.left = n.childNodes[0];
+ this.right = n.childNodes[1];
+ this.knob = n.childNodes[2];
+
+ dojo.addClass(this.domNode, (this.value == "on") ? "mblSwitchOn" : "mblSwitchOff");
+ this[this.value == "off" ? "left" : "right"].style.display = "none";
+ },
+
+ _changeState: function(/*String*/state){
+ // summary:
+ // Function to toggle the switch state on the switch
+ // state:
+ // Thhe state to toggle, switch 'on' or 'off'
+ // tags:
+ // private
+ if(!this.inner.parentNode || !this.inner.parentNode.tagName){
+ dojo.addClass(this.domNode, (state == "on") ? "mblSwitchOn" : "mblSwitchOff");
+ return;
+ }
+ var pos;
+ if(this.inner.offsetLeft == 0){ // currently ON
+ if(state == "on"){ return; }
+ pos = -53;
+ }else{ // currently OFF
+ if(state == "off"){ return; }
+ pos = 0;
+ }
+
+ var a = dojo.fx.slideTo({
+ node: this.inner,
+ duration: 500,
+ left: pos
+ });
+ var _this = this;
+ dojo.connect(a, "onEnd", function(){
+ _this[state == "off" ? "left" : "right"].style.display = "none";
+ });
+ a.play();
+ }
+});
+
+if(dojo.isIE || dojo.isBB){
+
+dojo.extend(dojox.mobile.RoundRect, {
+ buildRendering: function(){
+ // summary:
+ // Function to simulate the borderRadius appearance on IE, since
+ // IE does not support this CSS style.
+ // tags:
+ // protected
+ dojox.mobile.createRoundRect(this);
+ this.domNode.className = "mblRoundRect";
+ }
+});
+
+dojox.mobile.RoundRectList._addChild = dojox.mobile.RoundRectList.prototype.addChild;
+dojo.extend(dojox.mobile.RoundRectList, {
+ buildRendering: function(){
+ // summary:
+ // Function to simulate the borderRadius appearance on IE, since
+ // IE does not support this CSS style.
+ // tags:
+ // protected
+ dojox.mobile.createRoundRect(this, true);
+ this.domNode.className = "mblRoundRectList";
+ },
+
+ postCreate: function(){
+ this.redrawBorders();
+ },
+
+ addChild: function(widget){
+ dojox.mobile.RoundRectList._addChild.apply(this, arguments);
+ this.redrawBorders();
+ if(dojox.mobile.applyPngFilter){
+ dojox.mobile.applyPngFilter(widget.domNode);
+ }
+ },
+
+ redrawBorders: function(){
+ // summary:
+ // Function to adjust the creation of RoundRectLists on IE.
+ // Removed undesired styles.
+ // tags:
+ // public
+
+ // Remove a border of the last ListItem.
+ // This is for browsers that do not support the last-child CSS pseudo-class.
+
+ var lastChildFound = false;
+ for(var i = this.containerNode.childNodes.length - 1; i >= 0; i--){
+ var c = this.containerNode.childNodes[i];
+ if(c.tagName == "LI"){
+ c.style.borderBottomStyle = lastChildFound ? "solid" : "none";
+ lastChildFound = true;
+ }
+ }
+ }
+});
+
+dojo.extend(dojox.mobile.EdgeToEdgeList, {
+ buildRendering: function(){
+ this.domNode = this.containerNode = this.srcNodeRef || dojo.doc.createElement("UL");
+ this.domNode.className = "mblEdgeToEdgeList";
+ }
+});
+
+if(dojox.mobile.IconContainer){
+
+dojox.mobile.IconContainer._addChild = dojox.mobile.IconContainer.prototype.addChild;
+dojo.extend(dojox.mobile.IconContainer, {
+ addChild: function(widget){
+ dojox.mobile.IconContainer._addChild.apply(this, arguments);
+ if(dojox.mobile.applyPngFilter){
+ dojox.mobile.applyPngFilter(widget.domNode);
+ }
+ }
+});
+
+} // if(dojox.mobile.IconContainer)
+
+dojo.mixin(dojox.mobile, {
+ createRoundRect: function(_this, isList){
+ // summary:
+ // Function to adjust the creation of rounded rectangles on IE.
+ // Deals with IE's lack of borderRadius support
+ // tags:
+ // public
+ var i;
+ _this.domNode = dojo.doc.createElement("DIV");
+ _this.domNode.style.padding = "0px";
+ _this.domNode.style.backgroundColor = "transparent";
+ _this.domNode.style.borderStyle = "none";
+ _this.containerNode = dojo.doc.createElement(isList?"UL":"DIV");
+ _this.containerNode.className = "mblRoundRectContainer";
+ if(_this.srcNodeRef){
+ _this.srcNodeRef.parentNode.replaceChild(_this.domNode, _this.srcNodeRef);
+ for(i = 0, len = _this.srcNodeRef.childNodes.length; i < len; i++){
+ _this.containerNode.appendChild(_this.srcNodeRef.removeChild(_this.srcNodeRef.firstChild));
+ }
+ _this.srcNodeRef = null;
+ }
+ _this.domNode.appendChild(_this.containerNode);
+
+ for(i = 0; i <= 5; i++){
+ var top = dojo.create("DIV");
+ top.className = "mblRoundCorner mblRoundCorner"+i+"T";
+ _this.domNode.insertBefore(top, _this.containerNode);
+
+ var bottom = dojo.create("DIV");
+ bottom.className = "mblRoundCorner mblRoundCorner"+i+"B";
+ _this.domNode.appendChild(bottom);
+ }
+ }
+});
+
+if(dojox.mobile.ScrollableView){
+
+dojo.extend(dojox.mobile.ScrollableView, {
+ postCreate: function(){
+ // On IE, margin-top of the first child does not seem to be effective,
+ // probably because padding-top is specified for containerNode
+ // to make room for a fixed header. This dummy node is a workaround for that.
+ var dummy = dojo.create("DIV", {className:"mblDummyForIE", innerHTML:"&nbsp;"}, this.containerNode, "first");
+ dojo.style(dummy, {
+ position: "relative",
+ marginBottom: "-2px",
+ fontSize: "1px"
+ });
+ }
+});
+
+} // if(dojox.mobile.ScrollableView)
+
+} // if(dojo.isIE)
+
+if(dojo.isIE <= 6){
+ dojox.mobile.applyPngFilter = function(root){
+ root = root || dojo.body();
+ var nodes = root.getElementsByTagName("IMG");
+ var blank = dojo.moduleUrl("dojo", "resources/blank.gif");
+ for(var i = 0, len = nodes.length; i < len; i++){
+ var img = nodes[i];
+ var w = img.offsetWidth;
+ var h = img.offsetHeight;
+ if(w === 0 || h === 0){
+ // The reason why the image has no width/height may be because
+ // display is "none". If that is the case, let's change the
+ // display to "" temporarily and see if the image returns them.
+ if(dojo.style(img, "display") != "none"){ continue; }
+ img.style.display = "";
+ w = img.offsetWidth;
+ h = img.offsetHeight;
+ img.style.display = "none";
+ if(w === 0 || h === 0){ continue; }
+ }
+ var src = img.src;
+ if(src.indexOf("resources/blank.gif") != -1){ continue; }
+ img.src = blank;
+ img.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + src+"')";
+ img.style.width = w + "px";
+ img.style.height = h + "px";
+ }
+ };
+} // if(dojo.isIE <= 6)
+
+dojox.mobile.loadCss = function(/*String|Array*/files){
+ // summary:
+ // Function to load and register CSS files with the page
+ // files: String|Array
+ // The CSS files to load and register with the page.
+ // tags:
+ // private
+ if(!dojo.global._loadedCss){
+ var obj = {};
+ dojo.forEach(dojox.mobile.getCssPaths(), function(path){
+ obj[path] = true;
+ });
+ dojo.global._loadedCss = obj;
+ }
+ if(!dojo.isArray(files)){ files = [files]; }
+ for(var i = 0; i < files.length; i++){
+ var file = files[i];
+ if(!dojo.global._loadedCss[file]){
+ dojo.global._loadedCss[file] = true;
+ if(dojo.doc.createStyleSheet){
+ // for some reason, IE hangs when you try to load
+ // multiple css files almost at once.
+ setTimeout(function(file){
+ return function(){
+ dojo.doc.createStyleSheet(file);
+ };
+ }(file), 0);
+ }else{
+ var link = dojo.doc.createElement("link");
+ link.href = file;
+ link.type = "text/css";
+ link.rel = "stylesheet";
+ var head = dojo.doc.getElementsByTagName('head')[0];
+ head.appendChild(link);
+ }
+ }
+ }
+};
+
+dojox.mobile.getCssPaths = function(){
+ var paths = [];
+ var i, j;
+
+ // find @import
+ var s = dojo.doc.styleSheets;
+ for(i = 0; i < s.length; i++){
+ var r = s[i].cssRules || s[i].imports;
+ if(!r){ continue; }
+ for(j = 0; j < r.length; j++){
+ if(r[j].href){
+ paths.push(r[j].href);
+ }
+ }
+ }
+
+ // find <link>
+ var elems = dojo.doc.getElementsByTagName("link");
+ for(i = 0, len = elems.length; i < len; i++){
+ if(elems[i].href){
+ paths.push(elems[i].href);
+ }
+ }
+ return paths;
+};
+
+dojox.mobile.loadCompatPattern = /\/themes\/(domButtons|buttons|iphone|android).*\.css$/;
+
+dojox.mobile.loadCompatCssFiles = function(){
+ // summary:
+ // Function to perform page-level adjustments on browsers such as
+ // IE and firefox. It loads compat specific css files into the
+ // page header.
+ var paths = dojox.mobile.getCssPaths();
+ for(var i = 0; i < paths.length; i++){
+ var href = paths[i];
+ if(href.match(dojox.mobile.loadCompatPattern) && href.indexOf("-compat.css") == -1){
+ var compatCss = href.substring(0, href.length-4)+"-compat.css";
+ dojox.mobile.loadCss(compatCss);
+ }
+ }
+};
+
+dojox.mobile.hideAddressBar = function(){
+ // nop
+};
+
+dojo.addOnLoad(function(){
+ if(dojo.config["mblLoadCompatCssFiles"] !== false){
+ dojox.mobile.loadCompatCssFiles();
+ }
+ if(dojox.mobile.applyPngFilter){
+ dojox.mobile.applyPngFilter();
+ }
+});
+
+} // end of if(!dojo.isWebKit){
+
+}
+
+if(!dojo._hasResource["dojox.mobile.app.compat"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.mobile.app.compat"] = true;
+dojo.provide("dojox.mobile.app.compat");
+
+
+// summary:
+// CSS3 compatibility module for apps
+// description:
+// This module provides support for some of the CSS3 features to djMobile
+// for non-CSS3 browsers, such as IE or Firefox.
+// If you load this module, it directly replaces some of the methods of
+// djMobile instead of subclassing. This way, html pages remains the same
+// regardless of whether this compatibility module is used or not.
+// Recommended usage is as follows. the code below loads dojox.mobile.compat
+// only when isWebKit is true.
+//
+// dojo.require("dojox.mobile");
+// dojo.requireIf(!dojo.isWebKit, "dojox.mobile.appCompat");
+
+dojo.extend(dojox.mobile.app.AlertDialog, {
+ _doTransition: function(dir){
+ console.log("in _doTransition and this = ", this);
+
+ var h = dojo.marginBox(this.domNode.firstChild).h;
+
+ var bodyHeight = this.controller.getWindowSize().h;
+
+ var high = bodyHeight - h;
+ var low = bodyHeight;
+
+ var anim1 = dojo.fx.slideTo({
+ node: this.domNode,
+ duration: 400,
+ top: {start: dir < 0 ? high : low, end: dir < 0 ? low: high}
+ });
+
+ var anim2 = dojo[dir < 0 ? "fadeOut" : "fadeIn"]({
+ node: this.mask,
+ duration: 400
+ });
+
+ var anim = dojo.fx.combine([anim1, anim2]);
+
+ var _this = this;
+
+ dojo.connect(anim, "onEnd", this, function(){
+ if(dir < 0){
+ _this.domNode.style.display = "none";
+ dojo.destroy(_this.domNode);
+ dojo.destroy(_this.mask);
+ }
+ });
+ anim.play();
+ }
+});
+
+dojo.extend(dojox.mobile.app.List, {
+ deleteRow: function(){
+ console.log("deleteRow in compat mode", row);
+
+ var row = this._selectedRow;
+ // First make the row invisible
+ // Put it back where it came from
+ dojo.style(row, {
+ visibility: "hidden",
+ minHeight: "0px"
+ });
+ dojo.removeClass(row, "hold");
+
+
+ // Animate reducing it's height to zero, then delete the data from the
+ // array
+ var height = dojo.contentBox(row).h;
+ dojo.animateProperty({
+ node: row,
+ duration: 800,
+ properties: {
+ height: {start: height, end: 1},
+ paddingTop: {end: 0},
+ paddingBottom: {end: 0}
+ },
+ onEnd: this._postDeleteAnim
+ }).play();
+ }
+});
+
+if(dojox.mobile.app.ImageView && !dojo.create("canvas").getContext){
+ dojo.extend(dojox.mobile.app.ImageView, {
+ buildRendering: function(){
+ this.domNode.innerHTML =
+ "ImageView widget is not supported on this browser."
+ + "Please try again with a modern browser, e.g. "
+ + "Safari, Chrome or Firefox";
+ this.canvas = {};
+ },
+
+ postCreate: function(){}
+ });
+}
+
+if(dojox.mobile.app.ImageThumbView){
+ dojo.extend(dojox.mobile.app.ImageThumbView, {
+ place: function(node, x, y){
+ dojo.style(node, {
+ top: y + "px",
+ left: x + "px",
+ visibility: "visible"
+ });
+ }
+ })
+}
+
+}
+
+
+}};});