UNPKG

dijit

Version:

Dijit provides a complete collection of user interface controls based on Dojo, giving you the power to create web applications that are highly optimized for usability, performance, internationalization, accessibility, but above all deliver an incredible u

237 lines (200 loc) 8.75 kB
define([ "dojo/_base/array", // array.filter array.forEach "dojo/_base/declare", // declare "dojo/dom-class", // domClass.contains domClass.toggle "dojo/dom-geometry", // domGeometry.contentBox domGeometry.marginBox "dojo/dom-style", "dojo/_base/lang", // lang.mixin "dojo/query", // query "../registry", // registry.byId "../Viewport", "./utils" // marginBox2contextBox ], function(array, declare, domClass, domGeometry, domStyle, lang, query, registry, Viewport, layoutUtils){ // module: // dijit/layout/_ContentPaneResizeMixin return declare("dijit.layout._ContentPaneResizeMixin", null, { // summary: // Resize() functionality of ContentPane. If there's a single layout widget // child then it will call resize() with the same dimensions as the ContentPane. // Otherwise just calls resize on each child. // // Also implements basic startup() functionality, where starting the parent // will start the children // doLayout: Boolean // - false - don't adjust size of children // - true - if there is a single visible child widget, set it's size to however big the ContentPane is doLayout: true, // isLayoutContainer: [protected] Boolean // Indicates that this widget will call resize() on it's child widgets // when they become visible. isLayoutContainer: true, startup: function(){ // summary: // See `dijit/layout/_LayoutWidget.startup()` for description. // Although ContentPane doesn't extend _LayoutWidget, it does implement // the same API. if(this._started){ return; } var parent = this.getParent(); this._childOfLayoutWidget = parent && parent.isLayoutContainer; // I need to call resize() on my child/children (when I become visible), unless // I'm the child of a layout widget in which case my parent will call resize() on me and I'll do it then. this._needLayout = !this._childOfLayoutWidget; this.inherited(arguments); if(this._isShown()){ this._onShow(); } if(!this._childOfLayoutWidget){ // Since my parent isn't a layout container, and my style *may be* width=height=100% // or something similar (either set directly or via a CSS class), // monitor when viewport size changes so that I can re-layout. // This is more for subclasses of ContentPane than ContentPane itself, although it // could be useful for a ContentPane if it has a single child widget inheriting ContentPane's size. this.own(Viewport.on("resize", lang.hitch(this, "resize"))); } }, _checkIfSingleChild: function(){ // summary: // Test if we have exactly one visible widget as a child, // and if so assume that we are a container for that widget, // and should propagate startup() and resize() calls to it. // Skips over things like data stores since they aren't visible. if(!this.doLayout){ return; } var candidateWidgets = [], otherVisibleNodes = false; query("> *", this.containerNode).some(function(node){ var widget = registry.byNode(node); if(widget && widget.resize){ candidateWidgets.push(widget); }else if(!/script|link|style/i.test(node.nodeName) && node.offsetHeight){ otherVisibleNodes = true; } }); this._singleChild = candidateWidgets.length == 1 && !otherVisibleNodes ? candidateWidgets[0] : null; // So we can set overflow: hidden to avoid a safari bug w/scrollbars showing up (#9449) domClass.toggle(this.containerNode, this.baseClass + "SingleChild", !!this._singleChild); }, resize: function(changeSize, resultSize){ // summary: // See `dijit/layout/_LayoutWidget.resize()` for description. // Although ContentPane doesn't extend _LayoutWidget, it does implement // the same API. this._resizeCalled = true; this._scheduleLayout(changeSize, resultSize); }, _scheduleLayout: function(changeSize, resultSize){ // summary: // Resize myself, and call resize() on each of my child layout widgets, either now // (if I'm currently visible) or when I become visible if(this._isShown()){ this._layout(changeSize, resultSize); }else{ this._needLayout = true; this._changeSize = changeSize; this._resultSize = resultSize; } }, _layout: function(changeSize, resultSize){ // summary: // Resize myself according to optional changeSize/resultSize parameters, like a layout widget. // Also, since I am an isLayoutContainer widget, each of my children expects me to // call resize() or layout() on it. // // Should be called on initialization and also whenever we get new content // (from an href, or from set('content', ...))... but deferred until // the ContentPane is visible delete this._needLayout; // For the TabContainer --> BorderContainer --> ContentPane case, _onShow() is // never called directly, so resize() is our trigger to do the initial href download (see [20099]). // However, don't load href for closed TitlePanes. if(!this._wasShown && this.open !== false){ this._onShow(); } // Set margin box size, unless it wasn't specified, in which case use current size. if(changeSize){ domGeometry.setMarginBox(this.domNode, changeSize); } // Compute content box size of containerNode in case we [later] need to size our single child. var cn = this.containerNode; if(cn === this.domNode){ // If changeSize or resultSize was passed to this method and this.containerNode == // this.domNode then we can compute the content-box size without querying the node, // which is more reliable (similar to LayoutWidget.resize) (see for example #9449). var mb = resultSize || {}; lang.mixin(mb, changeSize || {}); // changeSize overrides resultSize if(!("h" in mb) || !("w" in mb)){ mb = lang.mixin(domGeometry.getMarginBox(cn), mb); // just use domGeometry.setMarginBox() to fill in missing values } this._contentBox = layoutUtils.marginBox2contentBox(cn, mb); }else{ this._contentBox = domGeometry.getContentBox(cn); } this._layoutChildren(); }, _layoutChildren: function(){ // Call _checkIfSingleChild() again in case app has manually mucked w/the content // of the ContentPane (rather than changing it through the set("content", ...) API. this._checkIfSingleChild(); if(this._singleChild && this._singleChild.resize){ var cb = this._contentBox || domGeometry.getContentBox(this.containerNode); // note: if widget has padding this._contentBox will have l and t set, // but don't pass them to resize() or it will doubly-offset the child this._singleChild.resize({w: cb.w, h: cb.h}); }else{ // All my child widgets are independently sized (rather than matching my size), // but I still need to call resize() on each child to make it layout. var children = this.getChildren(), widget, i = 0; while(widget = children[i++]){ if(widget.resize){ widget.resize(); } } } }, _isShown: function(){ // summary: // Returns true if the content is currently shown. // description: // If I am a child of a layout widget then it actually returns true if I've ever been visible, // not whether I'm currently visible, since that's much faster than tracing up the DOM/widget // tree every call, and at least solves the performance problem on page load by deferring loading // hidden ContentPanes until they are first shown if(this._childOfLayoutWidget){ // If we are TitlePane, etc - we return that only *IF* we've been resized if(this._resizeCalled && "open" in this){ return this.open; } return this._resizeCalled; }else if("open" in this){ return this.open; // for TitlePane, etc. }else{ var node = this.domNode, parent = this.domNode.parentNode; return (node.style.display != 'none') && (node.style.visibility != 'hidden') && !domClass.contains(node, "dijitHidden") && parent && parent.style && (parent.style.display != 'none'); } }, _onShow: function(){ // summary: // Called when the ContentPane is made visible // description: // For a plain ContentPane, this is called on initialization, from startup(). // If the ContentPane is a hidden pane of a TabContainer etc., then it's // called whenever the pane is made visible. // // Does layout/resize of child widget(s) // Need to keep track of whether ContentPane has been shown (which is different than // whether or not it's currently visible). this._wasShown = true; if(this._needLayout){ // If a layout has been scheduled for when we become visible, do it now this._layout(this._changeSize, this._resultSize); } this.inherited(arguments); } }); });