@qooxdoo/framework
Version:
The JS Framework for Coders
510 lines (422 loc) • 13 kB
JavaScript
/* ************************************************************************
qooxdoo - the new era of web development
http://qooxdoo.org
Copyright:
2004-2008 1&1 Internet AG, Germany, http://www.1und1.de
License:
MIT: https://opensource.org/licenses/MIT
See the LICENSE file in the project's top-level directory for details.
Authors:
* Sebastian Werner (wpbasti)
* Fabian Jakobs (fjakobs)
* Jonathan Weiß (jonathan_rass)
************************************************************************ */
/**
* Container, which provides scrolling in one dimension (vertical or horizontal).
*
* @childControl button-forward {qx.ui.form.RepeatButton} button to step forward
* @childControl button-backward {qx.ui.form.RepeatButton} button to step backward
* @childControl content {qx.ui.container.Composite} container to hold the content
* @childControl scrollpane {qx.ui.core.scroll.ScrollPane} the scroll pane holds the content to enable scrolling
*
* *Example*
*
* Here is a little example of how to use the widget.
*
* <pre class='javascript'>
* // create slide bar container
* slideBar = new qx.ui.container.SlideBar().set({
* width: 300
* });
*
* // set layout
* slideBar.setLayout(new qx.ui.layout.HBox());
*
* // add some widgets
* for (var i=0; i<10; i++)
* {
* slideBar.add((new qx.ui.core.Widget()).set({
* backgroundColor : (i % 2 == 0) ? "red" : "blue",
* width : 60
* }));
* }
*
* this.getRoot().add(slideBar);
* </pre>
*
* This example creates a SlideBar and add some widgets with alternating
* background colors. Since the content is larger than the container, two
* scroll buttons at the left and the right edge are shown.
*
* *External Documentation*
*
* <a href='http://manual.qooxdoo.org/${qxversion}/pages/widget/slidebar.html' target='_blank'>
* Documentation of this widget in the qooxdoo manual.</a>
*/
qx.Class.define("qx.ui.container.SlideBar",
{
extend : qx.ui.core.Widget,
include :
[
qx.ui.core.MRemoteChildrenHandling,
qx.ui.core.MRemoteLayoutHandling
],
/*
*****************************************************************************
CONSTRUCTOR
*****************************************************************************
*/
/**
* @param orientation {String?"horizontal"} The slide bar orientation
*/
construct : function(orientation)
{
this.base(arguments);
var scrollPane = this.getChildControl("scrollpane");
this._add(scrollPane, {flex: 1});
if (orientation != null) {
this.setOrientation(orientation);
} else {
this.initOrientation();
}
this.addListener("roll", this._onRoll, this);
},
/*
*****************************************************************************
PROPERTIES
*****************************************************************************
*/
properties :
{
// overridden
appearance :
{
refine : true,
init : "slidebar"
},
/** Orientation of the bar */
orientation :
{
check : ["horizontal", "vertical"],
init : "horizontal",
apply : "_applyOrientation"
},
/** The number of pixels to scroll if the buttons are pressed */
scrollStep :
{
check : "Integer",
init : 15,
themeable : true
}
},
/*
*****************************************************************************
EVENTS
*****************************************************************************
*/
events :
{
/** Fired on scroll animation end invoked by 'scroll*' methods. */
scrollAnimationEnd : "qx.event.type.Event"
},
/*
*****************************************************************************
MEMBERS
*****************************************************************************
*/
members :
{
/*
---------------------------------------------------------------------------
WIDGET API
---------------------------------------------------------------------------
*/
// overridden
getChildrenContainer : function() {
return this.getChildControl("content");
},
// overridden
_createChildControlImpl : function(id, hash)
{
var control;
switch(id)
{
case "button-forward":
control = new qx.ui.form.RepeatButton;
control.addListener("execute", this._onExecuteForward, this);
control.setFocusable(false);
this._addAt(control, 2);
break;
case "button-backward":
control = new qx.ui.form.RepeatButton;
control.addListener("execute", this._onExecuteBackward, this);
control.setFocusable(false);
this._addAt(control, 0);
break;
case "content":
control = new qx.ui.container.Composite();
this.getChildControl("scrollpane").add(control);
break;
case "scrollpane":
control = new qx.ui.core.scroll.ScrollPane();
control.addListener("update", this._onResize, this);
control.addListener("scrollX", this._onScroll, this);
control.addListener("scrollY", this._onScroll, this);
control.addListener("scrollAnimationEnd", this._onScrollAnimationEnd, this);
break;
}
return control || this.base(arguments, id);
},
// overridden
/**
* @lint ignoreReferenceField(_forwardStates)
*/
_forwardStates :
{
barLeft : true,
barTop : true,
barRight : true,
barBottom : true
},
/*
---------------------------------------------------------------------------
PUBLIC SCROLL API
---------------------------------------------------------------------------
*/
/**
* Scrolls the element's content by the given amount.
*
* @param offset {Integer?0} Amount to scroll
* @param duration {Number?} The time in milliseconds the scroll to should take.
*/
scrollBy : function(offset, duration)
{
var pane = this.getChildControl("scrollpane");
if (this.getOrientation() === "horizontal") {
pane.scrollByX(offset, duration);
} else {
pane.scrollByY(offset, duration);
}
},
/**
* Scrolls the element's content to the given coordinate
*
* @param value {Integer} The position to scroll to.
* @param duration {Number?} The time in milliseconds the scroll to should take.
*/
scrollTo : function(value, duration)
{
var pane = this.getChildControl("scrollpane");
if (this.getOrientation() === "horizontal") {
pane.scrollToX(value, duration);
} else {
pane.scrollToY(value, duration);
}
},
/*
---------------------------------------------------------------------------
PROPERTY APPLY ROUTINES
---------------------------------------------------------------------------
*/
// overridden
_applyEnabled : function(value, old, name) {
this.base(arguments, value, old, name);
this._updateArrowsEnabled();
},
// property apply
_applyOrientation : function(value, old)
{
var oldLayouts = [this.getLayout(), this._getLayout()];
var buttonForward = this.getChildControl("button-forward");
var buttonBackward = this.getChildControl("button-backward");
// old can also be null, so we have to check both explicitly to set
// the states correctly.
if (old == "vertical" && value == "horizontal")
{
buttonForward.removeState("vertical");
buttonBackward.removeState("vertical");
buttonForward.addState("horizontal");
buttonBackward.addState("horizontal");
}
else if (old == "horizontal" && value == "vertical")
{
buttonForward.removeState("horizontal");
buttonBackward.removeState("horizontal");
buttonForward.addState("vertical");
buttonBackward.addState("vertical");
}
if (value == "horizontal")
{
this._setLayout(new qx.ui.layout.HBox());
this.setLayout(new qx.ui.layout.HBox());
}
else
{
this._setLayout(new qx.ui.layout.VBox());
this.setLayout(new qx.ui.layout.VBox());
}
if (oldLayouts[0]) {
oldLayouts[0].dispose();
}
if (oldLayouts[1]) {
oldLayouts[1].dispose();
}
},
/*
---------------------------------------------------------------------------
EVENT LISTENERS
---------------------------------------------------------------------------
*/
/**
* Scrolls pane on roll events
*
* @param e {qx.event.type.Roll} the roll event
*/
_onRoll : function(e)
{
// only wheel and touch
if (e.getPointerType() == "mouse") {
return;
}
var delta = 0;
var pane = this.getChildControl("scrollpane");
if (this.getOrientation() === "horizontal") {
delta = e.getDelta().x;
var position = pane.getScrollX();
var max = pane.getScrollMaxX();
var steps = parseInt(delta);
// pass the event to the parent if both scrollbars are at the end
if (!(
steps < 0 && position <= 0 ||
steps > 0 && position >= max ||
delta == 0)
) {
e.stop();
} else {
e.stopMomentum();
}
} else {
delta = e.getDelta().y;
var position = pane.getScrollY();
var max = pane.getScrollMaxY();
var steps = parseInt(delta);
// pass the event to the parent if both scrollbars are at the end
if (!(
steps < 0 && position <= 0 ||
steps > 0 && position >= max ||
delta == 0
)) {
e.stop();
} else {
e.stopMomentum();
}
}
this.scrollBy(parseInt(delta, 10));
// block all momentum scrolling
if (e.getMomentum()) {
e.stop();
}
},
/**
* Update arrow enabled state after scrolling
*/
_onScroll : function() {
this._updateArrowsEnabled();
},
/**
* Handler to fire the 'scrollAnimationEnd' event.
*/
_onScrollAnimationEnd : function() {
this.fireEvent("scrollAnimationEnd");
},
/**
* Listener for resize event. This event is fired after the
* first flush of the element which leads to another queuing
* when the changes modify the visibility of the scroll buttons.
*
* @param e {Event} Event object
*/
_onResize : function(e)
{
var content = this.getChildControl("scrollpane").getChildren()[0];
if (!content) {
return;
}
var innerSize = this.getInnerSize();
var contentSize = content.getBounds();
var overflow = (this.getOrientation() === "horizontal") ?
contentSize.width > innerSize.width :
contentSize.height > innerSize.height;
if (overflow) {
this._showArrows();
this._updateArrowsEnabled();
} else {
this._hideArrows();
}
},
/**
* Scroll handler for left scrolling
*
*/
_onExecuteBackward : function() {
this.scrollBy(-this.getScrollStep());
},
/**
* Scroll handler for right scrolling
*
*/
_onExecuteForward : function() {
this.scrollBy(this.getScrollStep());
},
/*
---------------------------------------------------------------------------
UTILITIES
---------------------------------------------------------------------------
*/
/**
* Update arrow enabled state
*/
_updateArrowsEnabled : function()
{
// set the disables state directly because we are overriding the
// inheritance
if (!this.getEnabled()) {
this.getChildControl("button-backward").setEnabled(false);
this.getChildControl("button-forward").setEnabled(false);
return;
}
var pane = this.getChildControl("scrollpane");
if (this.getOrientation() === "horizontal")
{
var position = pane.getScrollX();
var max = pane.getScrollMaxX();
}
else
{
var position = pane.getScrollY();
var max = pane.getScrollMaxY();
}
this.getChildControl("button-backward").setEnabled(position > 0);
this.getChildControl("button-forward").setEnabled(position < max);
},
/**
* Show the arrows (Called from resize event)
*
*/
_showArrows : function()
{
this._showChildControl("button-forward");
this._showChildControl("button-backward");
},
/**
* Hide the arrows (Called from resize event)
*
*/
_hideArrows : function()
{
this._excludeChildControl("button-forward");
this._excludeChildControl("button-backward");
this.scrollTo(0);
}
}
});