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.
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.
11 * All this funkiness is necessary because there is no HTML scroll control.
12 * TODO(mmenke): Consider implementing our own scrollbar directly.
14 var HorizontalScrollbarView
= (function() {
17 // We inherit from DivView.
18 var superClass
= DivView
;
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);
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.
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;
40 HorizontalScrollbarView
.prototype = {
41 // Inherit the superclass's methods.
42 __proto__
: superClass
.prototype,
44 setGeometry: function(left
, top
, width
, height
) {
45 superClass
.prototype.setGeometry
.call(this, left
, top
, width
, height
);
46 this.setRange(this.range_
);
49 show: function(isVisible
) {
50 superClass
.prototype.show
.call(this, isVisible
);
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.
60 * If |range| is less than the original position, |position_| is set to
61 * |range|. Otherwise, it is not modified.
63 setRange: function(range
) {
65 setNodeWidth(this.innerDiv_
, this.getWidth() + range
);
66 if (range
< this.position_
)
67 this.position_
= range
;
68 this.setPosition(this.position_
);
72 * Sets the position of the scrollbar. |position| must be between 0 and
73 * |range_|, inclusive.
75 setPosition: function(position
) {
76 this.position_
= position
;
77 this.updatePosition_();
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.
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;
94 this.getNode().scrollLeft
= this.position_
;
95 if (this.getNode().scrollLeft
!= this.position_
) {
96 this.updatePositionTimerId_
=
97 window
.setTimeout(this.updatePosition_
.bind(this));
101 getRange: function() {
105 getPosition: function() {
106 return this.position_
;
109 onScroll_: function() {
110 // If we're waiting to update the range, ignore messages from the
112 if (this.updatePositionTimerId_
!== null)
114 var newPosition
= this.getNode().scrollLeft
;
115 if (newPosition
== this.position_
)
117 this.position_
= newPosition
;
122 return HorizontalScrollbarView
;