/* 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: Toolbar.js 616 2013-04-22 23:48:38Z geert $
*/
"use strict";
SUI.Toolbar = SUI.defineClass(
/** @lends SUI.Toolbar.prototype */{
/** @ignore */ baseClass: SUI.Box,
/**
* @class
* SUI.Toolbar is a component that gives you a strip that can contain a
* number of toolbar buttons and possibly other box elements. The actions
* for the buttons can be set individually or provided by an action list.
* In case of too little space, toolbar buttons that are that can't be
* displayed are substituted by a popup menu.
*
* @augments SUI.Box
*
* @description
* Create a toolbar.
*
* @constructs
* @param see base class
* @param {SUI.Box[]} arg.tools An array of box items that will be
* presented on the toolbar. If these boxes also implement 'setAction'
* than the can be initialized from and item of an action list and if
* they implement menuItemData then the will appear on the toolbar's
* sub menu if the tool can't be displayed due to lack of space.
*/
initializer: function(arg) {
// anchor by default not to the bottom
if (!arg.anchor) {
arg.anchor = { right:true,left:true,top:true,bottom:false };
}
// set default height
if (!arg.height) {
arg.height = this.TOOLBAR_HEIGHT;
}
SUI.Toolbar.initializeBase(this, arg);
this.actionList = arg.actionlist || null;
// fix the min and max height to the current height
this.minHeight(this.height());
this.maxHeight(this.height());
// initialize the tools array
this._tools = [];
// loop through all tools in the arguments ...
for (var i=0; i<arg.tools.length; i++) {
// ... and add them to our list ...
this._tools.push(arg.tools[i]);
// ... and as child of the bar ...
arg.tools[i].parent(this);
// ... if the tool could be linked to an action item ...
if (this.actionList && arg.tools[i].setAction) {
// ... then try to do this
arg.tools[i].setAction(this.actionList);
}
}
// add a single line under the toolbar
this.border(new SUI.Border(0, 0, this.TOOLBAR_BORDER_BOTTOM_WIDTH, 0));
this.padding(new SUI.Padding(this.BUTTON_PADDING));
// a toolbar has have a button that shows a popup menu that is shown
// when space is too little for all the other buttons
var that = this;
this.menuButton = new SUI.ToolbarButton({
title: "",
icon: SUI.resource.tbMenu,
handler: function() { that._handleSubMenu(); }
});
this.menuButton.parent(this);
// add the toolbar CSS class
this.addClass("sui-tb-toolbar");
},
/**
* Padding of the buttons on the toolbar
*/
BUTTON_PADDING: 2,
/**
* Width of the border under the toolbar
*/
TOOLBAR_BORDER_BOTTOM_WIDTH: 1,
/**
* Height of the toolbar (including the border)
*/
TOOLBAR_HEIGHT: 31,
/**
* Display the toolbar control. Set the CSS size and position of the
* of the bar and it's tools.
*/
display: function() {
// set the CSS size and position of the bar
this.setDim();
// set the CSS size and position of the (visible) tools
for (var i=0; i < this._menuStart && i < this._tools.length; i++) {
this._tools[i].display();
}
// set the CSS size and position of the sub menu buttom
this.menuButton.setDim();
},
/**
* Lay out the the toolbar. Calculate the sizes and positions of all
* the toolbar and it's tools. Create a sub menu if necessary.
*/
layOut: function() {
// the menu button is not shown by default
this.menuButton.el().style.display = "none";
// start at the left padding distance ...
var left = 0;
// ... and loop through the tools, ...
for (var i=0; i<this._tools.length; i++) {
// ... set the tool's postion ...
this._tools[i].left(left);
// ... layout the tool ...
this._tools[i].layOut();
// ... and show it ...
this._tools[i].el().style.display = "block";
// increase current left with the with of the button and the
// toolbar button
left += this._tools[i].width() + this.BUTTON_PADDING;
}
// find offscreen buttons
this._menuStart = this._tools.length;
// is the total tool's width larger than the toobar itself ?
if (left > this.width()) {
// yes, then walk down ...
for (i=this._tools.length-1; i>0; i--) {
// ... and decrease the left ...
left -= this._tools[i].width() + this.BUTTON_PADDING;
// ... until there is space for our sub menu button
if (left < this.width() - this.menuButton.width()) {
break;
}
}
// save the index of the first offscreen tool ...
this._menuStart = i;
// ...and hide the offscreen tools
for (; i < this._tools.length; i++) {
this._tools[i].el().style.display = "none";
}
// set the position of the sub menu button ...
this.menuButton.left(this.clientWidth() - this.menuButton.width());
// ... and display it
this.menuButton.el().style.display = "block";
}
},
// index of first offscreen item to add the the sub menu
_menuStart: 0,
// reference to the submenu (if it's active)
_subMenu: null,
// the tools array
_tools: null,
/* Create a sub menu form the currently ofscreen items, or remove it
* if was already created.
*/
_handleSubMenu: function() {
// if there was a sub menu created already ...
if (this._subMenu) {
// ... remove it ...
this._subMenu.removeMenu();
this._subMenu = null;
} else {
// ... else create it, set the button to pressed first, ...
this.menuButton.select(true);
// ... create an array with menu item information from the
// undisplayed buttons ...
var items = [];
for (var i=this._menuStart; i<this._tools.length; i++) {
if (this._tools[i].menuItemData) {
var item = this._tools[i].menuItemData();
items.push(item);
}
}
// ... and create the sub menu
this._subMenu = new SUI.PopupMenu({
actionlist: this.actionList,
items: items
});
// clear our reference to the menu if the menu is removed by
// an other UI action and 'un-press' the button
var that = this;
this._subMenu.addListener("onRemoveMenu",
function() {
that._subMenu = null;
that.menuButton.select(false);
}
);
// now show the menu right under the button
var p = this.menuButton.absPos();
this._subMenu.showMenu(p.t+this.menuButton.height() -1, p.l -1);
}
}
});