From 4bc24fe3e14bff661458b5b6d3781a36856fdccb Mon Sep 17 00:00:00 2001 From: rachel-fenichel Date: Wed, 20 Apr 2016 11:26:01 -0700 Subject: [PATCH] Constrain scrollbar value in set() and decompose resize() into horizontal and vertical modes. --- core/scrollbar.js | 139 +++++++++++++++++++++++++++------------------- 1 file changed, 81 insertions(+), 58 deletions(-) diff --git a/core/scrollbar.js b/core/scrollbar.js index 42d053cc0..6c2a4ff31 100644 --- a/core/scrollbar.js +++ b/core/scrollbar.js @@ -270,69 +270,91 @@ Blockly.Scrollbar.prototype.resize = function(opt_metrics) { * .absoluteLeft: Left-edge of view. */ if (this.horizontal_) { - var outerLength = hostMetrics.viewWidth - 1; - if (this.pair_) { - // Shorten the scrollbar to make room for the corner square. - outerLength -= Blockly.Scrollbar.scrollbarThickness; - } else { - // Only show the scrollbar if needed. - // Ideally this would also apply to scrollbar pairs, but that's a bigger - // headache (due to interactions with the corner square). - this.setVisible(outerLength < hostMetrics.contentWidth); - } - this.ratio_ = outerLength / hostMetrics.contentWidth; - if (this.ratio_ === -Infinity || this.ratio_ === Infinity || - isNaN(this.ratio_)) { - this.ratio_ = 0; - } - var innerLength = hostMetrics.viewWidth * this.ratio_; - var innerOffset = (hostMetrics.viewLeft - hostMetrics.contentLeft) * - this.ratio_; - this.svgKnob_.setAttribute('width', Math.max(0, innerLength)); - this.xCoordinate = hostMetrics.absoluteLeft + 0.5; - if (this.pair_ && this.workspace_.RTL) { - this.xCoordinate += hostMetrics.absoluteLeft + - Blockly.Scrollbar.scrollbarThickness; - } - this.yCoordinate = hostMetrics.absoluteTop + hostMetrics.viewHeight - - Blockly.Scrollbar.scrollbarThickness - 0.5; - this.svgGroup_.setAttribute('transform', - 'translate(' + this.xCoordinate + ',' + this.yCoordinate + ')'); - this.svgBackground_.setAttribute('width', Math.max(0, outerLength)); - this.svgKnob_.setAttribute('x', this.constrainKnob_(innerOffset)); + this.resizeHorizontal_(hostMetrics); } else { - var outerLength = hostMetrics.viewHeight - 1; - if (this.pair_) { - // Shorten the scrollbar to make room for the corner square. - outerLength -= Blockly.Scrollbar.scrollbarThickness; - } else { - // Only show the scrollbar if needed. - this.setVisible(outerLength < hostMetrics.contentHeight); - } - this.ratio_ = outerLength / hostMetrics.contentHeight; - if (this.ratio_ === -Infinity || this.ratio_ === Infinity || - isNaN(this.ratio_)) { - this.ratio_ = 0; - } - var innerLength = hostMetrics.viewHeight * this.ratio_; - var innerOffset = (hostMetrics.viewTop - hostMetrics.contentTop) * - this.ratio_; - this.svgKnob_.setAttribute('height', Math.max(0, innerLength)); - this.xCoordinate = hostMetrics.absoluteLeft + 0.5; - if (!this.workspace_.RTL) { - this.xCoordinate += hostMetrics.viewWidth - - Blockly.Scrollbar.scrollbarThickness - 1; - } - this.yCoordinate = hostMetrics.absoluteTop + 0.5; - this.svgGroup_.setAttribute('transform', - 'translate(' + this.xCoordinate + ',' + this.yCoordinate + ')'); - this.svgBackground_.setAttribute('height', Math.max(0, outerLength)); - this.svgKnob_.setAttribute('y', this.constrainKnob_(innerOffset)); + this.resizeVertical_(hostMetrics); } // Resizing may have caused some scrolling. this.onScroll_(); }; +/** + * Recalculate a horizontal scrollbar's location and length. + * @param {!Object} hostMetrics A data structure describing all the + * required dimensions, possibly fetched from the host + * object. + * @private + */ +Blockly.Scrollbar.prototype.resizeHorizontal_ = function(hostMetrics) { + var outerLength = hostMetrics.viewWidth - 1; + if (this.pair_) { + // Shorten the scrollbar to make room for the corner square. + outerLength -= Blockly.Scrollbar.scrollbarThickness; + } else { + // Only show the scrollbar if needed. + // Ideally this would also apply to scrollbar pairs, but that's a bigger + // headache (due to interactions with the corner square). + this.setVisible(outerLength < hostMetrics.contentWidth); + } + this.ratio_ = outerLength / hostMetrics.contentWidth; + if (this.ratio_ === -Infinity || this.ratio_ === Infinity || + isNaN(this.ratio_)) { + this.ratio_ = 0; + } + var innerLength = hostMetrics.viewWidth * this.ratio_; + var innerOffset = (hostMetrics.viewLeft - hostMetrics.contentLeft) * + this.ratio_; + this.svgKnob_.setAttribute('width', Math.max(0, innerLength)); + this.xCoordinate = hostMetrics.absoluteLeft + 0.5; + if (this.pair_ && this.workspace_.RTL) { + this.xCoordinate += hostMetrics.absoluteLeft + + Blockly.Scrollbar.scrollbarThickness; + } + this.yCoordinate = hostMetrics.absoluteTop + hostMetrics.viewHeight - + Blockly.Scrollbar.scrollbarThickness - 0.5; + this.svgGroup_.setAttribute('transform', + 'translate(' + this.xCoordinate + ',' + this.yCoordinate + ')'); + this.svgBackground_.setAttribute('width', Math.max(0, outerLength)); + this.svgKnob_.setAttribute('x', this.constrainKnob_(innerOffset)); +}; + +/** + * Recalculate a vertical scrollbar's location and length. + * @param {!Object} hostMetrics A data structure describing all the + * required dimensions, possibly fetched from the host + * object. + * @private + */ +Blockly.Scrollbar.prototype.resizeVertical_ = function(hostMetrics) { + var outerLength = hostMetrics.viewHeight - 1; + if (this.pair_) { + // Shorten the scrollbar to make room for the corner square. + outerLength -= Blockly.Scrollbar.scrollbarThickness; + } else { + // Only show the scrollbar if needed. + this.setVisible(outerLength < hostMetrics.contentHeight); + } + this.ratio_ = outerLength / hostMetrics.contentHeight; + if (this.ratio_ === -Infinity || this.ratio_ === Infinity || + isNaN(this.ratio_)) { + this.ratio_ = 0; + } + var innerLength = hostMetrics.viewHeight * this.ratio_; + var innerOffset = (hostMetrics.viewTop - hostMetrics.contentTop) * + this.ratio_; + this.svgKnob_.setAttribute('height', Math.max(0, innerLength)); + this.xCoordinate = hostMetrics.absoluteLeft + 0.5; + if (!this.workspace_.RTL) { + this.xCoordinate += hostMetrics.viewWidth - + Blockly.Scrollbar.scrollbarThickness - 1; + } + this.yCoordinate = hostMetrics.absoluteTop + 0.5; + this.svgGroup_.setAttribute('transform', + 'translate(' + this.xCoordinate + ',' + this.yCoordinate + ')'); + this.svgBackground_.setAttribute('height', Math.max(0, outerLength)); + this.svgKnob_.setAttribute('y', this.constrainKnob_(innerOffset)); +}; + /** * Create all the DOM elements required for a scrollbar. * The resulting widget is not sized. @@ -533,8 +555,9 @@ Blockly.Scrollbar.prototype.onScroll_ = function() { * @param {number} value The distance from the top/left end of the bar. */ Blockly.Scrollbar.prototype.set = function(value) { + var constrainedValue = this.constrainKnob_(value * this.ratio_); // Move the scrollbar slider. - this.svgKnob_.setAttribute(this.horizontal_ ? 'x' : 'y', value * this.ratio_); + this.svgKnob_.setAttribute(this.horizontal_ ? 'x' : 'y', constrainedValue); this.onScroll_(); };