document.getAnonymousElementByAttribute(this, "anonid", "scrollbox"); document.getAnonymousElementByAttribute(this, "anonid", "scrollbutton-up"); document.getAnonymousElementByAttribute(this, "anonid", "scrollbutton-down"); null null null null null = (vertical ? scrollContentRect.bottom : scrollContentRect.right)) { elementEnd = vertical ? scrollPaddingRect.bottom : scrollPaddingRect.right; } var amountToScroll; if (elementStart < containerStart) { amountToScroll = elementStart - containerStart; } else if (containerEnd < elementEnd) { amountToScroll = elementEnd - containerEnd; } else if (this._isScrolling) { // decelerate if a currently-visible element is selected during the scroll const STOP_DISTANCE = 15; if (this._isScrolling == -1 && elementStart - STOP_DISTANCE < containerStart) amountToScroll = elementStart - containerStart; else if (this._isScrolling == 1 && containerEnd - STOP_DISTANCE < elementEnd) amountToScroll = elementEnd - containerEnd; else amountToScroll = this._isScrolling * STOP_DISTANCE; } else { return; } this._stopSmoothScroll(); if (aSmoothScroll != false && this.smoothScroll) { this._smoothScrollByPixels(amountToScroll, element); } else { this.scrollByPixels(amountToScroll); } ]]> = this.duration ? 1 : 1 - Math.pow(1 - timePassed / this.duration, 4); this.scrollbox.scrollPosition = this.startPos + (this.distance * pos); if (pos == 1) this.scrollbox._stopSmoothScroll(); else this.requestHandle = window.requestAnimationFrame(this.sample.bind(this)); } })]]> 0 ? rect[end] + 1 : rect[start] - 1; var nextElement = this._elementFromPoint(x, index); if (!nextElement) return; var targetElement; if (this._isRTLScrollbox) index *= -1; while (index < 0 && nextElement) { if (this._canScrollToElement(nextElement)) targetElement = nextElement; nextElement = nextElement.previousSibling; index++; } while (index > 0 && nextElement) { if (this._canScrollToElement(nextElement)) targetElement = nextElement; nextElement = nextElement.nextSibling; index--; } if (!targetElement) return; this.ensureElementIsVisible(targetElement, aSmoothScroll); ]]> 0 ? rect[end] + 1 : rect[start] - 1; var pixelDelta = pageDelta * (rect[end] - rect[start]); var destinationPosition = containerEdge + pixelDelta; var nextElement = this._elementFromPoint(containerEdge, pageDelta); if (!nextElement) return; // We need to iterate over our elements in the direction of pageDelta. // pageDelta is the physical direction, so in a horizontal scroll box, // positive values scroll to the right no matter if the scrollbox is // LTR or RTL. But RTL changes how we need to advance the iteration // (whether to get the next or the previous sibling of the current // element). var logicalAdvanceDir = pageDelta * (this._isRTLScrollbox ? -1 : 1); var advance = logicalAdvanceDir > 0 ? (e => e.nextSibling) : (e => e.previousSibling); var extendsPastTarget = (pageDelta > 0) ? (e => e.getBoundingClientRect()[end] > destinationPosition) : (e => e.getBoundingClientRect()[start] < destinationPosition); // We want to scroll to the last element we encounter before we find // an element which extends past destinationPosition. var targetElement; do { if (this._canScrollToElement(nextElement)) targetElement = nextElement; nextElement = advance(nextElement); } while (nextElement && !extendsPastTarget(nextElement)); if (!targetElement) return; this.ensureElementIsVisible(targetElement, aSmoothScroll); ]]> elements[high].getBoundingClientRect()[end]) return null; var mid, rect; while (low <= high) { mid = Math.floor((low + high) / 2); rect = elements[mid].getBoundingClientRect(); if (rect[start] > aX) high = mid - 1; else if (rect[end] < aX) low = mid + 1; else return elements[mid]; } // There's no element at the requested coordinate, but the algorithm // from above yields an element next to it, in a random direction. // The desired scrolling direction leads to the correct element. if (!aPhysicalScrollDir) return null; if (aPhysicalScrollDir < 0 && rect[start] > aX) mid = Math.max(mid - 1, 0); else if (aPhysicalScrollDir > 0 && rect[end] < aX) mid = Math.min(mid + 1, elements.length - 1); return elements[mid]; ]]> 0 [null, null] -1 Math.abs(event.deltaX); let delta = isVertical ? event.deltaY : event.deltaX; let scrollByDelta = isVertical && this._isRTLScrollbox ? -delta : delta; if (this._prevMouseScrolls.every(prev => prev == isVertical)) { if (event.deltaMode == event.DOM_DELTA_PIXEL) this.scrollByPixels(scrollByDelta); else if (event.deltaMode == event.DOM_DELTA_PAGE) this.scrollByPage(scrollByDelta); else this.scrollByIndex(scrollByDelta); } if (this._prevMouseScrolls.length > 1) this._prevMouseScrolls.shift(); this._prevMouseScrolls.push(isVertical); } event.stopPropagation(); event.preventDefault(); ]]> 1) { // Multiple touch points detected, abort. In particular this aborts // the panning gesture when the user puts a second finger down after // already panning with one finger. Aborting at this point prevents // the pan gesture from being resumed until all fingers are lifted // (as opposed to when the user is back down to one finger). this._touchStart = -1; } else { this._touchStart = (this.orient == "vertical" ? event.touches[0].screenY : event.touches[0].screenX); } ]]> = 0) { var touchPoint = (this.orient == "vertical" ? event.touches[0].screenY : event.touches[0].screenX); var delta = this._touchStart - touchPoint; if (Math.abs(delta) > 0) { this.scrollByPixels(delta); this._touchStart = touchPoint; } event.preventDefault(); } ]]> 0 150 3) return; var scrollBack = (aEvent.originalTarget == this._scrollButtonUp); var scrollLeftOrUp = this._isRTLScrollbox ? !scrollBack : scrollBack; var targetElement; if (aEvent.detail == 2) { // scroll by the size of the scrollbox let [start, end] = this._startEndProps; let x; if (scrollLeftOrUp) x = this.scrollClientRect[start] - this.scrollClientSize; else x = this.scrollClientRect[end] + this.scrollClientSize; targetElement = this._elementFromPoint(x, scrollLeftOrUp ? -1 : 1); // the next partly-hidden element will become fully visible, // so don't scroll too far if (targetElement) targetElement = scrollBack ? targetElement.nextSibling : targetElement.previousSibling; } if (!targetElement) { // scroll to the first resp. last element let elements = this._getScrollableElements(); targetElement = scrollBack ? elements[0] : elements[elements.length - 1]; } this.ensureElementIsVisible(targetElement); ]]>