UNPKG

@qooxdoo/framework

Version:

The JS Framework for Coders

410 lines (327 loc) 10.2 kB
/* ************************************************************************ qooxdoo - the new era of web development http://qooxdoo.org Copyright: 2009 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: * Fabian Jakobs (fjakobs) ************************************************************************ */ /** * The scroll bar widget wraps the native browser scroll bars as a qooxdoo widget. * It can be uses instead of the styled qooxdoo scroll bars. * * Scroll bars are used by the {@link qx.ui.container.Scroll} container. Usually * a scroll bar is not used directly. * * *Example* * * Here is a little example of how to use the widget. * * <pre class='javascript'> * var scrollBar = new qx.ui.core.scroll.NativeScrollBar("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.NativeScrollBar", { extend : qx.ui.core.Widget, implement : qx.ui.core.scroll.IScrollBar, /** * @param orientation {String?"horizontal"} The initial scroll bar orientation */ construct : function(orientation) { this.base(arguments); this.addState("native"); this.getContentElement().addListener("scroll", this._onScroll, this); this.addListener("pointerdown", this._stopPropagation, this); this.addListener("pointerup", this._stopPropagation, this); this.addListener("pointermove", this._stopPropagation, this); this.addListener("appear", this._onAppear, this); this.getContentElement().add(this._getScrollPaneElement()); this.getContentElement().setStyle("box-sizing", "content-box"); // 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 : { /** * Fired as soon as the scroll animation ended. */ scrollAnimationEnd: 'qx.event.type.Event' }, properties : { // overridden appearance : { refine : true, init : "scrollbar" }, // interface implementation orientation : { check : [ "horizontal", "vertical" ], init : "horizontal", apply : "_applyOrientation" }, // interface implementation maximum : { check : "PositiveInteger", apply : "_applyMaximum", init : 100 }, // interface implementation position : { check : "Number", init : 0, apply : "_applyPosition", event : "scroll" }, /** * Step size for each tap on the up/down or left/right buttons. */ singleStep : { check : "Integer", init : 20 }, // interface implementation knobFactor : { check : "PositiveNumber", nullable : true } }, members : { __isHorizontal : null, __scrollPaneElement : null, __requestId : null, __scrollAnimationframe : null, /** * Get the scroll pane html element. * * @return {qx.html.Element} The element */ _getScrollPaneElement : function() { if (!this.__scrollPaneElement) { this.__scrollPaneElement = new qx.html.Element(); } return this.__scrollPaneElement; }, /* --------------------------------------------------------------------------- WIDGET API --------------------------------------------------------------------------- */ // overridden renderLayout : function(left, top, width, height) { var changes = this.base(arguments, left, top, width, height); this._updateScrollBar(); return changes; }, // overridden _getContentHint : function() { var scrollbarWidth = qx.bom.element.Scroll.getScrollbarWidth(); return { width: this.__isHorizontal ? 100 : scrollbarWidth, maxWidth: this.__isHorizontal ? null : scrollbarWidth, minWidth: this.__isHorizontal ? null : scrollbarWidth, height: this.__isHorizontal ? scrollbarWidth : 100, maxHeight: this.__isHorizontal ? scrollbarWidth : null, minHeight: this.__isHorizontal ? scrollbarWidth : null }; }, // overridden _applyEnabled : function(value, old) { this.base(arguments, value, old); this._updateScrollBar(); }, /* --------------------------------------------------------------------------- PROPERTY APPLY ROUTINES --------------------------------------------------------------------------- */ // property apply _applyMaximum : function(value) { this._updateScrollBar(); }, // property apply _applyPosition : function(value) { var content = this.getContentElement(); if (this.__isHorizontal) { content.scrollToX(value); } else { content.scrollToY(value); } }, // property apply _applyOrientation : function(value, old) { var isHorizontal = this.__isHorizontal = value === "horizontal"; this.set({ allowGrowX : isHorizontal, allowShrinkX : isHorizontal, allowGrowY : !isHorizontal, allowShrinkY : !isHorizontal }); if (isHorizontal) { this.replaceState("vertical", "horizontal"); } else { this.replaceState("horizontal", "vertical"); } this.getContentElement().setStyles({ overflowX: isHorizontal ? "scroll" : "hidden", overflowY: isHorizontal ? "hidden" : "scroll" }); // Update layout qx.ui.core.queue.Layout.add(this); }, /** * Update the scroll bar according to its current size, max value and * enabled state. */ _updateScrollBar : function() { var isHorizontal = this.__isHorizontal; var bounds = this.getBounds(); if (!bounds) { return; } if (this.isEnabled()) { var containerSize = isHorizontal ? bounds.width : bounds.height; var innerSize = this.getMaximum() + containerSize; } else { innerSize = 0; } // Scrollbars don't work properly in IE/Edge if the element with overflow has // exactly the size of the scrollbar. Thus we move the element one pixel // out of the view and increase the size by one. if (qx.core.Environment.get("engine.name") == "mshtml" || qx.core.Environment.get("browser.name") == "edge") { var bounds = this.getBounds(); this.getContentElement().setStyles({ left: (isHorizontal ? bounds.left : (bounds.left -1)) + "px", top: (isHorizontal ? (bounds.top - 1) : bounds.top) + "px", width: (isHorizontal ? bounds.width : bounds.width + 1) + "px", height: (isHorizontal ? bounds.height + 1 : bounds.height) + "px" }); } this._getScrollPaneElement().setStyles({ left: 0, top: 0, width: (isHorizontal ? innerSize : 1) + "px", height: (isHorizontal ? 1 : innerSize) + "px" }); this.updatePosition(this.getPosition()); }, // interface implementation scrollTo : function(position, duration) { // if a user sets a new position, stop any animation this.stopScrollAnimation(); if (duration) { var from = this.getPosition(); this.__scrollAnimationframe = new qx.bom.AnimationFrame(); this.__scrollAnimationframe.on("frame", function(timePassed) { var newPos = parseInt(timePassed/duration * (position - from) + from); this.updatePosition(newPos); }, this); this.__scrollAnimationframe.on("end", function() { this.setPosition(Math.max(0, Math.min(this.getMaximum(), position))); this.__scrollAnimationframe = null; this.fireEvent("scrollAnimationEnd"); }, this); this.__scrollAnimationframe.startSequence(duration); } else { this.updatePosition(position); } }, /** * Helper to set the new position taking care of min and max values. * @param position {Number} The new position. */ updatePosition : function(position) { this.setPosition(Math.max(0, Math.min(this.getMaximum(), position))); }, // interface implementation scrollBy : function(offset, duration) { this.scrollTo(this.getPosition() + offset, duration); }, // interface implementation scrollBySteps : function(steps, duration) { var size = this.getSingleStep(); this.scrollBy(steps * size, duration); }, /** * If a scroll animation is running, it will be stopped. */ stopScrollAnimation : function() { if (this.__scrollAnimationframe) { this.__scrollAnimationframe.cancelSequence(); this.__scrollAnimationframe = null; } }, /** * Scroll event handler * * @param e {qx.event.type.Event} the scroll event */ _onScroll : function(e) { var container = this.getContentElement(); var position = this.__isHorizontal ? container.getScrollX() : container.getScrollY(); this.setPosition(position); }, /** * Listener for appear which ensured the scroll bar is positioned right * on appear. * * @param e {qx.event.type.Data} Incoming event object */ _onAppear : function(e) { this._applyPosition(this.getPosition()); }, /** * Stops propagation on the given even * * @param e {qx.event.type.Event} the event */ _stopPropagation : function(e) { e.stopPropagation(); } }, destruct : function() { this._disposeObjects("__scrollPaneElement"); } });