| Index: netlog_viewer/horizontal_scrollbar_view.js
|
| diff --git a/netlog_viewer/horizontal_scrollbar_view.js b/netlog_viewer/horizontal_scrollbar_view.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..d443c89717468ee7f7f5ebb2ae2fca91fecad244
|
| --- /dev/null
|
| +++ b/netlog_viewer/horizontal_scrollbar_view.js
|
| @@ -0,0 +1,124 @@
|
| +// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +/**
|
| + * This view consists of two nested divs. The outer one has a horizontal
|
| + * scrollbar and the inner one has a height of 1 pixel and a width set to
|
| + * allow an appropriate scroll range. The view reports scroll events to
|
| + * a callback specified on construction.
|
| + *
|
| + * All this funkiness is necessary because there is no HTML scroll control.
|
| + * TODO(mmenke): Consider implementing our own scrollbar directly.
|
| + */
|
| +var HorizontalScrollbarView = (function() {
|
| + 'use strict';
|
| +
|
| + // We inherit from DivView.
|
| + var superClass = DivView;
|
| +
|
| + /**
|
| + * @constructor
|
| + */
|
| + function HorizontalScrollbarView(divId, innerDivId, callback) {
|
| + superClass.call(this, divId);
|
| + this.callback_ = callback;
|
| + this.innerDiv_ = $(innerDivId);
|
| + $(divId).onscroll = this.onScroll_.bind(this);
|
| +
|
| + // The current range and position of the scrollbar. Because DOM updates
|
| + // are asynchronous, the current state cannot be read directly from the DOM
|
| + // after updating the range.
|
| + this.range_ = 0;
|
| + this.position_ = 0;
|
| +
|
| + // The DOM updates asynchronously, so sometimes we need a timer to update
|
| + // the current scroll position after resizing the scrollbar.
|
| + this.updatePositionTimerId_ = null;
|
| + }
|
| +
|
| + HorizontalScrollbarView.prototype = {
|
| + // Inherit the superclass's methods.
|
| + __proto__: superClass.prototype,
|
| +
|
| + setGeometry: function(left, top, width, height) {
|
| + superClass.prototype.setGeometry.call(this, left, top, width, height);
|
| + this.setRange(this.range_);
|
| + },
|
| +
|
| + show: function(isVisible) {
|
| + superClass.prototype.show.call(this, isVisible);
|
| + },
|
| +
|
| + /**
|
| + * Sets the range of the scrollbar. The scrollbar can have a value
|
| + * anywhere from 0 to |range|, inclusive. The width of the drag area
|
| + * on the scrollbar will generally be based on the width of the scrollbar
|
| + * relative to the size of |range|, so if the scrollbar is about the size
|
| + * of the thing we're scrolling, we get fairly nice behavior.
|
| + *
|
| + * If |range| is less than the original position, |position_| is set to
|
| + * |range|. Otherwise, it is not modified.
|
| + */
|
| + setRange: function(range) {
|
| + this.range_ = range;
|
| + setNodeWidth(this.innerDiv_, this.getWidth() + range);
|
| + if (range < this.position_)
|
| + this.position_ = range;
|
| + this.setPosition(this.position_);
|
| + },
|
| +
|
| + /**
|
| + * Sets the position of the scrollbar. |position| must be between 0 and
|
| + * |range_|, inclusive.
|
| + */
|
| + setPosition: function(position) {
|
| + this.position_ = position;
|
| + this.updatePosition_();
|
| + },
|
| +
|
| + /**
|
| + * Updates the visible position of the scrollbar to be |position_|.
|
| + * On failure, calls itself again after a timeout. This is needed because
|
| + * setRange does not synchronously update the DOM.
|
| + */
|
| + updatePosition_: function() {
|
| + // Clear the timer if we have one, so we don't have two timers running at
|
| + // once. This is safe even if we were just called from the timer, in
|
| + // which case clearTimeout will silently fail.
|
| + if (this.updatePositionTimerId_ !== null) {
|
| + window.clearTimeout(this.updatePositionTimerId_);
|
| + this.updatePositionTimerId_ = null;
|
| + }
|
| +
|
| + this.getNode().scrollLeft = this.position_;
|
| + if (this.getNode().scrollLeft != this.position_) {
|
| + this.updatePositionTimerId_ =
|
| + window.setTimeout(this.updatePosition_.bind(this));
|
| + }
|
| + },
|
| +
|
| + getRange: function() {
|
| + return this.range_;
|
| + },
|
| +
|
| + getPosition: function() {
|
| + return this.position_;
|
| + },
|
| +
|
| + onScroll_: function() {
|
| + // If we're waiting to update the range, ignore messages from the
|
| + // scrollbar.
|
| + if (this.updatePositionTimerId_ !== null)
|
| + return;
|
| + var newPosition = this.getNode().scrollLeft;
|
| + if (newPosition == this.position_)
|
| + return;
|
| + this.position_ = newPosition;
|
| + this.callback_();
|
| + }
|
| + };
|
| +
|
| + return HorizontalScrollbarView;
|
| +})();
|
| +
|
|
|