@qooxdoo/framework
Version:
The JS Framework for Coders
470 lines (405 loc) • 12.9 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://qooxdoo.org/docs/#desktop/widget/slidebar.md' 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(orientation) {
super();
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
*****************************************************************************
*/
/* eslint-disable @qooxdoo/qx/no-refs-in-members */
members: {
/*
---------------------------------------------------------------------------
WIDGET API
---------------------------------------------------------------------------
*/
// overridden
getChildrenContainer() {
return this.getChildControl("content");
},
// overridden
_createChildControlImpl(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 || super._createChildControlImpl(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(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(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(value, old, name) {
super._applyEnabled(value, old, name);
this._updateArrowsEnabled();
},
// property apply
_applyOrientation(value, old) {
// ARIA attrs
this.getContentElement().setAttribute("aria-orientation", value);
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(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() {
this._updateArrowsEnabled();
},
/**
* Handler to fire the 'scrollAnimationEnd' event.
*/
_onScrollAnimationEnd() {
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(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() {
this.scrollBy(-this.getScrollStep());
},
/**
* Scroll handler for right scrolling
*
*/
_onExecuteForward() {
this.scrollBy(this.getScrollStep());
},
/*
---------------------------------------------------------------------------
UTILITIES
---------------------------------------------------------------------------
*/
/**
* Update arrow enabled state
*/
_updateArrowsEnabled() {
// 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() {
this._showChildControl("button-forward");
this._showChildControl("button-backward");
},
/**
* Hide the arrows (Called from resize event)
*
*/
_hideArrows() {
this._excludeChildControl("button-forward");
this._excludeChildControl("button-backward");
this.scrollTo(0);
}
}
});