OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 /** |
| 6 * This view consists of two nested divs. The outer one has a horizontal |
| 7 * scrollbar and the inner one has a height of 1 pixel and a width set to |
| 8 * allow an appropriate scroll range. The view reports scroll events to |
| 9 * a callback specified on construction. |
| 10 * |
| 11 * All this funkiness is necessary because there is no HTML scroll control. |
| 12 * TODO(mmenke): Consider implementing our own scrollbar directly. |
| 13 */ |
| 14 var HorizontalScrollbarView = (function() { |
| 15 'use strict'; |
| 16 |
| 17 // We inherit from DivView. |
| 18 var superClass = DivView; |
| 19 |
| 20 /** |
| 21 * @constructor |
| 22 */ |
| 23 function HorizontalScrollbarView(divId, innerDivId, callback) { |
| 24 superClass.call(this, divId); |
| 25 this.callback_ = callback; |
| 26 this.innerDiv_ = $(innerDivId); |
| 27 $(divId).onscroll = this.onScroll_.bind(this); |
| 28 |
| 29 // The current range and position of the scrollbar. Because DOM updates |
| 30 // are asynchronous, the current state cannot be read directly from the DOM |
| 31 // after updating the range. |
| 32 this.range_ = 0; |
| 33 this.position_ = 0; |
| 34 |
| 35 // The DOM updates asynchronously, so sometimes we need a timer to update |
| 36 // the current scroll position after resizing the scrollbar. |
| 37 this.updatePositionTimerId_ = null; |
| 38 } |
| 39 |
| 40 HorizontalScrollbarView.prototype = { |
| 41 // Inherit the superclass's methods. |
| 42 __proto__: superClass.prototype, |
| 43 |
| 44 setGeometry: function(left, top, width, height) { |
| 45 superClass.prototype.setGeometry.call(this, left, top, width, height); |
| 46 this.setRange(this.range_); |
| 47 }, |
| 48 |
| 49 show: function(isVisible) { |
| 50 superClass.prototype.show.call(this, isVisible); |
| 51 }, |
| 52 |
| 53 /** |
| 54 * Sets the range of the scrollbar. The scrollbar can have a value |
| 55 * anywhere from 0 to |range|, inclusive. The width of the drag area |
| 56 * on the scrollbar will generally be based on the width of the scrollbar |
| 57 * relative to the size of |range|, so if the scrollbar is about the size |
| 58 * of the thing we're scrolling, we get fairly nice behavior. |
| 59 * |
| 60 * If |range| is less than the original position, |position_| is set to |
| 61 * |range|. Otherwise, it is not modified. |
| 62 */ |
| 63 setRange: function(range) { |
| 64 this.range_ = range; |
| 65 setNodeWidth(this.innerDiv_, this.getWidth() + range); |
| 66 if (range < this.position_) |
| 67 this.position_ = range; |
| 68 this.setPosition(this.position_); |
| 69 }, |
| 70 |
| 71 /** |
| 72 * Sets the position of the scrollbar. |position| must be between 0 and |
| 73 * |range_|, inclusive. |
| 74 */ |
| 75 setPosition: function(position) { |
| 76 this.position_ = position; |
| 77 this.updatePosition_(); |
| 78 }, |
| 79 |
| 80 /** |
| 81 * Updates the visible position of the scrollbar to be |position_|. |
| 82 * On failure, calls itself again after a timeout. This is needed because |
| 83 * setRange does not synchronously update the DOM. |
| 84 */ |
| 85 updatePosition_: function() { |
| 86 // Clear the timer if we have one, so we don't have two timers running at |
| 87 // once. This is safe even if we were just called from the timer, in |
| 88 // which case clearTimeout will silently fail. |
| 89 if (this.updatePositionTimerId_ !== null) { |
| 90 window.clearTimeout(this.updatePositionTimerId_); |
| 91 this.updatePositionTimerId_ = null; |
| 92 } |
| 93 |
| 94 this.getNode().scrollLeft = this.position_; |
| 95 if (this.getNode().scrollLeft != this.position_) { |
| 96 this.updatePositionTimerId_ = |
| 97 window.setTimeout(this.updatePosition_.bind(this)); |
| 98 } |
| 99 }, |
| 100 |
| 101 getRange: function() { |
| 102 return this.range_; |
| 103 }, |
| 104 |
| 105 getPosition: function() { |
| 106 return this.position_; |
| 107 }, |
| 108 |
| 109 onScroll_: function() { |
| 110 // If we're waiting to update the range, ignore messages from the |
| 111 // scrollbar. |
| 112 if (this.updatePositionTimerId_ !== null) |
| 113 return; |
| 114 var newPosition = this.getNode().scrollLeft; |
| 115 if (newPosition == this.position_) |
| 116 return; |
| 117 this.position_ = newPosition; |
| 118 this.callback_(); |
| 119 } |
| 120 }; |
| 121 |
| 122 return HorizontalScrollbarView; |
| 123 })(); |
| 124 |
OLD | NEW |