1 | define(["dojo/_base/kernel", |
---|
2 | "dojo/_base/declare", |
---|
3 | "dojo/_base/connect", |
---|
4 | "dojo/_base/array", |
---|
5 | "dojo/_base/Deferred", |
---|
6 | "dojo/_base/lang", |
---|
7 | "dojo/_base/sniff", |
---|
8 | "dojo/dom-style", |
---|
9 | "dojo/dom-geometry", |
---|
10 | "dojo/dom-class", |
---|
11 | "dojo/dom-construct", |
---|
12 | "dojo/dom-attr", |
---|
13 | "dojo/query", |
---|
14 | "dijit", |
---|
15 | "dojox", |
---|
16 | "dijit/_WidgetBase", |
---|
17 | "dijit/_TemplatedMixin", |
---|
18 | "dijit/_WidgetsInTemplateMixin", |
---|
19 | "dojox/css3/transit", |
---|
20 | "./animation", |
---|
21 | "./model", |
---|
22 | "./view", |
---|
23 | "./bind"], |
---|
24 | function(dojo,declare,connect, array,deferred,dlang,has,dstyle,dgeometry,cls,dconstruct,dattr,query,dijit,dojox,WidgetBase,Templated,WidgetsInTemplate,transit, anim, model, baseView, bind){ |
---|
25 | |
---|
26 | var marginBox2contentBox = function(/*DomNode*/ node, /*Object*/ mb){ |
---|
27 | // summary: |
---|
28 | // Given the margin-box size of a node, return its content box size. |
---|
29 | // Functions like dojo.contentBox() but is more reliable since it doesn't have |
---|
30 | // to wait for the browser to compute sizes. |
---|
31 | var cs = dstyle.getComputedStyle(node); |
---|
32 | var me = dgeometry.getMarginExtents(node, cs); |
---|
33 | var pb = dgeometry.getPadBorderExtents(node, cs); |
---|
34 | return { |
---|
35 | l: dstyle.toPixelValue(node, cs.paddingLeft), |
---|
36 | t: dstyle.toPixelValue(node, cs.paddingTop), |
---|
37 | w: mb.w - (me.w + pb.w), |
---|
38 | h: mb.h - (me.h + pb.h) |
---|
39 | }; |
---|
40 | }; |
---|
41 | |
---|
42 | var capitalize = function(word){ |
---|
43 | return word.substring(0,1).toUpperCase() + word.substring(1); |
---|
44 | }; |
---|
45 | |
---|
46 | var size = function(widget, dim){ |
---|
47 | // size the child |
---|
48 | var newSize = widget.resize ? widget.resize(dim) : dgeometry.setMarginBox(widget.domNode, dim); |
---|
49 | // record child's size |
---|
50 | if(newSize){ |
---|
51 | // if the child returned it's new size then use that |
---|
52 | dojo.mixin(widget, newSize); |
---|
53 | }else{ |
---|
54 | // otherwise, call marginBox(), but favor our own numbers when we have them. |
---|
55 | // the browser lies sometimes |
---|
56 | dojo.mixin(widget, dgeometry.getMarginBox(widget.domNode)); |
---|
57 | |
---|
58 | dojo.mixin(widget, dim); |
---|
59 | } |
---|
60 | }; |
---|
61 | |
---|
62 | return declare("dojox.app.scene", [dijit._WidgetBase, dijit._TemplatedMixin, dijit._WidgetsInTemplateMixin], { |
---|
63 | isContainer: true, |
---|
64 | widgetsInTemplate: true, |
---|
65 | defaultView: "default", |
---|
66 | |
---|
67 | selectedChild: null, |
---|
68 | baseClass: "scene mblView", |
---|
69 | isFullScreen: false, |
---|
70 | defaultViewType: baseView, |
---|
71 | |
---|
72 | //Temporary work around for getting a null when calling getParent |
---|
73 | getParent: function(){return null;}, |
---|
74 | |
---|
75 | |
---|
76 | constructor: function(params,node){ |
---|
77 | this.children={}; |
---|
78 | if(params.parent){ |
---|
79 | this.parent=params.parent |
---|
80 | } |
---|
81 | if(params.app){ |
---|
82 | this.app = params.app; |
---|
83 | } |
---|
84 | }, |
---|
85 | |
---|
86 | buildRendering: function(){ |
---|
87 | this.inherited(arguments); |
---|
88 | dstyle.set(this.domNode, {width: "100%", "height": "100%"}); |
---|
89 | cls.add(this.domNode,"dijitContainer"); |
---|
90 | }, |
---|
91 | |
---|
92 | splitChildRef: function(childId){ |
---|
93 | var id = childId.split(","); |
---|
94 | if (id.length>0){ |
---|
95 | var to = id.shift(); |
---|
96 | }else{ |
---|
97 | console.warn("invalid child id passed to splitChildRef(): ", childId); |
---|
98 | } |
---|
99 | |
---|
100 | return { |
---|
101 | id:to || this.defaultView, |
---|
102 | next: id.join(',') |
---|
103 | } |
---|
104 | }, |
---|
105 | |
---|
106 | loadChild: function(childId,subIds){ |
---|
107 | // if no childId, load the default view |
---|
108 | if (!childId) { |
---|
109 | var parts = this.defaultView ? this.defaultView.split(",") : "default"; |
---|
110 | childId = parts.shift(); |
---|
111 | subIds = parts.join(','); |
---|
112 | } |
---|
113 | |
---|
114 | var cid = this.id+"_" + childId; |
---|
115 | if (this.children[cid]){ |
---|
116 | return this.children[cid]; |
---|
117 | } |
---|
118 | |
---|
119 | if (this.views&& this.views[childId]){ |
---|
120 | var conf = this.views[childId]; |
---|
121 | if (!conf.dependencies){conf.dependencies=[];} |
---|
122 | var deps = conf.template? conf.dependencies.concat(["dojo/text!app/"+conf.template]) : |
---|
123 | conf.dependencies.concat([]); |
---|
124 | |
---|
125 | var def = new deferred(); |
---|
126 | if (deps.length>0) { |
---|
127 | require(deps,function(){ |
---|
128 | def.resolve.call(def, arguments); |
---|
129 | }); |
---|
130 | }else{ |
---|
131 | def.resolve(true); |
---|
132 | } |
---|
133 | |
---|
134 | var loadChildDeferred = new deferred(); |
---|
135 | var self = this; |
---|
136 | deferred.when(def, function(){ |
---|
137 | var ctor; |
---|
138 | if (conf.type){ |
---|
139 | ctor=dojo.getObject(conf.type); |
---|
140 | }else if (self.defaultViewType){ |
---|
141 | ctor=self.defaultViewType; |
---|
142 | }else{ |
---|
143 | throw Error("Unable to find appropriate ctor for the base child class"); |
---|
144 | } |
---|
145 | |
---|
146 | var params = dojo.mixin({}, conf, { |
---|
147 | id: self.id + "_" + childId, |
---|
148 | templateString: conf.template?arguments[0][arguments[0].length-1]:"<div></div>", |
---|
149 | parent: self, |
---|
150 | app: self.app |
---|
151 | }) |
---|
152 | if (subIds){ |
---|
153 | params.defaultView=subIds; |
---|
154 | } |
---|
155 | var child = new ctor(params); |
---|
156 | //load child's model if it is not loaded before |
---|
157 | if(!child.loadedModels){ |
---|
158 | child.loadedModels = model(conf.models, self.loadedModels) |
---|
159 | //TODO need to find out a better way to get all bindable controls in a view |
---|
160 | bind([child], child.loadedModels); |
---|
161 | } |
---|
162 | var addResult = self.addChild(child); |
---|
163 | //publish /app/loadchild event |
---|
164 | //application can subscript this event to do user define operation like select TabBarButton, add dynamic script text etc. |
---|
165 | connect.publish("/app/loadchild", [child]); |
---|
166 | |
---|
167 | var promise; |
---|
168 | |
---|
169 | subIds = subIds.split(','); |
---|
170 | if ((subIds[0].length > 0) && (subIds.length > 1)) {//TODO join subIds |
---|
171 | promise = child.loadChild(subIds[0], subIds[1]); |
---|
172 | } |
---|
173 | else |
---|
174 | if (subIds[0].length > 0) { |
---|
175 | promise = child.loadChild(subIds[0], ""); |
---|
176 | } |
---|
177 | |
---|
178 | dojo.when(promise, function(){ |
---|
179 | loadChildDeferred.resolve(addResult) |
---|
180 | }); |
---|
181 | }); |
---|
182 | return loadChildDeferred; |
---|
183 | } |
---|
184 | |
---|
185 | throw Error("Child '" + childId + "' not found."); |
---|
186 | }, |
---|
187 | |
---|
188 | resize: function(changeSize,resultSize){ |
---|
189 | var node = this.domNode; |
---|
190 | |
---|
191 | // set margin box size, unless it wasn't specified, in which case use current size |
---|
192 | if(changeSize){ |
---|
193 | dgeometry.setMarginBox(node, changeSize); |
---|
194 | |
---|
195 | // set offset of the node |
---|
196 | if(changeSize.t){ node.style.top = changeSize.t + "px"; } |
---|
197 | if(changeSize.l){ node.style.left = changeSize.l + "px"; } |
---|
198 | } |
---|
199 | |
---|
200 | // If either height or width wasn't specified by the user, then query node for it. |
---|
201 | // But note that setting the margin box and then immediately querying dimensions may return |
---|
202 | // inaccurate results, so try not to depend on it. |
---|
203 | var mb = resultSize || {}; |
---|
204 | dojo.mixin(mb, changeSize || {}); // changeSize overrides resultSize |
---|
205 | if( !("h" in mb) || !("w" in mb) ){ |
---|
206 | mb = dojo.mixin(dgeometry.getMarginBox(node), mb); // just use dojo.marginBox() to fill in missing values |
---|
207 | } |
---|
208 | |
---|
209 | // Compute and save the size of my border box and content box |
---|
210 | // (w/out calling dojo.contentBox() since that may fail if size was recently set) |
---|
211 | var cs = dstyle.getComputedStyle(node); |
---|
212 | var me = dgeometry.getMarginExtents(node, cs); |
---|
213 | var be = dgeometry.getBorderExtents(node, cs); |
---|
214 | var bb = (this._borderBox = { |
---|
215 | w: mb.w - (me.w + be.w), |
---|
216 | h: mb.h - (me.h + be.h) |
---|
217 | }); |
---|
218 | var pe = dgeometry.getPadExtents(node, cs); |
---|
219 | this._contentBox = { |
---|
220 | l: dstyle.toPixelValue(node, cs.paddingLeft), |
---|
221 | t: dstyle.toPixelValue(node, cs.paddingTop), |
---|
222 | w: bb.w - pe.w, |
---|
223 | h: bb.h - pe.h |
---|
224 | }; |
---|
225 | |
---|
226 | // Callback for widget to adjust size of its children |
---|
227 | this.layout(); |
---|
228 | }, |
---|
229 | |
---|
230 | layout: function(){ |
---|
231 | var fullScreenScene,children,hasCenter; |
---|
232 | //console.log("fullscreen: ", this.selectedChild && this.selectedChild.isFullScreen); |
---|
233 | if (this.selectedChild && this.selectedChild.isFullScreen) { |
---|
234 | console.warn("fullscreen sceen layout"); |
---|
235 | /* |
---|
236 | fullScreenScene=true; |
---|
237 | children=[{domNode: this.selectedChild.domNode,region: "center"}]; |
---|
238 | dojo.query("> [region]",this.domNode).forEach(function(c){ |
---|
239 | if(this.selectedChild.domNode!==c.domNode){ |
---|
240 | dojo.style(c.domNode,"display","none"); |
---|
241 | } |
---|
242 | }) |
---|
243 | */ |
---|
244 | }else{ |
---|
245 | children = query("> [region]", this.domNode).map(function(node){ |
---|
246 | var w = dijit.getEnclosingWidget(node); |
---|
247 | if (w){return w;} |
---|
248 | |
---|
249 | return { |
---|
250 | domNode: node, |
---|
251 | region: dattr.get(node,"region") |
---|
252 | } |
---|
253 | |
---|
254 | }); |
---|
255 | if (this.selectedChild){ |
---|
256 | children = array.filter(children, function(c){ |
---|
257 | if (c.region=="center" && this.selectedChild && this.selectedChild.domNode!==c.domNode){ |
---|
258 | dstyle.set(c.domNode,"zIndex",25); |
---|
259 | dstyle.set(c.domNode,'display','none'); |
---|
260 | return false; |
---|
261 | }else if (c.region!="center"){ |
---|
262 | dstyle.set(c.domNode,"display",""); |
---|
263 | dstyle.set(c.domNode,"zIndex",100); |
---|
264 | } |
---|
265 | |
---|
266 | return c.domNode && c.region; |
---|
267 | },this); |
---|
268 | |
---|
269 | // this.selectedChild.region="center"; |
---|
270 | // dojo.attr(this.selectedChild.domNode,"region","center"); |
---|
271 | // dojo.style(this.selectedChild.domNode, "display",""); |
---|
272 | // dojo.style(this.selectedChild.domNode,"zIndex",50); |
---|
273 | |
---|
274 | // children.push({domNode: this.selectedChild.domNode, region: "center"}); |
---|
275 | // children.push(this.selectedChild); |
---|
276 | // console.log("children: ", children); |
---|
277 | }else{ |
---|
278 | array.forEach(children, function(c){ |
---|
279 | if (c && c.domNode && c.region=="center"){ |
---|
280 | dstyle.set(c.domNode,"zIndex",25); |
---|
281 | dstyle.set(c.domNode,'display','none'); |
---|
282 | } |
---|
283 | }); |
---|
284 | } |
---|
285 | |
---|
286 | } |
---|
287 | // We don't need to layout children if this._contentBox is null for the operation will do nothing. |
---|
288 | if (this._contentBox) { |
---|
289 | this.layoutChildren(this.domNode, this._contentBox, children); |
---|
290 | } |
---|
291 | array.forEach(this.getChildren(), function(child){ |
---|
292 | if (!child._started && child.startup){ |
---|
293 | child.startup(); |
---|
294 | } |
---|
295 | |
---|
296 | }); |
---|
297 | |
---|
298 | }, |
---|
299 | |
---|
300 | |
---|
301 | layoutChildren: function(/*DomNode*/ container, /*Object*/ dim, /*Widget[]*/ children, |
---|
302 | /*String?*/ changedRegionId, /*Number?*/ changedRegionSize){ |
---|
303 | // summary |
---|
304 | // Layout a bunch of child dom nodes within a parent dom node |
---|
305 | // container: |
---|
306 | // parent node |
---|
307 | // dim: |
---|
308 | // {l, t, w, h} object specifying dimensions of container into which to place children |
---|
309 | // children: |
---|
310 | // an array of Widgets or at least objects containing: |
---|
311 | // * domNode: pointer to DOM node to position |
---|
312 | // * region or layoutAlign: position to place DOM node |
---|
313 | // * resize(): (optional) method to set size of node |
---|
314 | // * id: (optional) Id of widgets, referenced from resize object, below. |
---|
315 | // changedRegionId: |
---|
316 | // If specified, the slider for the region with the specified id has been dragged, and thus |
---|
317 | // the region's height or width should be adjusted according to changedRegionSize |
---|
318 | // changedRegionSize: |
---|
319 | // See changedRegionId. |
---|
320 | |
---|
321 | // copy dim because we are going to modify it |
---|
322 | dim = dojo.mixin({}, dim); |
---|
323 | |
---|
324 | cls.add(container, "dijitLayoutContainer"); |
---|
325 | |
---|
326 | // Move "client" elements to the end of the array for layout. a11y dictates that the author |
---|
327 | // needs to be able to put them in the document in tab-order, but this algorithm requires that |
---|
328 | // client be last. TODO: move these lines to LayoutContainer? Unneeded other places I think. |
---|
329 | children = array.filter(children, function(item){ return item.region != "center" && item.layoutAlign != "client"; }) |
---|
330 | .concat(array.filter(children, function(item){ return item.region == "center" || item.layoutAlign == "client"; })); |
---|
331 | |
---|
332 | // set positions/sizes |
---|
333 | array.forEach(children, function(child){ |
---|
334 | var elm = child.domNode, |
---|
335 | pos = (child.region || child.layoutAlign); |
---|
336 | |
---|
337 | // set elem to upper left corner of unused space; may move it later |
---|
338 | var elmStyle = elm.style; |
---|
339 | elmStyle.left = dim.l+"px"; |
---|
340 | elmStyle.top = dim.t+"px"; |
---|
341 | elmStyle.position = "absolute"; |
---|
342 | |
---|
343 | cls.add(elm, "dijitAlign" + capitalize(pos)); |
---|
344 | |
---|
345 | // Size adjustments to make to this child widget |
---|
346 | var sizeSetting = {}; |
---|
347 | |
---|
348 | // Check for optional size adjustment due to splitter drag (height adjustment for top/bottom align |
---|
349 | // panes and width adjustment for left/right align panes. |
---|
350 | if(changedRegionId && changedRegionId == child.id){ |
---|
351 | sizeSetting[child.region == "top" || child.region == "bottom" ? "h" : "w"] = changedRegionSize; |
---|
352 | } |
---|
353 | |
---|
354 | // set size && adjust record of remaining space. |
---|
355 | // note that setting the width of a <div> may affect its height. |
---|
356 | if(pos == "top" || pos == "bottom"){ |
---|
357 | sizeSetting.w = dim.w; |
---|
358 | size(child, sizeSetting); |
---|
359 | dim.h -= child.h; |
---|
360 | if(pos == "top"){ |
---|
361 | dim.t += child.h; |
---|
362 | }else{ |
---|
363 | elmStyle.top = dim.t + dim.h + "px"; |
---|
364 | } |
---|
365 | }else if(pos == "left" || pos == "right"){ |
---|
366 | sizeSetting.h = dim.h; |
---|
367 | size(child, sizeSetting); |
---|
368 | dim.w -= child.w; |
---|
369 | if(pos == "left"){ |
---|
370 | dim.l += child.w; |
---|
371 | }else{ |
---|
372 | elmStyle.left = dim.l + dim.w + "px"; |
---|
373 | } |
---|
374 | }else if(pos == "client" || pos == "center"){ |
---|
375 | size(child, dim); |
---|
376 | } |
---|
377 | }); |
---|
378 | }, |
---|
379 | |
---|
380 | getChildren: function(){ |
---|
381 | return this._supportingWidgets; |
---|
382 | }, |
---|
383 | |
---|
384 | startup: function(){ |
---|
385 | if(this._started){ return; } |
---|
386 | this._started=true; |
---|
387 | |
---|
388 | var parts = this.defaultView?this.defaultView.split(","):"default"; |
---|
389 | var toId, subIds; |
---|
390 | toId= parts.shift(); |
---|
391 | subIds = parts.join(','); |
---|
392 | |
---|
393 | if(this.views[this.defaultView] && this.views[this.defaultView]["defaultView"]){ |
---|
394 | subIds = this.views[this.defaultView]["defaultView"]; |
---|
395 | } |
---|
396 | |
---|
397 | if(this.models && !this.loadedModels){ |
---|
398 | //if there is this.models config data and the models has not been loaded yet, |
---|
399 | //load models at here using the configuration data and load model logic in model.js |
---|
400 | this.loadedModels = model(this.models); |
---|
401 | bind(this.getChildren(), this.loadedModels); |
---|
402 | } |
---|
403 | |
---|
404 | //startup assumes all children are loaded into DOM before startup is called |
---|
405 | //startup will only start the current available children. |
---|
406 | var cid = this.id + "_" + toId; |
---|
407 | if (this.children[cid]) { |
---|
408 | var next = this.children[cid]; |
---|
409 | |
---|
410 | this.set("selectedChild", next); |
---|
411 | |
---|
412 | // If I am a not being controlled by a parent layout widget... |
---|
413 | var parent = this.getParent && this.getParent(); |
---|
414 | if (!(parent && parent.isLayoutContainer)) { |
---|
415 | // Do recursive sizing and layout of all my descendants |
---|
416 | // (passing in no argument to resize means that it has to glean the size itself) |
---|
417 | this.resize(); |
---|
418 | |
---|
419 | // Since my parent isn't a layout container, and my style *may be* width=height=100% |
---|
420 | // or something similar (either set directly or via a CSS class), |
---|
421 | // monitor when my size changes so that I can re-layout. |
---|
422 | // For browsers where I can't directly monitor when my size changes, |
---|
423 | // monitor when the viewport changes size, which *may* indicate a size change for me. |
---|
424 | this.connect(has("ie") ? this.domNode : dojo.global, 'onresize', function(){ |
---|
425 | // Using function(){} closure to ensure no arguments to resize. |
---|
426 | this.resize(); |
---|
427 | }); |
---|
428 | |
---|
429 | } |
---|
430 | |
---|
431 | array.forEach(this.getChildren(), function(child){ |
---|
432 | child.startup(); |
---|
433 | }); |
---|
434 | |
---|
435 | //transition to _startView |
---|
436 | if (this._startView && (this._startView != this.defaultView)) { |
---|
437 | this.transition(this._startView, {}); |
---|
438 | } |
---|
439 | } |
---|
440 | }, |
---|
441 | |
---|
442 | addChild: function(widget){ |
---|
443 | cls.add(widget.domNode, this.baseClass + "_child"); |
---|
444 | widget.region = "center";; |
---|
445 | dattr.set(widget.domNode,"region","center"); |
---|
446 | this._supportingWidgets.push(widget); |
---|
447 | dconstruct.place(widget.domNode,this.domNode); |
---|
448 | this.children[widget.id] = widget; |
---|
449 | return widget; |
---|
450 | }, |
---|
451 | |
---|
452 | removeChild: function(widget){ |
---|
453 | // summary: |
---|
454 | // Removes the passed widget instance from this widget but does |
---|
455 | // not destroy it. You can also pass in an integer indicating |
---|
456 | // the index within the container to remove |
---|
457 | |
---|
458 | if(widget){ |
---|
459 | var node = widget.domNode; |
---|
460 | if(node && node.parentNode){ |
---|
461 | node.parentNode.removeChild(node); // detach but don't destroy |
---|
462 | } |
---|
463 | return widget; |
---|
464 | } |
---|
465 | }, |
---|
466 | |
---|
467 | _setSelectedChildAttr: function(child,opts){ |
---|
468 | if (child !== this.selectedChild) { |
---|
469 | return deferred.when(child, dlang.hitch(this, function(child){ |
---|
470 | if (this.selectedChild){ |
---|
471 | if (this.selectedChild.deactivate){ |
---|
472 | this.selectedChild.deactivate(); |
---|
473 | } |
---|
474 | |
---|
475 | dstyle.set(this.selectedChild.domNode,"zIndex",25); |
---|
476 | } |
---|
477 | |
---|
478 | //dojo.style(child.domNode, { |
---|
479 | // "display": "", |
---|
480 | // "zIndex": 50, |
---|
481 | // "overflow": "auto" |
---|
482 | //}); |
---|
483 | this.selectedChild = child; |
---|
484 | dstyle.set(child.domNode, "display", ""); |
---|
485 | dstyle.set(child.domNode,"zIndex",50); |
---|
486 | this.selectedChild=child; |
---|
487 | if (this._started) { |
---|
488 | if (child.startup && !child._started){ |
---|
489 | child.startup(); |
---|
490 | }else if (child.activate){ |
---|
491 | child.activate(); |
---|
492 | } |
---|
493 | |
---|
494 | } |
---|
495 | this.layout(); |
---|
496 | })); |
---|
497 | } |
---|
498 | }, |
---|
499 | |
---|
500 | |
---|
501 | transition: function(transitionTo,opts){ |
---|
502 | //summary: |
---|
503 | // transitions from the currently visible scene to the defined scene. |
---|
504 | // it should determine what would be the best transition unless |
---|
505 | // an override in opts tells it to use a specific transitioning methodology |
---|
506 | // the transitionTo is a string in the form of [view]@[scene]. If |
---|
507 | // view is left of, the current scene will be transitioned to the default |
---|
508 | // view of the specified scene (eg @scene2), if the scene is left off |
---|
509 | // the app controller will instruct the active scene to the view (eg view1). If both |
---|
510 | // are supplied (view1@scene2), then the application should transition to the scene, |
---|
511 | // and instruct the scene to navigate to the view. |
---|
512 | var toId,subIds,next, current = this.selectedChild; |
---|
513 | console.log("scene", this.id, transitionTo); |
---|
514 | if (transitionTo){ |
---|
515 | var parts = transitionTo.split(","); |
---|
516 | toId= parts.shift(); |
---|
517 | subIds = parts.join(','); |
---|
518 | |
---|
519 | }else{ |
---|
520 | toId = this.defaultView; |
---|
521 | if(this.views[this.defaultView] && this.views[this.defaultView]["defaultView"]){ |
---|
522 | subIds = this.views[this.defaultView]["defaultView"]; |
---|
523 | } |
---|
524 | } |
---|
525 | |
---|
526 | next = this.loadChild(toId,subIds); |
---|
527 | |
---|
528 | if (!current){ |
---|
529 | //assume this.set(...) will return a promise object if child is first loaded |
---|
530 | //return nothing if child is already in array of this.children |
---|
531 | return this.set("selectedChild",next); |
---|
532 | } |
---|
533 | |
---|
534 | var transitionDeferred = new deferred(); |
---|
535 | deferred.when(next, dlang.hitch(this, function(next){ |
---|
536 | var promise; |
---|
537 | |
---|
538 | if (next!==current){ |
---|
539 | //TODO need to refactor here, when clicking fast, current will not be the |
---|
540 | //view we want to start transition. For example, during transition 1 -> 2 |
---|
541 | //if user click button to transition to 3 and then transition to 1. It will |
---|
542 | //perform transition 2 -> 3 and 2 -> 1 because current is always point to |
---|
543 | //2 during 1 -> 2 transition. |
---|
544 | |
---|
545 | var waitingList = anim.getWaitingList([next.domNode, current.domNode]); |
---|
546 | //update registry with deferred objects in animations of args. |
---|
547 | var transitionDefs = {}; |
---|
548 | transitionDefs[current.domNode.id] = anim.playing[current.domNode.id] = new deferred(); |
---|
549 | transitionDefs[next.domNode.id] = anim.playing[current.domNode.id] = new deferred(); |
---|
550 | |
---|
551 | deferred.when(waitingList, dojo.hitch(this, function(){ |
---|
552 | //assume next is already loaded so that this.set(...) will not return |
---|
553 | //a promise object. this.set(...) will handles the this.selectedChild, |
---|
554 | //activate or deactivate views and refresh layout. |
---|
555 | this.set("selectedChild", next); |
---|
556 | |
---|
557 | //publish /app/transition event |
---|
558 | //application can subscript this event to do user define operation like select TabBarButton, etc. |
---|
559 | connect.publish("/app/transition", [next, toId]); |
---|
560 | transit(current.domNode,next.domNode,dojo.mixin({},opts,{transition: this.defaultTransition || "none", transitionDefs: transitionDefs})).then(dlang.hitch(this, function(){ |
---|
561 | //dojo.style(current.domNode, "display", "none"); |
---|
562 | if (subIds && next.transition){ |
---|
563 | promise = next.transition(subIds,opts); |
---|
564 | } |
---|
565 | deferred.when(promise, function(){ |
---|
566 | transitionDeferred.resolve(); |
---|
567 | }); |
---|
568 | })); |
---|
569 | })); |
---|
570 | return; |
---|
571 | } |
---|
572 | |
---|
573 | //we didn't need to transition, but continue to propogate. |
---|
574 | if (subIds && next.transition){ |
---|
575 | promise = next.transition(subIds,opts); |
---|
576 | } |
---|
577 | deferred.when(promise, function(){ |
---|
578 | transitionDeferred.resolve(); |
---|
579 | }); |
---|
580 | })); |
---|
581 | return transitionDeferred; |
---|
582 | }, |
---|
583 | toString: function(){return this.id}, |
---|
584 | |
---|
585 | activate: function(){}, |
---|
586 | deactive: function(){} |
---|
587 | }); |
---|
588 | }); |
---|