/* Copyright (c) 2011, Geert Bergman (geert@scrivo.nl)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of "Scrivo" nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $Id: AnchorLayout.js 738 2013-07-12 18:38:39Z geert $
*/
"use strict";
SUI.AnchorLayout = SUI.defineClass(
/** @lends SUI.AnchorLayout.prototype */{
/** @ignore */ baseClass: SUI.Box,
/**
* @class
* <p>SUI.AnchorLayout is the the component that handles the layout of
* anchored boxes. Anchoring means that child boxes can be positioned
* relative to the edges of the anchor layout box.
* </p>
* <p>Suppose you have an input field with a label. In this situation
* the label has a fixed size and if the form is enlarged and you only
* want the input field to resize.
* </p>
* <p>This is easy to accomplish with an anchor layout. The label will
* have a fixed width and will be anchored to the left side of the
* container box (an instance of SUI.AnchorLayout). The input field will
* be anchored on the left and right of the container box, setting the
* left to a value slightly larger that the right side of the label and
* the right to zero. When resizing the container the label will always
* be shown at its fixed width and the rest of the width will be used
* for the input field.
* </p>
* <p>Or in code:</p>
* var b = new SUI.AnchorLayout({
* top: 10, left 10, width: 800, height: 800
*
*
*
* can contain other box elements. It is essentially nothing more than a
* SUI.Box with a list of children. It knows how to deal with anchored
* boxes.
*
* @augments SUI.Box
*
* @description
* Construct a SUI.AnchorLayout component.
*
* @constructs
* @param see base class
*/
initializer: function(arg) {
// anchors default to all sides
if (!arg.anchor) {
arg.anchor = {left:true,right:true,top:true,bottom:true};
}
SUI.AnchorLayout.initializeBase(this, arg);
// start with an empty children's list
this.children = [];
},
/**
* The list of children of this container.
* @type SUI.Box[]
* @deprecated Will be moved to a getter setter function
*/
children: null,
/**
* Add an box to the container. Add it to the document tree and to
* the container's list of children.
* @param {SUI.AnchorLayout} child box to add
* @param {SUI.AnchorLayout} parent Container to add box to (none for this)
*/
add: function(child, parent) {
this.children.push(child);
child.parent(parent || this);
},
/**
* Display the Container. Set the CSS positions of the element's box(es)
* and for the children of the box.
*/
display: function() {
SUI.AnchorLayout.parentMethod(this, "display");
for (var i=0; i<this.children.length; i++) {
this.children[i].display();
}
},
/**
* Lay out the Container. Calculate the position of the Container and
* it's contents.
*/
layOut: function() {
// call layOut for the children of the Container
this._layoutChildren();
},
/**
* Remove a child box.
* @param {SUI.Box} child a reference to the box to remove
* @param {SUI.AnchorLayout} parent Container to remove box from (none for
* this)
*/
remove: function(child, parent) {
// Find the index in the list of child containers
var i = this.children.indexOf(child);
// none found is an error
if (i === -1) {
throw "Trying to remove a nonexisting SUI.AnchorLayout";
}
// Remove it form the DOM tree ...
(parent || this).el().removeChild(child.el());
// ... and from the list
this.children.splice(i,1);
},
/**
* Layout the children of the Container. Use the anchors of the children to
* place them on the client area of the Container.
* @private
*/
_layoutChildren: function() {
for (var i=0; i<this.children.length; i++) {
var c = this.children[i];
// do the width calculation using the left and right anchors and
// the available client width
if (c.anchor.left && c.anchor.right) {
c.width(c.parent().clientWidth() - c.left() - c.right());
} else if (c.anchor.right) {
c.left(c.parent().clientWidth() - c.width() - c.right());
} else if (c.anchor.left) {
c.right(c.parent().clientWidth() - c.width() - c.left());
}
// do the height calculation using of the top and bottom anchors
// and the available client height
if (c.anchor.top && c.anchor.bottom) {
c.height(c.parent().clientHeight() - c.top() - c.bottom());
} else if (c.anchor.bottom) {
c.top(c.parent().clientHeight() - c.height() - c.bottom());
} else if (c.anchor.top) {
c.bottom(c.parent().clientHeight() - c.height() - c.top());
}
// now do the child's layOut
c.layOut();
}
}
});