UNPKG

@qooxdoo/framework

Version:

The JS Framework for Coders

487 lines (390 loc) 12.4 kB
/* ************************************************************************ 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) ************************************************************************ */ /** * The scroll bar widget, is a special slider, which is used in qooxdoo instead * of the native browser scroll bars. * * Scroll bars are used by the {@link qx.ui.container.Scroll} container. Usually * a scroll bar is not used directly. * * @childControl slider {qx.ui.core.scroll.ScrollSlider} scroll slider component * @childControl button-begin {qx.ui.form.RepeatButton} button to scroll to top * @childControl button-end {qx.ui.form.RepeatButton} button to scroll to bottom * * *Example* * * Here is a little example of how to use the widget. * * <pre class='javascript'> * var scrollBar = new qx.ui.core.scroll.ScrollBar("horizontal"); * scrollBar.set({ * maximum: 500 * }) * this.getRoot().add(scrollBar); * </pre> * * This example creates a horizontal scroll bar with a maximum value of 500. * * *External Documentation* * * <a href='http://manual.qooxdoo.org/${qxversion}/pages/widget/scrollbar.html' target='_blank'> * Documentation of this widget in the qooxdoo manual.</a> */ qx.Class.define("qx.ui.core.scroll.ScrollBar", { extend : qx.ui.core.Widget, implement : qx.ui.core.scroll.IScrollBar, /* ***************************************************************************** CONSTRUCTOR ***************************************************************************** */ /** * @param orientation {String?"horizontal"} The initial scroll bar orientation */ construct : function(orientation) { this.base(arguments); // Create child controls this._createChildControl("button-begin"); this._createChildControl("slider").addListener("resize", this._onResizeSlider, this); this._createChildControl("button-end"); // Configure orientation if (orientation != null) { this.setOrientation(orientation); } else { this.initOrientation(); } // prevent drag & drop on scrolling this.addListener("track", function(e) { e.stopPropagation(); }, this); }, events : { /** Change event for the value. */ "scrollAnimationEnd": "qx.event.type.Event" }, /* ***************************************************************************** PROPERTIES ***************************************************************************** */ properties : { // overridden appearance : { refine : true, init : "scrollbar" }, /** * The scroll bar orientation */ orientation : { check : [ "horizontal", "vertical" ], init : "horizontal", apply : "_applyOrientation" }, /** * The maximum value (difference between available size and * content size). */ maximum : { check : "PositiveInteger", apply : "_applyMaximum", init : 100 }, /** * Position of the scrollbar (which means the scroll left/top of the * attached area's pane) * * Strictly validates according to {@link #maximum}. * Does not apply any correction to the incoming value. If you depend * on this, please use {@link #scrollTo} instead. */ position : { check : "qx.lang.Type.isNumber(value)&&value>=0&&value<=this.getMaximum()", init : 0, apply : "_applyPosition", event : "scroll" }, /** * Step size for each tap on the up/down or left/right buttons. */ singleStep : { check : "Integer", init : 20 }, /** * The amount to increment on each event. Typically corresponds * to the user pressing <code>PageUp</code> or <code>PageDown</code>. */ pageStep : { check : "Integer", init : 10, apply : "_applyPageStep" }, /** * Factor to apply to the width/height of the knob in relation * to the dimension of the underlying area. */ knobFactor : { check : "PositiveNumber", apply : "_applyKnobFactor", nullable : true } }, /* ***************************************************************************** MEMBERS ***************************************************************************** */ members : { __offset : 2, __originalMinSize : 0, // overridden _computeSizeHint : function() { var hint = this.base(arguments); if (this.getOrientation() === "horizontal") { this.__originalMinSize = hint.minWidth; hint.minWidth = 0; } else { this.__originalMinSize = hint.minHeight; hint.minHeight = 0; } return hint; }, // overridden renderLayout : function(left, top, width, height) { var changes = this.base(arguments, left, top, width, height); var horizontal = this.getOrientation() === "horizontal"; if (this.__originalMinSize >= (horizontal ? width : height)) { this.getChildControl("button-begin").setVisibility("hidden"); this.getChildControl("button-end").setVisibility("hidden"); } else { this.getChildControl("button-begin").setVisibility("visible"); this.getChildControl("button-end").setVisibility("visible"); } return changes; }, // overridden _createChildControlImpl : function(id, hash) { var control; switch(id) { case "slider": control = new qx.ui.core.scroll.ScrollSlider(); control.setPageStep(100); control.setFocusable(false); control.addListener("changeValue", this._onChangeSliderValue, this); control.addListener("slideAnimationEnd", this._onSlideAnimationEnd, this); this._add(control, {flex: 1}); break; case "button-begin": // Top/Left Button control = new qx.ui.form.RepeatButton(); control.setFocusable(false); control.addListener("execute", this._onExecuteBegin, this); this._add(control); break; case "button-end": // Bottom/Right Button control = new qx.ui.form.RepeatButton(); control.setFocusable(false); control.addListener("execute", this._onExecuteEnd, this); this._add(control); break; } return control || this.base(arguments, id); }, /* --------------------------------------------------------------------------- PROPERTY APPLY ROUTINES --------------------------------------------------------------------------- */ // property apply _applyMaximum : function(value) { this.getChildControl("slider").setMaximum(value); }, // property apply _applyPosition : function(value) { this.getChildControl("slider").setValue(value); }, // property apply _applyKnobFactor : function(value) { this.getChildControl("slider").setKnobFactor(value); }, // property apply _applyPageStep : function(value) { this.getChildControl("slider").setPageStep(value); }, // property apply _applyOrientation : function(value, old) { // Dispose old layout var oldLayout = this._getLayout(); if (oldLayout) { oldLayout.dispose(); } // Reconfigure if (value === "horizontal") { this._setLayout(new qx.ui.layout.HBox()); this.setAllowStretchX(true); this.setAllowStretchY(false); this.replaceState("vertical", "horizontal"); this.getChildControl("button-begin").replaceState("up", "left"); this.getChildControl("button-end").replaceState("down", "right"); } else { this._setLayout(new qx.ui.layout.VBox()); this.setAllowStretchX(false); this.setAllowStretchY(true); this.replaceState("horizontal", "vertical"); this.getChildControl("button-begin").replaceState("left", "up"); this.getChildControl("button-end").replaceState("right", "down"); } // Sync slider orientation this.getChildControl("slider").setOrientation(value); }, /* --------------------------------------------------------------------------- METHOD REDIRECTION TO SLIDER --------------------------------------------------------------------------- */ /** * Scrolls to the given position. * * This method automatically corrects the given position to respect * the {@link #maximum}. * * @param position {Integer} Scroll to this position. Must be greater zero. * @param duration {Number} The time in milliseconds the slide to should take. */ scrollTo : function(position, duration) { this.getChildControl("slider").slideTo(position, duration); }, /** * Scrolls by the given offset. * * This method automatically corrects the given position to respect * the {@link #maximum}. * * @param offset {Integer} Scroll by this offset * @param duration {Number} The time in milliseconds the slide to should take. */ scrollBy : function(offset, duration) { this.getChildControl("slider").slideBy(offset, duration); }, /** * Scrolls by the given number of steps. * * This method automatically corrects the given position to respect * the {@link #maximum}. * * @param steps {Integer} Number of steps * @param duration {Number} The time in milliseconds the slide to should take. */ scrollBySteps : function(steps, duration) { var size = this.getSingleStep(); this.getChildControl("slider").slideBy(steps * size, duration); }, /** * Updates the position property considering the minimum and maximum values. * @param position {Number} The new position. */ updatePosition : function(position) { this.getChildControl("slider").updatePosition(position); }, /** * If a scroll animation is running, it will be stopped. */ stopScrollAnimation : function() { this.getChildControl("slider").stopSlideAnimation(); }, /* --------------------------------------------------------------------------- EVENT LISTENER --------------------------------------------------------------------------- */ /** * Executed when the up/left button is executed (pressed) * * @param e {qx.event.type.Event} Execute event of the button */ _onExecuteBegin : function(e) { this.scrollBy(-this.getSingleStep(), 50); }, /** * Executed when the down/right button is executed (pressed) * * @param e {qx.event.type.Event} Execute event of the button */ _onExecuteEnd : function(e) { this.scrollBy(this.getSingleStep(), 50); }, /** * Change listener for slider animation end. */ _onSlideAnimationEnd : function() { this.fireEvent("scrollAnimationEnd"); }, /** * Change listener for slider value changes. * * @param e {qx.event.type.Data} The change event object */ _onChangeSliderValue : function(e) { this.setPosition(e.getData()); }, /** * Hide the knob of the slider if the slidebar is too small or show it * otherwise. * * @param e {qx.event.type.Data} event object */ _onResizeSlider : function(e) { var knob = this.getChildControl("slider").getChildControl("knob"); var knobHint = knob.getSizeHint(); var hideKnob = false; var sliderSize = this.getChildControl("slider").getInnerSize(); if (this.getOrientation() == "vertical") { if (sliderSize.height < knobHint.minHeight + this.__offset) { hideKnob = true; } } else { if (sliderSize.width < knobHint.minWidth + this.__offset) { hideKnob = true; } } if (hideKnob) { knob.exclude(); } else { knob.show(); } } } });