define(["dojo/_base/declare", "dojo/_base/lang", "dojo/_base/array", "dojo/_base/window", "dojo/query", "dojo/dom-geometry", "dojo/dom-attr", "dojo/dom-style", "dijit/registry", "./LayoutBase", "../utils/layout", "../utils/constraints"], function(declare, lang, array, win, query, domGeom, domAttr, domStyle, registry, LayoutBase, layout, constraints){ // module: // dojox/app/controllers/Layout // summary: // Extends LayoutBase which binds "app-initLayout", "app-layoutView" and "app-resize" events on application instance. return declare("dojox.app.controllers.Layout", LayoutBase, { constructor: function(app, events){ // summary: // bind "app-initLayout" and "app-layoutView" events on application instance. // // app: // dojox/app application instance. // events: // {event : handler} }, onResize: function(){ this._doResize(this.app); // this is needed to resize the children on an orientation change or a resize of the browser. // it was being done in _doResize, but was not needed for every call to _doResize. this.resizeSelectedChildren(this.app); }, resizeSelectedChildren: function(w){ for(var hash in w.selectedChildren){ // need this to handle all selectedChildren if(w.selectedChildren[hash] && w.selectedChildren[hash].domNode){ this.app.log("in Layout resizeSelectedChildren calling resizeSelectedChildren calling _doResize for w.selectedChildren[hash].id="+w.selectedChildren[hash].id); this._doResize(w.selectedChildren[hash]); // Call resize on child widgets, needed to get the scrollableView to resize correctly initially array.forEach(w.selectedChildren[hash].domNode.children, function(child){ if(registry.byId(child.id) && registry.byId(child.id).resize){ registry.byId(child.id).resize(); } }); this.resizeSelectedChildren(w.selectedChildren[hash]); } } }, initLayout: function(event){ // summary: // Response to dojox/app "app-initLayout" event. // // example: // Use emit to trigger "app-initLayout" event, and this function will respond to the event. For example: // | this.app.emit("app-initLayout", view); // // event: Object // | {"view": view, "callback": function(){}}; this.app.log("in app/controllers/Layout.initLayout event=",event); this.app.log("in app/controllers/Layout.initLayout event.view.parent.name=[",event.view.parent.name,"]"); if (!event.view.domNode.parentNode) { event.view.parent.domNode.appendChild(event.view.domNode); } domAttr.set(event.view.domNode, "data-app-constraint", event.view.constraint); this.inherited(arguments); }, _doResize: function(view){ // summary: // resize view. // // view: Object // view instance needs to do layout. var node = view.domNode; if(!node){ this.app.log("Warning - View has not been loaded, in Layout _doResize view.domNode is not set for view.id="+view.id+" view=",view); return; } // If either height or width wasn't specified by the user, then query node for it. // But note that setting the margin box and then immediately querying dimensions may return // inaccurate results, so try not to depend on it. var mb = {}; if( !("h" in mb) || !("w" in mb) ){ mb = lang.mixin(domGeom.getMarginBox(node), mb); // just use dojo/_base/html.marginBox() to fill in missing values } // Compute and save the size of my border box and content box // (w/out calling dojo/_base/html.contentBox() since that may fail if size was recently set) if(view !== this.app){ var cs = domStyle.getComputedStyle(node); var me = domGeom.getMarginExtents(node, cs); var be = domGeom.getBorderExtents(node, cs); var bb = (view._borderBox = { w: mb.w - (me.w + be.w), h: mb.h - (me.h + be.h) }); var pe = domGeom.getPadExtents(node, cs); view._contentBox = { l: domStyle.toPixelValue(node, cs.paddingLeft), t: domStyle.toPixelValue(node, cs.paddingTop), w: bb.w - pe.w, h: bb.h - pe.h }; }else{ // if we are layouting the top level app the above code does not work when hiding address bar // so let's use similar code to dojo mobile. view._contentBox = { l: 0, t: 0, h: win.global.innerHeight || win.doc.documentElement.clientHeight, w: win.global.innerWidth || win.doc.documentElement.clientWidth }; } this.inherited(arguments); }, layoutView: function(event){ // summary: // Response to dojox/app "app-layoutView" event. // // example: // Use emit to trigger "app-layoutView" event, and this function will response the event. For example: // | this.app.emit("app-layoutView", view); // // event: Object // | {"parent":parent, "view":view, "removeView": boolean} if(event.view){ this.inherited(arguments); // normally when called from transition doResize will be false, and the resize will only be done when the app-resize event is fired if(event.doResize){ this._doResize(event.parent || this.app); this._doResize(event.view); } } }, _doLayout: function(view){ // summary: // do view layout. // // view: Object // view instance needs to do layout. if(!view){ console.warn("layout empty view."); return; } this.app.log("in Layout _doLayout called for view.id="+view.id+" view=",view); var children; // TODO: probably need to handle selectedChildren here, not just selected child... // TODO: why are we passing view here? not parent? This call does not seem logical? var selectedChild = constraints.getSelectedChild(view, view.constraint); if(selectedChild && selectedChild.isFullScreen){ console.warn("fullscreen sceen layout"); /* fullScreenScene=true; children=[{domNode: selectedChild.domNode,constraint: "center"}]; query("> [constraint]",this.domNode).forEach(function(c){ if(selectedChild.domNode!==c.domNode){ dstyle(c.domNode,"display","none"); } }) */ }else{ children = query("> [data-app-constraint]", view.domNode).map(function(node){ var w = registry.getEnclosingWidget(node); if(w){ w._constraint = domAttr.get(node, "data-app-constraint"); return w; } return { domNode: node, _constraint: domAttr.get(node, "data-app-constraint") }; }); if(selectedChild){ children = array.filter(children, function(c){ // do not need to set display none here it is set in select. return c.domNode && c._constraint; }, view); } } // We don't need to layout children if this._contentBox is null for the operation will do nothing. if(view._contentBox){ layout.layoutChildren(view.domNode, view._contentBox, children); } } }); });