| Index: client/touch/Scrollbar.dart
|
| ===================================================================
|
| --- client/touch/Scrollbar.dart (revision 4144)
|
| +++ client/touch/Scrollbar.dart (working copy)
|
| @@ -1,352 +0,0 @@
|
| -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
|
| -// for details. All rights reserved. Use of this source code is governed by a
|
| -// BSD-style license that can be found in the LICENSE file.
|
| -
|
| -/**
|
| - * Implementation of a scrollbar for the custom scrolling behavior
|
| - * defined in [:Scroller:].
|
| - */
|
| -class Scrollbar implements ScrollListener {
|
| - /**
|
| - * The minimum size of scrollbars when not compressed.
|
| - */
|
| - static final _MIN_SIZE = 30;
|
| -
|
| - /**
|
| - * The minimum compressed size of scrollbars. Scrollbars are compressed when
|
| - * the content is stretching past its boundaries.
|
| - */
|
| - static final _MIN_COMPRESSED_SIZE = 8;
|
| - /** Padding in pixels to add above and bellow the scrollbar. */
|
| - static final _PADDING_LENGTH = 10;
|
| - /**
|
| - * The amount of time to wait before hiding scrollbars after showing them.
|
| - * Measured in ms.
|
| - */
|
| - static final _DISPLAY_TIME = 300;
|
| - static final DRAG_CLASS_NAME = 'drag';
|
| -
|
| - Scroller _scroller;
|
| - Element _frame;
|
| - bool _scrollInProgress = false;
|
| - bool _scrollBarDragInProgressValue = false;
|
| -
|
| - /**
|
| - * Cached values of height and width. Keys will be 'height' and 'width'
|
| - * depending on if they are applied to vertical or horizontal scrollbar.
|
| - */
|
| - Map<String, num> _cachedSize;
|
| -
|
| - /**
|
| - * This bound function will be used as the input to window.setTimeout when
|
| - * scheduling the hiding of the scrollbars.
|
| - */
|
| - Function _boundHideFn;
|
| -
|
| - Element _verticalElement;
|
| - Element _horizontalElement;
|
| -
|
| - int _currentScrollStartMouse;
|
| - num _currentScrollStartOffset;
|
| - bool _currentScrollVertical;
|
| - num _currentScrollRatio;
|
| - num _timerId;
|
| -
|
| - bool _displayOnHover;
|
| - bool _hovering = false;
|
| -
|
| - Scrollbar(Scroller scroller, [displayOnHover = true]) :
|
| - _displayOnHover = displayOnHover,
|
| - _scroller = scroller,
|
| - _frame = scroller.getFrame(),
|
| - _cachedSize = new Map<String, num>() {
|
| - _boundHideFn = () { _showScrollbars(false); };
|
| - }
|
| -
|
| - bool get _scrollBarDragInProgress() => _scrollBarDragInProgressValue;
|
| -
|
| - void set _scrollBarDragInProgress(bool value) {
|
| - _scrollBarDragInProgressValue = value;
|
| - _toggleClass(_verticalElement, DRAG_CLASS_NAME,
|
| - value && _currentScrollVertical);
|
| - _toggleClass(_horizontalElement, DRAG_CLASS_NAME,
|
| - value && !_currentScrollVertical);
|
| - }
|
| -
|
| - // TODO(jacobr): move this helper method into the DOM.
|
| - void _toggleClass(Element e, String className, bool enabled) {
|
| - if (enabled) {
|
| - if (!e.classes.contains(className)) {
|
| - e.classes.add(className);
|
| - }
|
| - } else {
|
| - e.classes.remove(className);
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Initializes elements and event handlers. Must be called after
|
| - * construction and before usage.
|
| - */
|
| - void initialize() {
|
| - // Don't initialize if we have already been initialized.
|
| - // TODO(jacobr): remove this once bugs are fixed and enterDocument is only
|
| - // called once by each view.
|
| - if (_verticalElement != null) {
|
| - return;
|
| - }
|
| - _verticalElement = new Element.html(
|
| - '<div class="touch-scrollbar touch-scrollbar-vertical"></div>');
|
| - _horizontalElement = new Element.html(
|
| - '<div class="touch-scrollbar touch-scrollbar-horizontal"></div>');
|
| - _scroller.addScrollListener(this);
|
| -
|
| - Element scrollerEl = _scroller.getElement();
|
| -
|
| - if (!Device.supportsTouch) {
|
| - _addEventListeners(
|
| - _verticalElement, _onStart, _onMove, _onEnd, _onEnd, true);
|
| - _addEventListeners(
|
| - _horizontalElement, _onStart, _onMove, _onEnd, _onEnd, true);
|
| - }
|
| -
|
| - _scroller.addScrollListener(this);
|
| - _showScrollbars(false);
|
| - _scroller.onScrollerStart.add(_onScrollerStart);
|
| - _scroller.onScrollerEnd.add(_onScrollerEnd);
|
| - if (_displayOnHover) {
|
| - // TODO(jacobr): rather than adding all these event listeners we could
|
| - // instead attach a single global event listener and let data in the
|
| - // DOM drive.
|
| - _frame.on.click.add((Event e) {
|
| - // Always focus on click as one of our children isn't all focused.
|
| - if (!_frame.contains(document.activeElement)) {
|
| - scrollerEl.focus();
|
| - }
|
| - }, false);
|
| - _frame.on.mouseOver.add((Event e) {
|
| - final activeElement = document.activeElement;
|
| - // TODO(jacobr): don't steal focus from a child element or a truly
|
| - // focusable element. Only support stealing focus ffrom another
|
| - // element that was given fake focus.
|
| - if (activeElement is BodyElement ||
|
| - (!_frame.contains(activeElement) &&
|
| - activeElement is DivElement)) {
|
| - scrollerEl.focus();
|
| - }
|
| - if (_hovering == false) {
|
| - _hovering = true;
|
| - _cancelTimeout();
|
| - _showScrollbars(true);
|
| - refresh();
|
| - }
|
| - }, false);
|
| - _frame.on.mouseOut.add((e) {
|
| - _hovering = false;
|
| - // Start hiding immediately if we aren't
|
| - // scrolling or already in the process of
|
| - // hidng the scrollbar
|
| - if (!_scrollInProgress && _timerId == null) {
|
| - _boundHideFn();
|
| - }
|
| - }, false);
|
| - }
|
| - }
|
| -
|
| - void _onStart(UIEvent e) {
|
| - Element elementOver = e.target;
|
| - if (elementOver == _verticalElement ||
|
| - elementOver == _horizontalElement) {
|
| - _currentScrollVertical = elementOver == _verticalElement;
|
| - if (_currentScrollVertical) {
|
| - _currentScrollStartMouse = e.pageY;
|
| - _currentScrollStartOffset = _scroller.getVerticalOffset();
|
| - } else {
|
| - _currentScrollStartMouse = e.pageX;
|
| - _currentScrollStartOffset = _scroller.getHorizontalOffset();
|
| - }
|
| - _refreshScrollRatio();
|
| - _scrollBarDragInProgress = true;
|
| - _scroller._momentum.abort();
|
| - e.stopPropagation();
|
| - }
|
| - }
|
| -
|
| - void _refreshScrollRatio() {
|
| - Size contentSize = _scroller._getAdjustedContentSize();
|
| - if (_currentScrollVertical) {
|
| - _refreshScrollRatioHelper(
|
| - _scroller._scrollSize.height, contentSize.height);
|
| - } else {
|
| - _refreshScrollRatioHelper(_scroller._scrollSize.width,
|
| - contentSize.width);
|
| - }
|
| - }
|
| -
|
| -
|
| - void _refreshScrollRatioHelper(num frameSize, num contentSize) {
|
| - num frameTravelDistance = frameSize - _defaultScrollSize(
|
| - frameSize, contentSize) -_PADDING_LENGTH * 2;
|
| - if (frameTravelDistance < 0.001) {
|
| - _currentScrollRatio = 0;
|
| - } else {
|
| - _currentScrollRatio = (contentSize - frameSize) / frameTravelDistance;
|
| - }
|
| - }
|
| -
|
| - void _onMove(UIEvent e) {
|
| - if (!_scrollBarDragInProgress) {
|
| - return;
|
| - }
|
| - _refreshScrollRatio();
|
| - int coordinate = _currentScrollVertical ? e.pageY : e.pageX;
|
| - num delta = (coordinate - _currentScrollStartMouse) * _currentScrollRatio;
|
| - if (delta != 0) {
|
| - num x;
|
| - num y;
|
| - _currentScrollStartOffset -= delta;
|
| - if (_currentScrollVertical) {
|
| - x = _scroller.getHorizontalOffset();
|
| - y = _currentScrollStartOffset.toInt();
|
| - } else {
|
| - x = _currentScrollStartOffset.toInt();
|
| - y = _scroller.getVerticalOffset();
|
| - }
|
| - _scroller.setPosition(x, y);
|
| - }
|
| - _currentScrollStartMouse = coordinate;
|
| - }
|
| -
|
| - void _onEnd(UIEvent e) {
|
| - _scrollBarDragInProgress = false;
|
| - // TODO(jacobr): make scrollbar less tightly coupled to the scroller.
|
| - _scroller.onScrollerDragEnd.dispatch(
|
| - new Event(ScrollerEventType.DRAG_END));
|
| - }
|
| -
|
| -
|
| - /**
|
| - * When scrolling ends, schedule a timeout to hide the scrollbars.
|
| - */
|
| - void _onScrollerEnd(Event e) {
|
| - _cancelTimeout();
|
| - _timerId = window.setTimeout(_boundHideFn, _DISPLAY_TIME);
|
| - _scrollInProgress = false;
|
| - }
|
| - void onScrollerMoved(num scrollX, num scrollY, bool decelerating) {
|
| - if (_scrollInProgress == false) {
|
| - // Display the scrollbar and then immediately prepare to hide it...
|
| - _onScrollerStart(null);
|
| - _onScrollerEnd(null);
|
| - }
|
| - updateScrollbars(scrollX, scrollY);
|
| - }
|
| -
|
| - void refresh() {
|
| - if (_scrollInProgress == false && _hovering == false) {
|
| - // No need to refresh if not visible.
|
| - return;
|
| - }
|
| - _scroller._resize(() {
|
| - updateScrollbars(_scroller.getHorizontalOffset(),
|
| - _scroller.getVerticalOffset());
|
| - });
|
| - }
|
| -
|
| - void updateScrollbars(num scrollX, num scrollY) {
|
| - Size contentSize = _scroller._getAdjustedContentSize();
|
| - if (_scroller._shouldScrollHorizontally()) {
|
| - num scrollPercentX = _scroller.getHorizontalScrollPercent(scrollX);
|
| - _updateScrollbar(_horizontalElement, scrollX, scrollPercentX,
|
| - _scroller._scrollSize.width,
|
| - contentSize.width, 'right', 'width');
|
| - }
|
| - if (_scroller._shouldScrollVertically()) {
|
| - num scrollPercentY = _scroller.getVerticalScrollPercent(scrollY);
|
| - _updateScrollbar(_verticalElement, scrollY, scrollPercentY,
|
| - _scroller._scrollSize.height,
|
| - contentSize.height, 'bottom', 'height');
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * When scrolling starts, show scrollbars and clear hide intervals.
|
| - */
|
| - void _onScrollerStart(Event e) {
|
| - _scrollInProgress = true;
|
| - _cancelTimeout();
|
| - _showScrollbars(true);
|
| - }
|
| -
|
| - void _cancelTimeout() {
|
| - if (_timerId != null) {
|
| - window.clearTimeout(_timerId);
|
| - _timerId = null;
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Show or hide the scrollbars by changing the opacity.
|
| - */
|
| - void _showScrollbars(bool show) {
|
| - if (_hovering == true && _displayOnHover) {
|
| - show = true;
|
| - }
|
| - _toggleOpacity(_verticalElement, show);
|
| - _toggleOpacity(_horizontalElement, show);
|
| - }
|
| -
|
| - _toggleOpacity(Element element, bool show) {
|
| - if (show) {
|
| - element.style.removeProperty("opacity");
|
| - } else {
|
| - element.style.opacity = '0';
|
| - }
|
| - }
|
| -
|
| - num _defaultScrollSize(num frameSize, num contentSize) {
|
| - return GoogleMath.clamp(
|
| - (frameSize -_PADDING_LENGTH * 2) * frameSize / contentSize,
|
| - _MIN_SIZE, frameSize -_PADDING_LENGTH * 2);
|
| - }
|
| -
|
| - /**
|
| - * Update the vertical or horizontal scrollbar based on the new scroll
|
| - * properties. The CSS property to adjust for position (bottom|right) is
|
| - * specified by [cssPos]. The CSS property to adjust for size (height|width)
|
| - * is specified by [cssSize].
|
| - */
|
| - void _updateScrollbar(Element element, num offset,
|
| - num scrollPercent, num frameSize,
|
| - num contentSize, String cssPos, String cssSize) {
|
| - if (!_cachedSize.containsKey(cssSize)) {
|
| - if (offset == null || contentSize < frameSize) {
|
| - return;
|
| - }
|
| - _frame.nodes.add(element);
|
| - }
|
| - num stretchPercent;
|
| - if (scrollPercent > 1) {
|
| - stretchPercent = scrollPercent - 1;
|
| - } else {
|
| - stretchPercent = scrollPercent < 0 ? -scrollPercent : 0;
|
| - }
|
| - num scrollPx = stretchPercent * (contentSize - frameSize);
|
| - num maxSize = _defaultScrollSize(frameSize, contentSize);
|
| - num size = Math.max(_MIN_COMPRESSED_SIZE, maxSize - scrollPx);
|
| - num maxOffset = frameSize - size -_PADDING_LENGTH * 2;
|
| - num pos = GoogleMath.clamp(scrollPercent * maxOffset,
|
| - 0, maxOffset) + _PADDING_LENGTH;
|
| - pos = pos.round();
|
| - size = size.round();
|
| - final style = element.style;
|
| - style.setProperty(cssPos, '${pos}px', '');
|
| - if (_cachedSize[cssSize] != size) {
|
| - _cachedSize[cssSize] = size;
|
| - style.setProperty(cssSize, '${size}px', '');
|
| - }
|
| - if (element.parent == null) {
|
| - _frame.nodes.add(element);
|
| - }
|
| - }
|
| -}
|
|
|