OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2013 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 'use strict'; |
| 6 |
| 7 /** |
| 8 * Creates a new scroll bar element. |
| 9 * @extends {HTMLDivElement} |
| 10 * @constructor |
| 11 */ |
| 12 var ScrollBar = cr.ui.define('div'); |
| 13 |
| 14 /** |
| 15 * Creates a vertical scrollbar. |
| 16 * |
| 17 * @param {Element} parent Parent element, must have a relative or absolute |
| 18 * positioning. |
| 19 * @param {Element=} opt_scrollableArea Element with scrollable contents. |
| 20 * If not passed, then call attachToView manually when the scrollable |
| 21 * element becomes available. |
| 22 */ |
| 23 ScrollBar.createVertical = function(parent, opt_scrollableArea) { |
| 24 var scrollbar = new ScrollBar(); |
| 25 parent.appendChild(scrollbar); |
| 26 if (opt_scrollableArea) |
| 27 scrollbar.attachToView(opt_scrollableArea); |
| 28 }; |
| 29 |
| 30 /** |
| 31 * Mode of the scrollbar. As for now, only vertical scrollbars are supported. |
| 32 * @type {number} |
| 33 */ |
| 34 ScrollBar.Mode = { |
| 35 VERTICAL: 0, |
| 36 HORIZONTAL: 1 |
| 37 }; |
| 38 |
| 39 ScrollBar.prototype = { |
| 40 set mode(value) { |
| 41 this.mode_ = value; |
| 42 if (this.mode_ == ScrollBar.Mode.VERTICAL) { |
| 43 this.classList.remove('scrollbar-horizontal'); |
| 44 this.classList.add('scrollbar-vertical'); |
| 45 } else { |
| 46 this.classList.remove('scrollbar-vertical'); |
| 47 this.classList.add('scrollbar-horizontal'); |
| 48 } |
| 49 this.redraw_(); |
| 50 }, |
| 51 get mode() { |
| 52 return this.mode_; |
| 53 } |
| 54 }; |
| 55 |
| 56 /** |
| 57 * Inherits after HTMLDivElement. |
| 58 */ |
| 59 ScrollBar.prototype.__proto__ = HTMLDivElement.prototype; |
| 60 |
| 61 /** |
| 62 * Initializes the DOM structure of the scrollbar. |
| 63 */ |
| 64 ScrollBar.prototype.decorate = function() { |
| 65 this.classList.add('scrollbar'); |
| 66 this.button_ = util.createChild(this, 'scrollbar-button', 'div'); |
| 67 this.mode = ScrollBar.Mode.VERTICAL; |
| 68 |
| 69 this.button_.addEventListener('mousedown', |
| 70 this.onButtonPressed_.bind(this)); |
| 71 window.addEventListener('mouseup', this.onMouseUp_.bind(this)); |
| 72 window.addEventListener('mousemove', this.onMouseMove_.bind(this)); |
| 73 |
| 74 // Unfortunately we need to pool, since we can't easily detect resizing |
| 75 // and content changes. |
| 76 setInterval(this.redraw_.bind(this), 50); |
| 77 }; |
| 78 |
| 79 /** |
| 80 * Attaches the scrollbar to a scrollable element and attaches handlers. |
| 81 * @param {Element} view Scrollable element. |
| 82 */ |
| 83 ScrollBar.prototype.attachToView = function(view) { |
| 84 this.view_ = view; |
| 85 this.view_.addEventListener('scroll', this.onScroll_.bind(this)); |
| 86 this.redraw_(); |
| 87 }; |
| 88 |
| 89 /** |
| 90 * Scroll handler. |
| 91 * @private |
| 92 */ |
| 93 ScrollBar.prototype.onScroll_ = function() { |
| 94 this.redraw_(); |
| 95 }; |
| 96 |
| 97 /** |
| 98 * Pressing on the scrollbar's button handler. |
| 99 * |
| 100 * @param {Event} event Pressing event. |
| 101 * @private |
| 102 */ |
| 103 ScrollBar.prototype.onButtonPressed_ = function(event) { |
| 104 this.buttonPressed_ = true; |
| 105 this.buttonPressedEvent_ = event; |
| 106 this.buttonPressedPosition_ = this.button_.offsetTop - this.view_.offsetTop; |
| 107 this.button_.classList.add('pressed'); |
| 108 |
| 109 event.preventDefault(); |
| 110 }; |
| 111 |
| 112 /** |
| 113 * Releasing the button handler. Note, that it may not be called when releasing |
| 114 * outside of the window. Therefore this is also called from onMouseMove_. |
| 115 * |
| 116 * @param {Event} event Mouse event. |
| 117 * @private |
| 118 */ |
| 119 ScrollBar.prototype.onMouseUp_ = function(event) { |
| 120 this.buttonPressed_ = false; |
| 121 this.button_.classList.remove('pressed'); |
| 122 }; |
| 123 |
| 124 /** |
| 125 * Mouse move handler. Updates the scroll position. |
| 126 * |
| 127 * @param {Event} event Mouse event. |
| 128 * @private |
| 129 */ |
| 130 ScrollBar.prototype.onMouseMove_ = function(event) { |
| 131 if (!this.buttonPressed_) |
| 132 return; |
| 133 if (!event.which) { |
| 134 this.onMouseUp_(event); |
| 135 return; |
| 136 } |
| 137 var clientSize = this.view_.clientHeight; |
| 138 var totalSize = this.view_.scrollHeight; |
| 139 var buttonSize = Math.max(50, clientSize / totalSize * clientSize); |
| 140 |
| 141 var buttonPosition = this.buttonPressedPosition_ + |
| 142 (event.screenY - this.buttonPressedEvent_.screenY); |
| 143 var scrollPosition = totalSize * (buttonPosition / clientSize); |
| 144 |
| 145 this.view_.scrollTop = scrollPosition; |
| 146 this.redraw_(); |
| 147 }; |
| 148 |
| 149 /** |
| 150 * Redraws the scrollbar. |
| 151 * @private |
| 152 */ |
| 153 ScrollBar.prototype.redraw_ = function() { |
| 154 if (!this.view_) |
| 155 return; |
| 156 |
| 157 var clientSize = this.view_.clientHeight; |
| 158 var clientTop = this.view_.offsetTop; |
| 159 var scrollPosition = this.view_.scrollTop; |
| 160 var totalSize = this.view_.scrollHeight; |
| 161 |
| 162 this.hidden = totalSize <= clientSize; |
| 163 |
| 164 var buttonSize = Math.max(50, clientSize / totalSize * clientSize); |
| 165 var buttonPosition = scrollPosition / (totalSize - clientSize) * |
| 166 (clientSize - buttonSize); |
| 167 |
| 168 this.button_.style.top = buttonPosition + clientTop + 'px'; |
| 169 this.button_.style.height = buttonSize + 'px'; |
| 170 }; |
OLD | NEW |