From d1b4126a6274194992a28b1d3f44b23ce990a900 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20D=C4=85browski?= Date: Sat, 11 Aug 2018 00:07:45 +0100 Subject: [PATCH] fix(rtl): support applying dir="rtl" on DOM elements other than the body Create a single function to check text direction based on dir attribute on DOM element or document. Fixes #11016 Fixes #9754 --- src/components/gridList/grid-list.js | 5 ++-- src/components/menu/js/menuServiceProvider.js | 2 +- src/components/panel/panel.js | 2 +- src/components/slider/slider.js | 2 +- src/components/tabs/js/tabsController.js | 2 +- .../virtualRepeat/virtual-repeater.js | 9 +++--- src/core/util/util.js | 28 +++++++++++++++++-- 7 files changed, 36 insertions(+), 14 deletions(-) diff --git a/src/components/gridList/grid-list.js b/src/components/gridList/grid-list.js index be158da9850..033953c124d 100644 --- a/src/components/gridList/grid-list.js +++ b/src/components/gridList/grid-list.js @@ -93,7 +93,7 @@ angular.module('material.components.gridList', ['material.core']) * * */ -function GridListDirective($interpolate, $mdConstant, $mdGridLayout, $mdMedia) { +function GridListDirective($interpolate, $mdConstant, $mdGridLayout, $mdMedia, $mdUtil) { return { restrict: 'E', controller: GridListController, @@ -270,8 +270,7 @@ function GridListDirective($interpolate, $mdConstant, $mdGridLayout, $mdMedia) { // The width and horizontal position of each tile is always calculated the same way, but the // height and vertical position depends on the rowMode. - var ltr = document.dir != 'rtl' && document.body.dir != 'rtl'; - var style = ltr ? { + var style = (!$mdUtil.isRtl(attrs)) ? { left: POSITION({ unit: hUnit, offset: position.col, gutter: gutter }), width: DIMENSION({ unit: hUnit, span: spans.col, gutter: gutter }), // resets diff --git a/src/components/menu/js/menuServiceProvider.js b/src/components/menu/js/menuServiceProvider.js index c74c66eb996..3650f3cbb5d 100644 --- a/src/components/menu/js/menuServiceProvider.js +++ b/src/components/menu/js/menuServiceProvider.js @@ -494,7 +494,7 @@ function MenuProvider($$interimElementProvider) { throw new Error('Invalid target mode "' + positionMode.top + '" specified for md-menu on Y axis.'); } - var rtl = ($mdUtil.bidi() === 'rtl'); + var rtl = $mdUtil.isRtl(el); switch (positionMode.left) { case 'target': diff --git a/src/components/panel/panel.js b/src/components/panel/panel.js index b9dc317ca7e..242d40281a2 100644 --- a/src/components/panel/panel.js +++ b/src/components/panel/panel.js @@ -2541,7 +2541,7 @@ function MdPanelPosition($injector) { this._$window = $injector.get('$window'); /** @private {boolean} */ - this._isRTL = $injector.get('$mdUtil').bidi() === 'rtl'; + this._isRTL = $injector.get('$mdUtil').isRtl(); /** @private @const {!angular.$mdConstant} */ this._$mdConstant = $injector.get('$mdConstant'); diff --git a/src/components/slider/slider.js b/src/components/slider/slider.js index ae6ea09def9..fa90ae78184 100644 --- a/src/components/slider/slider.js +++ b/src/components/slider/slider.js @@ -647,7 +647,7 @@ function SliderDirective($$rAF, $window, $mdAria, $mdUtil, $mdConstant, $mdThemi var size = vertical ? sliderDimensions.height : sliderDimensions.width; var calc = (position - offset) / size; - if (!vertical && $mdUtil.bidi() === 'rtl') { + if (!vertical && $mdUtil.isRtl(attr)) { calc = 1 - calc; } diff --git a/src/components/tabs/js/tabsController.js b/src/components/tabs/js/tabsController.js index ba12bd02d27..77080d42395 100644 --- a/src/components/tabs/js/tabsController.js +++ b/src/components/tabs/js/tabsController.js @@ -962,6 +962,6 @@ function MdTabsController ($scope, $element, $window, $mdConstant, $mdTabInkRipp } function isRtl() { - return ($mdUtil.bidi() === 'rtl'); + return $mdUtil.isRtl($attrs); } } diff --git a/src/components/virtualRepeat/virtual-repeater.js b/src/components/virtualRepeat/virtual-repeater.js index c9e437be165..4621407b9b4 100644 --- a/src/components/virtualRepeat/virtual-repeater.js +++ b/src/components/virtualRepeat/virtual-repeater.js @@ -125,6 +125,8 @@ function VirtualRepeatContainerController($$rAF, $mdUtil, $mdConstant, $parse, $ this.oldElementSize = null; /** @type {!number} Maximum amount of pixels allowed for a single DOM element */ this.maxElementPixels = $mdConstant.ELEMENT_MAX_PIXELS; + /** @type {string} Direction of the text */ + this.ltr = !$mdUtil.isRtl(this.$attrs); if (this.$attrs.mdTopIndex) { /** @type {function(angular.Scope): number} Binds to topIndex on AngularJS scope */ @@ -385,13 +387,12 @@ VirtualRepeatContainerController.prototype.resetScroll = function() { VirtualRepeatContainerController.prototype.handleScroll_ = function() { - var ltr = document.dir !== 'rtl' && document.body.dir !== 'rtl'; - if (!ltr && !this.maxSize) { + if (!this.ltr && !this.maxSize) { this.scroller.scrollLeft = this.scrollSize; this.maxSize = this.scroller.scrollLeft; } var offset = this.isHorizontal() ? - (ltr?this.scroller.scrollLeft : this.maxSize - this.scroller.scrollLeft) + (this.ltr ? this.scroller.scrollLeft : this.maxSize - this.scroller.scrollLeft) : this.scroller.scrollTop; if (this.scrollSize < this.size) return; if (offset > this.scrollSize - this.size) { @@ -405,7 +406,7 @@ VirtualRepeatContainerController.prototype.handleScroll_ = function() { var numItems = Math.max(0, Math.floor(offset / itemSize) - NUM_EXTRA); var transform = (this.isHorizontal() ? 'translateX(' : 'translateY(') + - (!this.isHorizontal() || ltr ? (numItems * itemSize) : - (numItems * itemSize)) + 'px)'; + (!this.isHorizontal() || this.ltr ? (numItems * itemSize) : - (numItems * itemSize)) + 'px)'; this.scrollOffset = offset; this.offsetter.style.webkitTransform = transform; diff --git a/src/core/util/util.js b/src/core/util/util.js index c517ee804c5..5163b35c433 100644 --- a/src/core/util/util.js +++ b/src/core/util/util.js @@ -83,12 +83,34 @@ function UtilFactory($document, $timeout, $compile, $rootScope, $$mdAnimate, $in return $options.getOption ? $options.getOption(optionName) : $options[optionName]; }, + /** + * Determines the current 'dir'ectional value based on the value of 'dir' + * attribute of the element. If that is not defined, it will try to use + * a 'dir' attribute of the body or html tag. + * + * @param $attrs + * @returns {boolean} + */ + isRtl: function(attrs) { + var dir = angular.isDefined(attrs) && attrs.hasOwnProperty('dir') && attrs.dir; + + switch (dir) { + case 'ltr': + return false; + + case 'rtl': + return true; + } + + return ($document[0].dir === 'rtl' || $document[0].body.dir === 'rtl'); + }, + /** * Bi-directional accessor/mutator used to easily update an element's * property based on the current 'dir'ectional value. */ - bidi : function(element, property, lValue, rValue) { - var ltr = !($document[0].dir == 'rtl' || $document[0].body.dir == 'rtl'); + bidi: function(element, property, lValue, rValue) { + var ltr = !this.isRtl(); // If accessor if (arguments.length == 0) return ltr ? 'ltr' : 'rtl'; @@ -105,7 +127,7 @@ function UtilFactory($document, $timeout, $compile, $rootScope, $$mdAnimate, $in }, bidiProperty: function (element, lProperty, rProperty, value) { - var ltr = !($document[0].dir == 'rtl' || $document[0].body.dir == 'rtl'); + var ltr = !this.isRtl(); var elem = angular.element(element);