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.
240 lines
9.1 KiB
240 lines
9.1 KiB
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", "dojo/sniff"], |
|
function(declare, lang, array, win, query, domGeom, domAttr, domStyle, registry, LayoutBase, layout, constraints, has){ |
|
// 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 || (has("ie") == 8 && !event.view.domNode.parentElement)) { |
|
if(this.app.useConfigOrder){ |
|
event.view.parent.domNode.appendChild(event.view.domNode); |
|
}else{ |
|
this.addViewToParentDomByConstraint(event); |
|
} |
|
} |
|
domAttr.set(event.view.domNode, "data-app-constraint", event.view.constraint); |
|
this.inherited(arguments); |
|
}, |
|
|
|
addViewToParentDomByConstraint: function(event){ |
|
// summary: |
|
// Insert the view domNode into the parent domNode based upon the constraints. |
|
// It should layout the children in this order: top, left, center, right, bottom |
|
// Unless it is rtl then it should layout the children in this order: top, right, center, left, bottom |
|
// |
|
// event: Object |
|
// | {"parent":parent, "view":view, "removeView": boolean} |
|
var newViewConstraint = event.view.constraint; |
|
if(newViewConstraint === "bottom"){ // if new is bottom always place last |
|
event.view.parent.domNode.appendChild(event.view.domNode); |
|
}else if(newViewConstraint === "top"){ // if new is top always place first |
|
event.view.parent.domNode.insertBefore(event.view.domNode, event.view.parent.domNode.firstChild); |
|
}else{ // need to compare new constraint to the previous ones |
|
if(event.view.parent.domNode.children.length > 0){ // parent node has children, check constraints |
|
// in this loop if previous is top or left skip it and look for next child, otherwise process it |
|
for(var childIndex in event.view.parent.domNode.children){ |
|
var child = event.view.parent.domNode.children[childIndex]; |
|
var dir = domStyle.get(event.view.parent.domNode,"direction"); |
|
var isltr = (dir === "ltr"); |
|
var LEADING_VIEW = isltr ? "left" : "right"; |
|
var TRAILING_VIEW = isltr ? "right" : "left"; |
|
if(child.getAttribute && child.getAttribute("data-app-constraint")) { |
|
var previousViewConstraint = child.getAttribute("data-app-constraint"); |
|
// if previous is bottom or previous is Trailing |
|
// or previous is not top and newView is Leading we need to insert before this child |
|
if(previousViewConstraint === "bottom" || |
|
(previousViewConstraint === TRAILING_VIEW) || |
|
(previousViewConstraint !== "top" && |
|
(newViewConstraint === LEADING_VIEW))){ |
|
event.view.parent.domNode.insertBefore(event.view.domNode, child); |
|
break; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
// if the domNode was not added to the parent yet add it to the end now |
|
if (!event.view.domNode.parentNode || (has("ie") == 8 && !event.view.domNode.parentElement)) { |
|
event.view.parent.domNode.appendChild(event.view.domNode); |
|
} |
|
}, |
|
|
|
_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); |
|
} |
|
} |
|
}); |
|
});
|
|
|