Path: blob/trunk/third_party/closure/goog/style/bidi.js
4122 views
/**1* @license2* Copyright The Closure Library Authors.3* SPDX-License-Identifier: Apache-2.04*/56/**7* @fileoverview Bidi utility functions.8*/910goog.provide('goog.style.bidi');1112goog.require('goog.dom');13goog.require('goog.style');14goog.require('goog.userAgent');15goog.require('goog.userAgent.platform');16goog.require('goog.userAgent.product');17goog.require('goog.userAgent.product.isVersion');181920/**21* Returns the normalized scrollLeft position for a scrolled element.22* @param {Element} element The scrolled element.23* @return {number} The number of pixels the element is scrolled. 0 indicates24* that the element is not scrolled at all (which, in general, is the25* left-most position in ltr and the right-most position in rtl).26*/27goog.style.bidi.getScrollLeft = function(element) {28'use strict';29var isRtl = goog.style.isRightToLeft(element);30if (isRtl && goog.style.bidi.usesNegativeScrollLeftInRtl_()) {31return -element.scrollLeft;32} else if (isRtl && !goog.userAgent.EDGE_OR_IE) {33// ScrollLeft starts at the maximum positive value and decreases towards34// 0 as the element is scrolled towards the left. However, for overflow35// visible, there is no scrollLeft and the value always stays correctly at 036var overflowX = goog.style.getComputedOverflowX(element);37if (overflowX == 'visible') {38return element.scrollLeft;39} else {40return element.scrollWidth - element.clientWidth - element.scrollLeft;41}42}43// ScrollLeft behavior is identical in rtl and ltr, it starts at 0 and44// increases as the element is scrolled away from the start.45return element.scrollLeft;46};474849/**50* Returns the "offsetStart" of an element, analogous to offsetLeft but51* normalized for right-to-left environments and various browser52* inconsistencies. This value returned can always be passed to setScrollOffset53* to scroll to an element's left edge in a left-to-right offsetParent or54* right edge in a right-to-left offsetParent.55*56* For example, here offsetStart is 10px in an LTR environment and 5px in RTL:57*58* <pre>59* | xxxxxxxxxx |60* ^^^^^^^^^^ ^^^^ ^^^^^61* 10px elem 5px62* </pre>63*64* If an element is positioned before the start of its offsetParent, the65* startOffset may be negative. This can be used with setScrollOffset to66* reliably scroll to an element:67*68* <pre>69* var scrollOffset = goog.style.bidi.getOffsetStart(element);70* goog.style.bidi.setScrollOffset(element.offsetParent, scrollOffset);71* </pre>72*73* @see setScrollOffset74*75* @param {Element} element The element for which we need to determine the76* offsetStart position.77* @return {number} The offsetStart for that element.78*/79goog.style.bidi.getOffsetStart = function(element) {80'use strict';81element = /** @type {!HTMLElement} */ (element);82var offsetLeftForReal = element.offsetLeft;8384// The element might not have an offsetParent.85// For example, the node might not be attached to the DOM tree,86// and position:fixed children do not have an offset parent.87// Just try to do the best we can with what we have.88var bestParent = element.offsetParent;8990if (!bestParent && goog.style.getComputedPosition(element) == 'fixed') {91bestParent = goog.dom.getOwnerDocument(element).documentElement;92}9394// Just give up in this case.95if (!bestParent) {96return offsetLeftForReal;97}9899if (goog.userAgent.GECKO && !goog.userAgent.isVersionOrHigher(58)) {100// When calculating an element's offsetLeft, Firefox 57 and below101// erroneously subtracts the border width from the actual distance.102// So we need to add it back. (Fixed in FireFox 58+)103var borderWidths = goog.style.getBorderBox(bestParent);104offsetLeftForReal += borderWidths.left;105} else if (106goog.userAgent.isDocumentModeOrHigher(8) &&107!goog.userAgent.isDocumentModeOrHigher(9)) {108// When calculating an element's offsetLeft, IE8/9-Standards Mode109// erroneously adds the border width to the actual distance. So we need to110// subtract it.111var borderWidths = goog.style.getBorderBox(bestParent);112offsetLeftForReal -= borderWidths.left;113}114115if (goog.style.isRightToLeft(bestParent)) {116// Right edge of the element relative to the left edge of its parent.117var elementRightOffset = offsetLeftForReal + element.offsetWidth;118119// Distance from the parent's right edge to the element's right edge.120return bestParent.clientWidth - elementRightOffset;121}122123return offsetLeftForReal;124};125126127/**128* Sets the element's scrollLeft attribute so it is correctly scrolled by129* offsetStart pixels. This takes into account whether the element is RTL and130* the nuances of different browsers. To scroll to the "beginning" of an131* element use getOffsetStart to obtain the element's offsetStart value and then132* pass the value to setScrollOffset.133* @see getOffsetStart134* @param {Element} element The element to set scrollLeft on.135* @param {number} offsetStart The number of pixels to scroll the element.136* If this value is < 0, 0 is used.137*/138goog.style.bidi.setScrollOffset = function(element, offsetStart) {139'use strict';140offsetStart = Math.max(offsetStart, 0);141// In LTR and in "mirrored" browser RTL (such as IE), we set scrollLeft to142// the number of pixels to scroll.143// Otherwise, in RTL, we need to account for different browser behavior.144if (!goog.style.isRightToLeft(element)) {145element.scrollLeft = offsetStart;146} else if (goog.style.bidi.usesNegativeScrollLeftInRtl_()) {147element.scrollLeft = -offsetStart;148} else if (!goog.userAgent.EDGE_OR_IE) {149// Take the current scrollLeft value and move to the right by the150// offsetStart to get to the left edge of the element, and then by151// the clientWidth of the element to get to the right edge.152element.scrollLeft =153element.scrollWidth - offsetStart - element.clientWidth;154} else {155element.scrollLeft = offsetStart;156}157};158159160/**161* @return {boolean} Whether the current browser returns negative scrollLeft162* values for RTL elements. If true, then scrollLeft starts at 0 and then163* becomes more negative as the element is scrolled towards the left.164* @private165*/166goog.style.bidi.usesNegativeScrollLeftInRtl_ = function() {167'use strict';168var isSafari10Plus =169goog.userAgent.product.SAFARI && goog.userAgent.product.isVersion(10);170var isIOS10Plus = goog.userAgent.IOS && goog.userAgent.platform.isVersion(10);171const isChrome85Plus =172goog.userAgent.product.CHROME && goog.userAgent.product.isVersion(85);173return goog.userAgent.GECKO || isSafari10Plus || isIOS10Plus ||174isChrome85Plus;175};176177178/**179* Sets the element's left style attribute in LTR or right style attribute in180* RTL. Also clears the left attribute in RTL and the right attribute in LTR.181* @param {Element} elem The element to position.182* @param {number} left The left position in LTR; will be set as right in RTL.183* @param {?number} top The top position. If null only the left/right is set.184* @param {boolean} isRtl Whether we are in RTL mode.185*/186goog.style.bidi.setPosition = function(elem, left, top, isRtl) {187'use strict';188if (top !== null) {189elem.style.top = top + 'px';190}191if (isRtl) {192elem.style.right = left + 'px';193elem.style.left = '';194} else {195elem.style.left = left + 'px';196elem.style.right = '';197}198};199200201