Changeset View
Changeset View
Standalone View
Standalone View
webroot/rsrc/externals/javelin/lib/Scrollbar.js
Show All 21 Lines | |||||
* This class was initially adapted from "Trackpad Scroll Emulator", by | * This class was initially adapted from "Trackpad Scroll Emulator", by | ||||
* Jonathan Nicol. See <https://github.com/jnicol/trackpad-scroll-emulator>. | * Jonathan Nicol. See <https://github.com/jnicol/trackpad-scroll-emulator>. | ||||
*/ | */ | ||||
JX.install('Scrollbar', { | JX.install('Scrollbar', { | ||||
construct: function(frame) { | construct: function(frame) { | ||||
this._frame = frame; | this._frame = frame; | ||||
JX.DOM.listen(frame, 'load', null, JX.bind(this, this._onload)); | |||||
this._onload(); | |||||
// Before doing anything, check if the scrollbar control has a measurable | // Before doing anything, check if the scrollbar control has a measurable | ||||
// width. If it doesn't, we're already in an environment with an aesthetic | // width. If it doesn't, we're already in an environment with an aesthetic | ||||
// scrollbar (like Safari on OSX with no mouse connected, or an iPhone) | // scrollbar (like Safari on OSX with no mouse connected, or an iPhone) | ||||
// and we don't need to do anything. | // and we don't need to do anything. | ||||
if (JX.Scrollbar._getScrollbarControlWidth() === 0) { | if (JX.Scrollbar._getScrollbarControlWidth() === 0) { | ||||
return; | return; | ||||
} | } | ||||
Show All 34 Lines | construct: function(frame) { | ||||
this._bar = JX.$N('div', {className: 'jx-scrollbar-bar'}, this._handle); | this._bar = JX.$N('div', {className: 'jx-scrollbar-bar'}, this._handle); | ||||
JX.DOM.prependContent(frame, this._bar); | JX.DOM.prependContent(frame, this._bar); | ||||
JX.DOM.listen(this._handle, 'mousedown', null, JX.bind(this, this._ondrag)); | JX.DOM.listen(this._handle, 'mousedown', null, JX.bind(this, this._ondrag)); | ||||
JX.DOM.listen(this._bar, 'mousedown', null, JX.bind(this, this._onjump)); | JX.DOM.listen(this._bar, 'mousedown', null, JX.bind(this, this._onjump)); | ||||
JX.enableDispatch(document.body, 'mouseenter'); | JX.enableDispatch(document.body, 'mouseenter'); | ||||
JX.DOM.listen(viewport, 'mouseenter', null, JX.bind(this, this._onenter)); | |||||
JX.DOM.listen(frame, 'scroll', null, JX.bind(this, this._onscroll)); | |||||
// Enabling dispatch for this event on `window` allows us to scroll even | // Enabling dispatch for this event on `window` allows us to scroll even | ||||
// if the mouse cursor is dragged outside the window in at least some | // if the mouse cursor is dragged outside the window in at least some | ||||
// browsers (for example, Safari on OSX). | // browsers (for example, Safari on OSX). | ||||
JX.enableDispatch(window, 'mousemove'); | JX.enableDispatch(window, 'mousemove'); | ||||
JX.DOM.listen(viewport, 'mouseenter', null, JX.bind(this, this._onenter)); | |||||
JX.DOM.listen(frame, 'scroll', null, JX.bind(this, this._onscroll)); | |||||
JX.DOM.listen(viewport, 'mouseenter', null, JX.bind(this, this._onenter)); | |||||
JX.DOM.listen(viewport, 'mouseenter', null, JX.bind(this, this._onenter)); | |||||
JX.Stratcom.listen('mousemove', null, JX.bind(this, this._onmove)); | JX.Stratcom.listen('mousemove', null, JX.bind(this, this._onmove)); | ||||
JX.Stratcom.listen('mouseup', null, JX.bind(this, this._ondrop)); | JX.Stratcom.listen('mouseup', null, JX.bind(this, this._ondrop)); | ||||
JX.Stratcom.listen('resize', null, JX.bind(this, this._onresize)); | JX.Stratcom.listen('resize', null, JX.bind(this, this._onresize)); | ||||
this._resizeViewport(); | this._resizeViewport(); | ||||
this._resizeBar(); | this._resizeBar(); | ||||
}, | }, | ||||
statics: { | statics: { | ||||
Show All 27 Lines | members: { | ||||
_content: null, | _content: null, | ||||
_bar: null, | _bar: null, | ||||
_handle: null, | _handle: null, | ||||
_timeout: null, | _timeout: null, | ||||
_dragOrigin: null, | _dragOrigin: null, | ||||
_scrollOrigin: null, | _scrollOrigin: null, | ||||
_lastHeight: null, | |||||
/** | /** | ||||
* Mark this content as the scroll frame. | * Mark this content as the scroll frame. | ||||
* | * | ||||
* This changes the behavior of the @{class:JX.DOM} scroll functions so the | * This changes the behavior of the @{class:JX.DOM} scroll functions so the | ||||
* continue to work properly if the main page content is reframed to scroll | * continue to work properly if the main page content is reframed to scroll | ||||
* independently. | * independently. | ||||
▲ Show 20 Lines • Show All 144 Lines • ▼ Show 20 Lines | members: { | ||||
_ondrop: function() { | _ondrop: function() { | ||||
this._dragOrigin = null; | this._dragOrigin = null; | ||||
// Reset the timer to hide the bar. | // Reset the timer to hide the bar. | ||||
this._showBar(); | this._showBar(); | ||||
}, | }, | ||||
/** | |||||
* Something inside the frame fired a load event. | |||||
* | |||||
* The typical case is that an image loaded. This may have changed the | |||||
* height of the scroll area, and we may want to make adjustments. | |||||
*/ | |||||
_onload: function() { | |||||
var viewport = this._viewport || this._frame; | |||||
var height = viewport.scrollHeight; | |||||
var visible = JX.Vector.getDim(viewport).y; | |||||
if (this._lastHeight !== null && this._lastHeight != height) { | |||||
// If the viewport was scrollable and was scrolled down to near the | |||||
// bottom, scroll it down to account for the new height. The effect | |||||
// of this rule is to keep panels like the chat column scrolled to | |||||
// the bottom as images load into the thread. | |||||
if (viewport.scrollTop > 0) { | |||||
if ((viewport.scrollTop + visible + 64) >= this._lastHeight) { | |||||
btrahan: What's the 64 here? I assume the "near the bottom" piece
I thought scrollTop when scrolled… | |||||
epriestleyAuthorUnsubmitted Not Done Inline ActionsYeah, "64" is "near the bottom". Here's what it's trying to do: "visible" is how many pixels tall the scrollable container is. Basically the height of the scrollbar itself in pixels. "scrollTop" is the position of the top of the scrollbar. +------------+ | text text | | text text | <--- Content, height = 25 | text text | | text text | | text text | | text text | | text text | | text text | | text text | +=================+ <--- Viewport, scrollTop = 11 ("viewport position") | | text text | ^| | | text text | .| | | text text | .| | | text text | .| | | text text | .| | | text text | .| <--- Scrollbar, visible = 8 ("scrollbar height") | | text text | .| | | text text | v| +=================+ <--- (scrollTop + visible) = 19 ("bottom of viewport") | text text | | text text | | text text | | text text | +------------+ scrollTop + visible is the position of the top of the scrollable window plus the height of the window itself, giving us the bottom of the scrollable window. If the content has height 500 and the viewport has height 100, "scrollTop" will never be close to 500. The largest value it can ever have is 400, since then you're at the bottom of the document and the last 100 px of document content are visible. epriestley: Yeah, "64" is "near the bottom". Here's what it's trying to do:
"visible" is how many pixels… | |||||
viewport.scrollTop += (height - this._lastHeight); | |||||
} | |||||
} | |||||
} | |||||
this._lastHeight = height; | |||||
}, | |||||
/** | /** | ||||
* Shove the scrollbar on the viewport under the edge of the frame so the | * Shove the scrollbar on the viewport under the edge of the frame so the | ||||
* user can't see it. | * user can't see it. | ||||
*/ | */ | ||||
_resizeViewport: function() { | _resizeViewport: function() { | ||||
var fdim = JX.Vector.getDim(this._frame); | var fdim = JX.Vector.getDim(this._frame); | ||||
fdim.x += JX.Scrollbar._getScrollbarControlWidth(); | fdim.x += JX.Scrollbar._getScrollbarControlWidth(); | ||||
fdim.setDim(this._viewport); | fdim.setDim(this._viewport); | ||||
▲ Show 20 Lines • Show All 89 Lines • Show Last 20 Lines |
What's the 64 here? I assume the "near the bottom" piece
I thought scrollTop when scrolled near the bottom would more or less be the height? Basically not sure about visible either.