1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file.
4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)'use strict';
6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)/**
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * Creates a new scroll bar element.
9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @extends {HTMLDivElement}
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @constructor
11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */
12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)var ScrollBar = cr.ui.define('div');
13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)/**
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * Mode of the scrollbar. As for now, only vertical scrollbars are supported.
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @type {number}
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ScrollBar.Mode = {
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  VERTICAL: 0,
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  HORIZONTAL: 1
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)};
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ScrollBar.prototype = {
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  set mode(value) {
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    this.mode_ = value;
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (this.mode_ == ScrollBar.Mode.VERTICAL) {
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      this.classList.remove('scrollbar-horizontal');
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      this.classList.add('scrollbar-vertical');
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    } else {
30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      this.classList.remove('scrollbar-vertical');
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      this.classList.add('scrollbar-horizontal');
32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    this.redraw_();
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  },
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  get mode() {
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return this.mode_;
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)};
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)/**
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * Inherits after HTMLDivElement.
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ScrollBar.prototype.__proto__ = HTMLDivElement.prototype;
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)/**
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * Initializes the DOM structure of the scrollbar.
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ScrollBar.prototype.decorate = function() {
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  this.classList.add('scrollbar');
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  this.button_ = util.createChild(this, 'scrollbar-button', 'div');
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  this.mode = ScrollBar.Mode.VERTICAL;
52f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  this.idleTimerId_ = 0;
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  this.button_.addEventListener('mousedown',
55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                this.onButtonPressed_.bind(this));
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  window.addEventListener('mouseup', this.onMouseUp_.bind(this));
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  window.addEventListener('mousemove', this.onMouseMove_.bind(this));
58868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)};
59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
60868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)/**
61868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * Initialize a scrollbar.
62868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *
63868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * @param {Element} parent Parent element, must have a relative or absolute
64868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *     positioning.
65868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * @param {Element=} opt_scrollableArea Element with scrollable contents.
66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *     If not passed, then call attachToView manually when the scrollable
67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *     element becomes available.
68868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) */
69868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)ScrollBar.prototype.initialize = function(parent, opt_scrollableArea) {
70868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  parent.appendChild(this);
71868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (opt_scrollableArea)
72868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    this.attachToView(opt_scrollableArea);
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)};
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)/**
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * Attaches the scrollbar to a scrollable element and attaches handlers.
77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @param {Element} view Scrollable element.
78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ScrollBar.prototype.attachToView = function(view) {
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  this.view_ = view;
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  this.view_.addEventListener('scroll', this.onScroll_.bind(this));
82868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  this.view_.addEventListener('relayout', this.onRelayout_.bind(this));
83eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  this.domObserver_ = new MutationObserver(this.onDomChanged_.bind(this));
84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  this.domObserver_.observe(this.view_, {subtree: true, attributes: true});
85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  this.onRelayout_();
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)};
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)/**
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * Scroll handler.
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @private
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ScrollBar.prototype.onScroll_ = function() {
93868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  this.scrollTop_ = this.view_.scrollTop;
94868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  this.redraw_();
95f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
96f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Add class 'scrolling' to scrollbar to make it visible while scrolling.
97f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  this.button_.classList.add('scrolling');
98f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
99f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Set timer to remove class 'scrolling' after scrolling becomes idle.
100f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (this.idleTimerId_)
101f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    clearTimeout(this.idleTimerId_);
102f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  this.idleTimerId_ = setTimeout(function() {
103f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    this.idleTimerId_ = 0;
104f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    this.button_.classList.remove('scrolling');
105f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }.bind(this), 1000);
106868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)};
107868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
108868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)/**
109868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * Relayout handler.
110868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * @private
111868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) */
112868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)ScrollBar.prototype.onRelayout_ = function() {
113868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  this.scrollHeight_ = this.view_.scrollHeight;
114868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  this.clientHeight_ = this.view_.clientHeight;
115868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  this.offsetTop_ = this.view_.offsetTop;
116868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  this.scrollTop_ = this.view_.scrollTop;
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  this.redraw_();
118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)};
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)/**
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * Pressing on the scrollbar's button handler.
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) *
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @param {Event} event Pressing event.
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @private
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ScrollBar.prototype.onButtonPressed_ = function(event) {
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  this.buttonPressed_ = true;
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  this.buttonPressedEvent_ = event;
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  this.buttonPressedPosition_ = this.button_.offsetTop - this.view_.offsetTop;
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  this.button_.classList.add('pressed');
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  event.preventDefault();
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)};
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)/**
136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * Releasing the button handler. Note, that it may not be called when releasing
137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * outside of the window. Therefore this is also called from onMouseMove_.
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) *
139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @param {Event} event Mouse event.
140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @private
141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */
142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ScrollBar.prototype.onMouseUp_ = function(event) {
143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  this.buttonPressed_ = false;
144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  this.button_.classList.remove('pressed');
145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)};
146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)/**
148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * Mouse move handler. Updates the scroll position.
149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) *
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @param {Event} event Mouse event.
151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @private
152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */
153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ScrollBar.prototype.onMouseMove_ = function(event) {
154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!this.buttonPressed_)
155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!event.which) {
157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    this.onMouseUp_(event);
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
160868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  var clientSize = this.getClientHeight();
161868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  var totalSize = this.getTotalHeight();
162eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // TODO(hirono): Fix the geometric calculation.  crbug.com/253779
163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  var buttonSize = Math.max(50, clientSize / totalSize * clientSize);
164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  var buttonPosition = this.buttonPressedPosition_ +
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      (event.screenY - this.buttonPressedEvent_.screenY);
166868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Ensures the scrollbar is in the view.
167868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  buttonPosition =
168868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      Math.max(0, Math.min(buttonPosition, clientSize - buttonSize));
169eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  var scrollPosition;
170eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (clientSize > buttonSize) {
171eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    scrollPosition = Math.max(totalSize - clientSize, 0) *
172eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        buttonPosition / (clientSize - buttonSize);
173eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  } else {
174eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    scrollPosition = 0;
175eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
177868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  this.scrollTop_ = scrollPosition;
178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  this.view_.scrollTop = scrollPosition;
179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  this.redraw_();
180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)};
181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)/**
183868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * Handles changed in Dom by redrawing the scrollbar. Ignores consecutive calls.
184868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * @private
185868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) */
186868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)ScrollBar.prototype.onDomChanged_ = function() {
187868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (this.domChangedTimer_) {
188868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    clearTimeout(this.domChangedTimer_);
189868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    this.domChangedTimer_ = null;
190868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
191868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  this.domChangedTimer_ = setTimeout(function() {
192868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    this.onRelayout_();
193868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    this.domChangedTimer_ = null;
194868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }.bind(this), 50);
195868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)};
196868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
197868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)/**
198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * Redraws the scrollbar.
199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @private
200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */
201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ScrollBar.prototype.redraw_ = function() {
202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!this.view_)
203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
205868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  var clientSize = this.getClientHeight();
206868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  var clientTop = this.offsetTop_;
207868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  var scrollPosition = this.scrollTop_;
208868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  var totalSize = this.getTotalHeight();
209868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  var hidden = totalSize <= clientSize;
210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  var buttonSize = Math.max(50, clientSize / totalSize * clientSize);
212eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  var buttonPosition;
213eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (clientSize - buttonSize > 0) {
214eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    buttonPosition = scrollPosition / (totalSize - clientSize) *
215eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        (clientSize - buttonSize);
216eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  } else {
217eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    buttonPosition = 0;
218eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
219868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  var buttonTop = buttonPosition + clientTop;
220c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
221868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  var time = Date.now();
222868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (this.hidden != hidden ||
223868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      this.lastButtonTop_ != buttonTop ||
224868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      this.lastButtonSize_ != buttonSize) {
225868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    requestAnimationFrame(function() {
226868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      this.hidden = hidden;
227868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      this.button_.style.top = buttonTop + 'px';
228868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      this.button_.style.height = buttonSize + 'px';
229868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }.bind(this));
230868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
231868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
232868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  this.lastButtonTop_ = buttonTop;
233868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  this.lastButtonSize_ = buttonSize;
234868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)};
235868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
236868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)/**
237868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * Returns the viewport height of the view.
238868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * @return {number} The viewport height of the view in px.
239868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * @protected
240868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) */
241868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)ScrollBar.prototype.getClientHeight = function() {
242868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return this.clientHeight_;
243868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)};
244868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
245868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)/**
246868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * Returns the total height of the view.
247868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * @return {number} The total height of the view in px.
248868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * @protected
249868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) */
250868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)ScrollBar.prototype.getTotalHeight = function() {
251868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return this.scrollHeight_;
252868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)};
253868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
254868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)/**
255868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * Creates a new scroll bar for elements in the main panel.
256868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * @extends {ScrollBar}
257868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * @constructor
258868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) */
259868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)var MainPanelScrollBar = cr.ui.define('div');
260868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
261868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)/**
262868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * Inherits after ScrollBar.
263868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) */
264868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)MainPanelScrollBar.prototype.__proto__ = ScrollBar.prototype;
265868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
266868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)/** @override */
267868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)MainPanelScrollBar.prototype.decorate = function() {
268868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  ScrollBar.prototype.decorate.call(this);
269868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
270868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  /**
271868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)   * Margin for the transparent preview panel at the bottom.
272868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)   * @type {number}
273868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)   * @private
274868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)   */
275868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  this.bottomMarginForPanel_ = 0;
276868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)};
277868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
278868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)/**
279868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * GReturns the viewport height of the view, considering the preview panel.
280868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *
281868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * @return {number} The viewport height of the view in px.
282868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * @override
283868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * @protected
284868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) */
285868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)MainPanelScrollBar.prototype.getClientHeight = function() {
286868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return this.clientHeight_ - this.bottomMarginForPanel_;
287868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)};
288868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
289868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)/**
290868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * Returns the total height of the view, considering the preview panel.
291868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *
292868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * @return {number} The total height of the view in px.
293868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * @override
294868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * @protected
295868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) */
296868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)MainPanelScrollBar.prototype.getTotalHeight = function() {
297868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return this.scrollHeight_ - this.bottomMarginForPanel_;
298868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)};
299868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
300868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)/**
301868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * Sets the bottom margin height of the view for the transparent preview panel.
302868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * @param {number} margin Margin to be set in px.
303868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) */
304868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)MainPanelScrollBar.prototype.setBottomMarginForPanel = function(margin) {
305868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  this.bottomMarginForPanel_ = margin;
306c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)};
307