You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
680 lines
24 KiB
680 lines
24 KiB
define([ |
|
"dojo/_base/array", |
|
"dojo/_base/config", |
|
"dojo/_base/connect", |
|
"dojo/_base/declare", |
|
"dojo/_base/lang", |
|
"dojo/sniff", |
|
"dojo/_base/window", |
|
"dojo/_base/Deferred", |
|
"dojo/dom", |
|
"dojo/dom-class", |
|
"dojo/dom-construct", |
|
"dojo/dom-geometry", |
|
"dojo/dom-style", |
|
"dijit/registry", |
|
"dijit/_Contained", |
|
"dijit/_Container", |
|
"dijit/_WidgetBase", |
|
"./ViewController", // to load ViewController for you (no direct references) |
|
"./common", |
|
"./transition", |
|
"./viewRegistry", |
|
"./_css3" |
|
], function(array, config, connect, declare, lang, has, win, Deferred, dom, domClass, domConstruct, domGeometry, domStyle, registry, Contained, Container, WidgetBase, ViewController, common, transitDeferred, viewRegistry, css3){ |
|
|
|
// module: |
|
// dojox/mobile/View |
|
|
|
var dm = lang.getObject("dojox.mobile", true); |
|
|
|
return declare("dojox.mobile.View", [WidgetBase, Container, Contained], { |
|
// summary: |
|
// A container widget for any HTML element and/or Dojo widgets |
|
// description: |
|
// View is a container widget for any HTML element and/or Dojo widgets. |
|
// As a Dojo widget container it can itself contain View widgets |
|
// forming a set of nested views. A Dojo Mobile application is usually |
|
// made of multiple View widgets and the user can navigate through |
|
// the views back and forth with animated transition effects. |
|
// |
|
// When using several sibling views (direct children of the same |
|
// element), you can use the 'selected' attribute to define whether |
|
// the view should be displayed when the application is launched. |
|
// If no view has selected=true, the first sibling view is displayed |
|
// at startup time. |
|
|
|
// selected: Boolean |
|
// If true, the view is displayed at startup time. |
|
selected: false, |
|
|
|
// keepScrollPos: Boolean |
|
// If true, the scroll position is kept when transition occurs between views. |
|
keepScrollPos: true, |
|
|
|
// tag: String |
|
// The name of the HTML tag to create as domNode. The default value is "div". |
|
tag: "div", |
|
|
|
/* internal properties */ |
|
baseClass: "mblView", |
|
|
|
constructor: function(/*Object*/params, /*DomNode?*/node){ |
|
// summary: |
|
// Creates a new instance of the class. |
|
// params: |
|
// Contains the parameters. |
|
// node: |
|
// The DOM node. If none is specified, it is automatically created. |
|
if(node){ |
|
dom.byId(node).style.visibility = "hidden"; |
|
} |
|
}, |
|
|
|
destroy: function(){ |
|
viewRegistry.remove(this.id); |
|
this.inherited(arguments); |
|
}, |
|
|
|
buildRendering: function(){ |
|
if(!this.templateString){ |
|
// Create root node if it wasn't created by _TemplatedMixin |
|
this.domNode = this.containerNode = this.srcNodeRef || domConstruct.create(this.tag); |
|
} |
|
|
|
this._animEndHandle = this.connect(this.domNode, css3.name("animationEnd"), "onAnimationEnd"); |
|
this._animStartHandle = this.connect(this.domNode, css3.name("animationStart"), "onAnimationStart"); |
|
if(!config.mblCSS3Transition){ |
|
this._transEndHandle = this.connect(this.domNode, css3.name("transitionEnd"), "onAnimationEnd"); |
|
} |
|
if(has('mblAndroid3Workaround')){ |
|
// workaround for the screen flicker issue on Android 3.x/4.0 |
|
// applying "-webkit-transform-style:preserve-3d" to domNode can avoid |
|
// transition animation flicker |
|
domStyle.set(this.domNode, css3.name("transformStyle"), "preserve-3d"); |
|
} |
|
|
|
viewRegistry.add(this); |
|
this.inherited(arguments); |
|
}, |
|
|
|
startup: function(){ |
|
if(this._started){ return; } |
|
|
|
// Determine which view among the siblings should be visible. |
|
// Priority: |
|
// 1. fragment id in the url (ex. #view1,view2) |
|
// 2. this.selected |
|
// 3. the first view |
|
if(this._visible === undefined){ |
|
var views = this.getSiblingViews(); |
|
var ids = location.hash && location.hash.substring(1).split(/,/); |
|
var fragView, selectedView, firstView; |
|
array.forEach(views, function(v, i){ |
|
if(array.indexOf(ids, v.id) !== -1){ fragView = v; } |
|
if(i == 0){ firstView = v; } |
|
if(v.selected){ selectedView = v; } |
|
v._visible = false; |
|
}, this); |
|
(fragView || selectedView || firstView)._visible = true; |
|
} |
|
if(this._visible){ |
|
// The 2nd arg is not to hide its sibling views so that they can be |
|
// correctly initialized. |
|
this.show(true, true); |
|
|
|
// Defer firing events to let user connect to events just after creation |
|
// TODO: revisit this for 2.0 |
|
this.defer(function(){ |
|
this.onStartView(); |
|
connect.publish("/dojox/mobile/startView", [this]); |
|
}); |
|
} |
|
|
|
if(this.domNode.style.visibility === "hidden"){ // this check is to avoid screen flickers |
|
this.domNode.style.visibility = "inherit"; |
|
} |
|
|
|
// Need to call inherited first - so that child widgets get started |
|
// up correctly |
|
this.inherited(arguments); |
|
|
|
var parent = this.getParent(); |
|
if(!parent || !parent.resize){ // top level widget |
|
this.resize(); |
|
} |
|
|
|
if(!this._visible){ |
|
// hide() should be called last so that child widgets can be |
|
// initialized while they are visible. |
|
this.hide(); |
|
} |
|
}, |
|
|
|
resize: function(){ |
|
// summary: |
|
// Calls resize() of each child widget. |
|
array.forEach(this.getChildren(), function(child){ |
|
if(child.resize){ child.resize(); } |
|
}); |
|
}, |
|
|
|
onStartView: function(){ |
|
// summary: |
|
// Stub function to connect to from your application. |
|
// description: |
|
// Called only when this view is shown at startup time. |
|
}, |
|
|
|
onBeforeTransitionIn: function(moveTo, dir, transition, context, method){ |
|
// summary: |
|
// Stub function to connect to from your application. |
|
// description: |
|
// Called before the arriving transition occurs. |
|
}, |
|
|
|
onAfterTransitionIn: function(moveTo, dir, transition, context, method){ |
|
// summary: |
|
// Stub function to connect to from your application. |
|
// description: |
|
// Called after the arriving transition occurs. |
|
}, |
|
|
|
onBeforeTransitionOut: function(moveTo, dir, transition, context, method){ |
|
// summary: |
|
// Stub function to connect to from your application. |
|
// description: |
|
// Called before the leaving transition occurs. |
|
}, |
|
|
|
onAfterTransitionOut: function(moveTo, dir, transition, context, method){ |
|
// summary: |
|
// Stub function to connect to from your application. |
|
// description: |
|
// Called after the leaving transition occurs. |
|
}, |
|
|
|
_clearClasses: function(/*DomNode*/node){ |
|
// summary: |
|
// Clean up the domNode classes that were added while making a transition. |
|
// description: |
|
// Remove all the "mbl" prefixed classes except mbl*View. |
|
if(!node){ return; } |
|
var classes = []; |
|
array.forEach(lang.trim(node.className||"").split(/\s+/), function(c){ |
|
if(c.match(/^mbl\w*View$/) || c.indexOf("mbl") === -1){ |
|
classes.push(c); |
|
} |
|
}, this); |
|
node.className = classes.join(' '); |
|
}, |
|
|
|
_fixViewState: function(/*DomNode*/toNode){ |
|
// summary: |
|
// Sanity check for view transition states. |
|
// description: |
|
// Sometimes uninitialization of Views fails after making view transition, |
|
// and that results in failure of subsequent view transitions. |
|
// This function does the uninitialization for all the sibling views. |
|
var nodes = this.domNode.parentNode.childNodes; |
|
for(var i = 0; i < nodes.length; i++){ |
|
var n = nodes[i]; |
|
if(n.nodeType === 1 && domClass.contains(n, "mblView")){ |
|
this._clearClasses(n); |
|
} |
|
} |
|
this._clearClasses(toNode); // just in case toNode is a sibling of an ancestor. |
|
|
|
// #16337 |
|
// Uninitialization may fail to clear _inProgress when multiple |
|
// performTransition calls occur in a short duration of time. |
|
var toWidget = registry.byNode(toNode); |
|
if(toWidget){ |
|
toWidget._inProgress = false; |
|
} |
|
}, |
|
|
|
convertToId: function(moveTo){ |
|
if(typeof(moveTo) == "string"){ |
|
// removes a leading hash mark (#) and params if exists |
|
// ex. "#bar&myParam=0003" -> "bar" |
|
return moveTo.replace(/^#?([^&?]+).*/, "$1"); |
|
} |
|
return moveTo; |
|
}, |
|
|
|
_isBookmarkable: function(detail){ |
|
return detail.moveTo && (config.mblForceBookmarkable || detail.moveTo.charAt(0) === '#') && !detail.hashchange; |
|
}, |
|
|
|
performTransition: function(/*String*/moveTo, /*Number*/transitionDir, /*String*/transition, |
|
/*Object|null*/context, /*String|Function*/method /*...*/){ |
|
// summary: |
|
// Function to perform the various types of view transitions, such as fade, slide, and flip. |
|
// moveTo: String |
|
// The id of the transition destination view which resides in |
|
// the current page. |
|
// If the value has a hash sign ('#') before the id |
|
// (e.g. #view1) and the dojo/hash module is loaded by the user |
|
// application, the view transition updates the hash in the |
|
// browser URL so that the user can bookmark the destination |
|
// view. In this case, the user can also use the browser's |
|
// back/forward button to navigate through the views in the |
|
// browser history. |
|
// If null, transitions to a blank view. |
|
// If '#', returns immediately without transition. |
|
// transitionDir: Number |
|
// The transition direction. If 1, transition forward. If -1, transition backward. |
|
// For example, the slide transition slides the view from right to left when transitionDir == 1, |
|
// and from left to right when transitionDir == -1. |
|
// transition: String |
|
// A type of animated transition effect. You can choose from |
|
// the standard transition types, "slide", "fade", "flip", or |
|
// from the extended transition types, "cover", "coverv", |
|
// "dissolve", "reveal", "revealv", "scaleIn", "scaleOut", |
|
// "slidev", "swirl", "zoomIn", "zoomOut", "cube", and |
|
// "swap". If "none" is specified, transition occurs |
|
// immediately without animation. |
|
// context: Object |
|
// The object that the callback function will receive as "this". |
|
// method: String|Function |
|
// A callback function that is called when the transition has finished. |
|
// A function reference, or name of a function in context. |
|
// tags: |
|
// public |
|
// |
|
// example: |
|
// Transition backward to a view whose id is "foo" with the slide animation. |
|
// | performTransition("foo", -1, "slide"); |
|
// |
|
// example: |
|
// Transition forward to a blank view, and then open another page. |
|
// | performTransition(null, 1, "slide", null, function(){location.href = href;}); |
|
|
|
if(this._inProgress){ return; } // transition is in progress |
|
this._inProgress = true; |
|
|
|
// normalize the arg |
|
var detail, optArgs; |
|
if(moveTo && typeof(moveTo) === "object"){ |
|
detail = moveTo; |
|
optArgs = transitionDir; // array |
|
}else{ |
|
detail = { |
|
moveTo: moveTo, |
|
transitionDir: transitionDir, |
|
transition: transition, |
|
context: context, |
|
method: method |
|
}; |
|
optArgs = []; |
|
for(var i = 5; i < arguments.length; i++){ |
|
optArgs.push(arguments[i]); |
|
} |
|
} |
|
|
|
// save the parameters |
|
this._detail = detail; |
|
this._optArgs = optArgs; |
|
this._arguments = [ |
|
detail.moveTo, |
|
detail.transitionDir, |
|
detail.transition, |
|
detail.context, |
|
detail.method |
|
]; |
|
|
|
if(detail.moveTo === "#"){ return; } |
|
var toNode; |
|
if(detail.moveTo){ |
|
toNode = this.convertToId(detail.moveTo); |
|
}else{ |
|
if(!this._dummyNode){ |
|
this._dummyNode = win.doc.createElement("div"); |
|
win.body().appendChild(this._dummyNode); |
|
} |
|
toNode = this._dummyNode; |
|
} |
|
|
|
if(this.addTransitionInfo && typeof(detail.moveTo) == "string" && this._isBookmarkable(detail)){ |
|
this.addTransitionInfo(this.id, detail.moveTo, {transitionDir:detail.transitionDir, transition:detail.transition}); |
|
} |
|
|
|
var fromNode = this.domNode; |
|
var fromTop = fromNode.offsetTop; |
|
toNode = this.toNode = dom.byId(toNode); |
|
if(!toNode){ console.log("dojox/mobile/View.performTransition: destination view not found: "+detail.moveTo); return; } |
|
toNode.style.visibility = "hidden"; |
|
toNode.style.display = ""; |
|
this._fixViewState(toNode); |
|
var toWidget = registry.byNode(toNode); |
|
if(toWidget){ |
|
// Now that the target view became visible, it's time to run resize() |
|
if(config.mblAlwaysResizeOnTransition || !toWidget._resized){ |
|
common.resizeAll(null, toWidget); |
|
toWidget._resized = true; |
|
} |
|
|
|
if(detail.transition && detail.transition != "none"){ |
|
// Temporarily add padding to align with the fromNode while transition |
|
toWidget._addTransitionPaddingTop(fromTop); |
|
} |
|
|
|
toWidget.load && toWidget.load(); // for ContentView |
|
|
|
toWidget.movedFrom = fromNode.id; |
|
} |
|
if(has('mblAndroidWorkaround') && !config.mblCSS3Transition |
|
&& detail.transition && detail.transition != "none"){ |
|
// workaround for the screen flicker issue on Android 2.2/2.3 |
|
// apply "-webkit-transform-style:preserve-3d" to both toNode and fromNode |
|
// to make them 3d-transition-ready state just before transition animation |
|
domStyle.set(toNode, css3.name("transformStyle"), "preserve-3d"); |
|
domStyle.set(fromNode, css3.name("transformStyle"), "preserve-3d"); |
|
// show toNode offscreen to avoid flicker when switching "display" and "visibility" styles |
|
domClass.add(toNode, "mblAndroidWorkaround"); |
|
} |
|
|
|
this.onBeforeTransitionOut.apply(this, this._arguments); |
|
connect.publish("/dojox/mobile/beforeTransitionOut", [this].concat(lang._toArray(this._arguments))); |
|
if(toWidget){ |
|
// perform view transition keeping the scroll position |
|
if(this.keepScrollPos && !this.getParent()){ |
|
var scrollTop = win.body().scrollTop || win.doc.documentElement.scrollTop || win.global.pageYOffset || 0; |
|
fromNode._scrollTop = scrollTop; |
|
var toTop = (detail.transitionDir == 1) ? 0 : (toNode._scrollTop || 0); |
|
toNode.style.top = "0px"; |
|
if(scrollTop > 1 || toTop !== 0){ |
|
fromNode.style.top = toTop - scrollTop + "px"; |
|
// address bar hiding does not work on iOS 7+. |
|
if(!(has("ios") >= 7) && config.mblHideAddressBar !== false){ |
|
this.defer(function(){ // iPhone needs setTimeout (via defer) |
|
win.global.scrollTo(0, (toTop || 1)); |
|
}); |
|
} |
|
} |
|
}else{ |
|
toNode.style.top = "0px"; |
|
} |
|
toWidget.onBeforeTransitionIn.apply(toWidget, this._arguments); |
|
connect.publish("/dojox/mobile/beforeTransitionIn", [toWidget].concat(lang._toArray(this._arguments))); |
|
} |
|
toNode.style.display = "none"; |
|
toNode.style.visibility = "inherit"; |
|
|
|
common.fromView = this; |
|
common.toView = toWidget; |
|
|
|
this._doTransition(fromNode, toNode, detail.transition, detail.transitionDir); |
|
}, |
|
|
|
_addTransitionPaddingTop: function(/*String|Integer*/ value){ |
|
// add padding top to the view in order to get alignment during the transition |
|
this.containerNode.style.paddingTop = value + "px"; |
|
}, |
|
|
|
_removeTransitionPaddingTop: function(){ |
|
// remove padding top from the view after the transition |
|
this.containerNode.style.paddingTop = ""; |
|
}, |
|
|
|
_toCls: function(s){ |
|
// convert from transition name to corresponding class name |
|
// ex. "slide" -> "mblSlide" |
|
return "mbl"+s.charAt(0).toUpperCase() + s.substring(1); |
|
}, |
|
|
|
_doTransition: function(fromNode, toNode, transition, transitionDir){ |
|
var rev = (transitionDir == -1) ? " mblReverse" : ""; |
|
toNode.style.display = ""; |
|
if(!transition || transition == "none"){ |
|
this.domNode.style.display = "none"; |
|
this.invokeCallback(); |
|
}else if(config.mblCSS3Transition){ |
|
//get dojox/css3/transit first |
|
Deferred.when(transitDeferred, lang.hitch(this, function(transit){ |
|
//follow the style of .mblView.mblIn in View.css |
|
//need to set the toNode to absolute position |
|
var toPosition = domStyle.get(toNode, "position"); |
|
domStyle.set(toNode, "position", "absolute"); |
|
Deferred.when(transit(fromNode, toNode, {transition: transition, reverse: (transitionDir===-1)?true:false}),lang.hitch(this,function(){ |
|
domStyle.set(toNode, "position", toPosition); |
|
// Reset the temporary padding on toNode |
|
toNode.style.paddingTop = ""; |
|
this.invokeCallback(); |
|
})); |
|
})); |
|
}else{ |
|
if(transition.indexOf("cube") != -1){ |
|
if(has('ipad')){ |
|
domStyle.set(toNode.parentNode, {webkitPerspective:1600}); |
|
}else if(has("ios")){ |
|
domStyle.set(toNode.parentNode, {webkitPerspective:800}); |
|
} |
|
} |
|
var s = this._toCls(transition); |
|
if(has('mblAndroidWorkaround')){ |
|
// workaround for the screen flicker issue on Android 2.2 |
|
// applying transition css classes just after setting toNode.style.display = "" |
|
// causes flicker, so wait for a while using setTimeout (via defer) |
|
var _this = this; |
|
_this.defer(function(){ |
|
domClass.add(fromNode, s + " mblOut" + rev); |
|
domClass.add(toNode, s + " mblIn" + rev); |
|
domClass.remove(toNode, "mblAndroidWorkaround"); // remove offscreen style |
|
_this.defer(function(){ |
|
domClass.add(fromNode, "mblTransition"); |
|
domClass.add(toNode, "mblTransition"); |
|
}, 30); // 30 = 100 - 70, to make total delay equal to 100ms |
|
}, 70); // 70ms is experiential value |
|
}else{ |
|
domClass.add(fromNode, s + " mblOut" + rev); |
|
domClass.add(toNode, s + " mblIn" + rev); |
|
this.defer(function(){ |
|
domClass.add(fromNode, "mblTransition"); |
|
domClass.add(toNode, "mblTransition"); |
|
}, 100); |
|
} |
|
// set transform origin |
|
var fromOrigin = "50% 50%"; |
|
var toOrigin = "50% 50%"; |
|
var scrollTop, posX, posY; |
|
if(transition.indexOf("swirl") != -1 || transition.indexOf("zoom") != -1){ |
|
if(this.keepScrollPos && !this.getParent()){ |
|
scrollTop = win.body().scrollTop || win.doc.documentElement.scrollTop || win.global.pageYOffset || 0; |
|
}else{ |
|
scrollTop = -domGeometry.position(fromNode, true).y; |
|
} |
|
posY = win.global.innerHeight / 2 + scrollTop; |
|
fromOrigin = "50% " + posY + "px"; |
|
toOrigin = "50% " + posY + "px"; |
|
}else if(transition.indexOf("scale") != -1){ |
|
var viewPos = domGeometry.position(fromNode, true); |
|
posX = ((this.clickedPosX !== undefined) ? this.clickedPosX : win.global.innerWidth / 2) - viewPos.x; |
|
if(this.keepScrollPos && !this.getParent()){ |
|
scrollTop = win.body().scrollTop || win.doc.documentElement.scrollTop || win.global.pageYOffset || 0; |
|
}else{ |
|
scrollTop = -viewPos.y; |
|
} |
|
posY = ((this.clickedPosY !== undefined) ? this.clickedPosY : win.global.innerHeight / 2) + scrollTop; |
|
fromOrigin = posX + "px " + posY + "px"; |
|
toOrigin = posX + "px " + posY + "px"; |
|
} |
|
domStyle.set(fromNode, css3.add({}, {transformOrigin:fromOrigin})); |
|
domStyle.set(toNode, css3.add({}, {transformOrigin:toOrigin})); |
|
} |
|
}, |
|
|
|
onAnimationStart: function(e){ |
|
// summary: |
|
// A handler that is called when transition animation starts. |
|
}, |
|
|
|
onAnimationEnd: function(e){ |
|
// summary: |
|
// A handler that is called after transition animation ends. |
|
var name = e.animationName || e.target.className; |
|
if(name.indexOf("Out") === -1 && |
|
name.indexOf("In") === -1 && |
|
name.indexOf("Shrink") === -1){ return; } |
|
var isOut = false; |
|
if(domClass.contains(this.domNode, "mblOut")){ |
|
isOut = true; |
|
this.domNode.style.display = "none"; |
|
domClass.remove(this.domNode, [this._toCls(this._detail.transition), "mblIn", "mblOut", "mblReverse"]); |
|
}else{ |
|
// Reset the temporary padding |
|
this._removeTransitionPaddingTop(); |
|
} |
|
domStyle.set(this.domNode, css3.add({}, {transformOrigin:""})); |
|
if(name.indexOf("Shrink") !== -1){ |
|
var li = e.target; |
|
li.style.display = "none"; |
|
domClass.remove(li, "mblCloseContent"); |
|
|
|
// If target is placed inside scrollable, need to call onTouchEnd |
|
// to adjust scroll position |
|
var p = viewRegistry.getEnclosingScrollable(this.domNode); |
|
p && p.onTouchEnd(); |
|
} |
|
if(isOut){ |
|
this.invokeCallback(); |
|
} |
|
this._clearClasses(this.domNode); |
|
|
|
// clear the clicked position |
|
this.clickedPosX = this.clickedPosY = undefined; |
|
|
|
if(name.indexOf("Cube") !== -1 && |
|
name.indexOf("In") !== -1 && has("ios")){ |
|
this.domNode.parentNode.style[css3.name("perspective")] = ""; |
|
} |
|
}, |
|
|
|
invokeCallback: function(){ |
|
// summary: |
|
// A function to be called after performing a transition to |
|
// call a specified callback. |
|
this.onAfterTransitionOut.apply(this, this._arguments); |
|
connect.publish("/dojox/mobile/afterTransitionOut", [this].concat(this._arguments)); |
|
var toWidget = registry.byNode(this.toNode); |
|
if(toWidget){ |
|
toWidget.onAfterTransitionIn.apply(toWidget, this._arguments); |
|
connect.publish("/dojox/mobile/afterTransitionIn", [toWidget].concat(this._arguments)); |
|
toWidget.movedFrom = undefined; |
|
if(this.setFragIds && this._isBookmarkable(this._detail)){ |
|
this.setFragIds(toWidget); // setFragIds is defined in bookmarkable.js |
|
} |
|
} |
|
if(has('mblAndroidWorkaround')){ |
|
// workaround for the screen flicker issue on Android 2.2/2.3 |
|
// remove "-webkit-transform-style" style after transition finished |
|
// to avoid side effects such as input field auto-scrolling issue |
|
// use setTimeout (via defer) to avoid flicker in case of ScrollableView |
|
this.defer(function(){ |
|
if(toWidget){ domStyle.set(this.toNode, css3.name("transformStyle"), ""); } |
|
domStyle.set(this.domNode, css3.name("transformStyle"), ""); |
|
}); |
|
} |
|
|
|
var c = this._detail.context, m = this._detail.method; |
|
if(c || m){ |
|
if(!m){ |
|
m = c; |
|
c = null; |
|
} |
|
c = c || win.global; |
|
if(typeof(m) == "string"){ |
|
c[m].apply(c, this._optArgs); |
|
}else if(typeof(m) == "function"){ |
|
m.apply(c, this._optArgs); |
|
} |
|
} |
|
this._detail = this._optArgs = this._arguments = undefined; |
|
this._inProgress = false; |
|
}, |
|
|
|
isVisible: function(/*Boolean?*/checkAncestors){ |
|
// summary: |
|
// Return true if this view is visible |
|
// checkAncestors: |
|
// If true, in addition to its own visibility, also checks the |
|
// ancestors visibility to see if the view is actually being |
|
// shown or not. |
|
var visible = function(node){ |
|
return domStyle.get(node, "display") !== "none"; |
|
}; |
|
if(checkAncestors){ |
|
for(var n = this.domNode; n.tagName !== "BODY"; n = n.parentNode){ |
|
if(!visible(n)){ return false; } |
|
} |
|
return true; |
|
}else{ |
|
return visible(this.domNode); |
|
} |
|
}, |
|
|
|
getShowingView: function(){ |
|
// summary: |
|
// Find the currently showing view from my sibling views. |
|
// description: |
|
// Note that depending on the ancestor views' visibility, |
|
// the found view may not be actually shown. |
|
var nodes = this.domNode.parentNode.childNodes; |
|
for(var i = 0; i < nodes.length; i++){ |
|
var n = nodes[i]; |
|
if(n.nodeType === 1 && domClass.contains(n, "mblView") && n.style.display !== "none"){ |
|
return registry.byNode(n); |
|
} |
|
} |
|
return null; |
|
}, |
|
|
|
getSiblingViews: function(){ |
|
// summary: |
|
// Returns an array of the sibling views. |
|
if(!this.domNode.parentNode){ return [this]; } |
|
return array.map(array.filter(this.domNode.parentNode.childNodes, |
|
function(n){ return n.nodeType === 1 && domClass.contains(n, "mblView"); }), |
|
function(n){ return registry.byNode(n); }); |
|
}, |
|
|
|
show: function(/*Boolean?*/noEvent, /*Boolean?*/doNotHideOthers){ |
|
// summary: |
|
// Shows this view without a transition animation. |
|
var out = this.getShowingView(); |
|
if(!noEvent){ |
|
if(out){ |
|
out.onBeforeTransitionOut(out.id); |
|
connect.publish("/dojox/mobile/beforeTransitionOut", [out, out.id]); |
|
} |
|
this.onBeforeTransitionIn(this.id); |
|
connect.publish("/dojox/mobile/beforeTransitionIn", [this, this.id]); |
|
} |
|
|
|
if(doNotHideOthers){ |
|
this.domNode.style.display = ""; |
|
}else{ |
|
array.forEach(this.getSiblingViews(), function(v){ |
|
v.domNode.style.display = (v === this) ? "" : "none"; |
|
}, this); |
|
} |
|
this.load && this.load(); // for ContentView |
|
|
|
if(!noEvent){ |
|
if(out){ |
|
out.onAfterTransitionOut(out.id); |
|
connect.publish("/dojox/mobile/afterTransitionOut", [out, out.id]); |
|
} |
|
this.onAfterTransitionIn(this.id); |
|
connect.publish("/dojox/mobile/afterTransitionIn", [this, this.id]); |
|
} |
|
}, |
|
|
|
hide: function(){ |
|
// summary: |
|
// Hides this view without a transition animation. |
|
this.domNode.style.display = "none"; |
|
} |
|
}); |
|
});
|
|
|