diff options
author | Gaƫl Poupard <gael.poupard@orange.com> | 2020-06-26 17:06:20 +0300 |
---|---|---|
committer | XhmikosR <xhmikosr@gmail.com> | 2020-12-04 08:52:03 +0300 |
commit | 9488978fb55286ba83e8193a871d1ff9815045b9 (patch) | |
tree | abb461d46722f107e54156709c88cf37ed9e24a6 /js | |
parent | 71ecc3323fb60ea05456470d10d17b614fe6dc04 (diff) |
feat(RTL): implement RTL
Using RTLCSS directives, renaming things to use logical names and following best practices.
Diffstat (limited to 'js')
-rw-r--r-- | js/src/carousel.js | 8 | ||||
-rw-r--r-- | js/src/dropdown.js | 27 | ||||
-rw-r--r-- | js/src/modal.js | 5 | ||||
-rw-r--r-- | js/src/popover.js | 2 | ||||
-rw-r--r-- | js/src/tooltip.js | 19 | ||||
-rw-r--r-- | js/src/util/index.js | 5 | ||||
-rw-r--r-- | js/tests/unit/dropdown.spec.js | 20 | ||||
-rw-r--r-- | js/tests/unit/toast.spec.js | 4 | ||||
-rw-r--r-- | js/tests/unit/tooltip.spec.js | 34 | ||||
-rw-r--r-- | js/tests/visual/dropdown.html | 34 | ||||
-rw-r--r-- | js/tests/visual/popover.html | 4 | ||||
-rw-r--r-- | js/tests/visual/scrollspy.html | 2 | ||||
-rw-r--r-- | js/tests/visual/toast.html | 10 | ||||
-rw-r--r-- | js/tests/visual/tooltip.html | 5 |
14 files changed, 115 insertions, 64 deletions
diff --git a/js/src/carousel.js b/js/src/carousel.js index 9c6fb53ee0..d8ad3a1354 100644 --- a/js/src/carousel.js +++ b/js/src/carousel.js @@ -79,8 +79,8 @@ const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}` const CLASS_NAME_CAROUSEL = 'carousel' const CLASS_NAME_ACTIVE = 'active' const CLASS_NAME_SLIDE = 'slide' -const CLASS_NAME_RIGHT = 'carousel-item-right' -const CLASS_NAME_LEFT = 'carousel-item-left' +const CLASS_NAME_END = 'carousel-item-end' +const CLASS_NAME_START = 'carousel-item-start' const CLASS_NAME_NEXT = 'carousel-item-next' const CLASS_NAME_PREV = 'carousel-item-prev' const CLASS_NAME_POINTER_EVENT = 'pointer-event' @@ -442,11 +442,11 @@ class Carousel extends BaseComponent { let eventDirectionName if (direction === DIRECTION_NEXT) { - directionalClassName = CLASS_NAME_LEFT + directionalClassName = CLASS_NAME_START orderClassName = CLASS_NAME_NEXT eventDirectionName = DIRECTION_LEFT } else { - directionalClassName = CLASS_NAME_RIGHT + directionalClassName = CLASS_NAME_END orderClassName = CLASS_NAME_PREV eventDirectionName = DIRECTION_RIGHT } diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 7b3bf5b4ec..0ac108ab81 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -11,6 +11,7 @@ import { getElementFromSelector, isElement, isVisible, + isRTL, noop, typeCheckConfig } from './util/index' @@ -53,9 +54,9 @@ const EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}` const CLASS_NAME_DISABLED = 'disabled' const CLASS_NAME_SHOW = 'show' const CLASS_NAME_DROPUP = 'dropup' -const CLASS_NAME_DROPRIGHT = 'dropright' -const CLASS_NAME_DROPLEFT = 'dropleft' -const CLASS_NAME_MENURIGHT = 'dropdown-menu-right' +const CLASS_NAME_DROPEND = 'dropend' +const CLASS_NAME_DROPSTART = 'dropstart' +const CLASS_NAME_MENUEND = 'dropdown-menu-end' const CLASS_NAME_NAVBAR = 'navbar' const CLASS_NAME_POSITION_STATIC = 'position-static' @@ -65,12 +66,12 @@ const SELECTOR_MENU = '.dropdown-menu' const SELECTOR_NAVBAR_NAV = '.navbar-nav' const SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)' -const PLACEMENT_TOP = 'top-start' -const PLACEMENT_TOPEND = 'top-end' -const PLACEMENT_BOTTOM = 'bottom-start' -const PLACEMENT_BOTTOMEND = 'bottom-end' -const PLACEMENT_RIGHT = 'right-start' -const PLACEMENT_LEFT = 'left-start' +const PLACEMENT_TOP = isRTL ? 'top-end' : 'top-start' +const PLACEMENT_TOPEND = isRTL ? 'top-start' : 'top-end' +const PLACEMENT_BOTTOM = isRTL ? 'bottom-end' : 'bottom-start' +const PLACEMENT_BOTTOMEND = isRTL ? 'bottom-start' : 'bottom-end' +const PLACEMENT_RIGHT = isRTL ? 'left-start' : 'right-start' +const PLACEMENT_LEFT = isRTL ? 'right-start' : 'left-start' const Default = { offset: 0, @@ -277,14 +278,14 @@ class Dropdown extends BaseComponent { // Handle dropup if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) { - placement = this._menu.classList.contains(CLASS_NAME_MENURIGHT) ? + placement = this._menu.classList.contains(CLASS_NAME_MENUEND) ? PLACEMENT_TOPEND : PLACEMENT_TOP - } else if (parentDropdown.classList.contains(CLASS_NAME_DROPRIGHT)) { + } else if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) { placement = PLACEMENT_RIGHT - } else if (parentDropdown.classList.contains(CLASS_NAME_DROPLEFT)) { + } else if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) { placement = PLACEMENT_LEFT - } else if (this._menu.classList.contains(CLASS_NAME_MENURIGHT)) { + } else if (this._menu.classList.contains(CLASS_NAME_MENUEND)) { placement = PLACEMENT_BOTTOMEND } diff --git a/js/src/modal.js b/js/src/modal.js index a9cf8ae6cf..94bf95f8ad 100644 --- a/js/src/modal.js +++ b/js/src/modal.js @@ -13,6 +13,7 @@ import { getElementFromSelector, getTransitionDurationFromElement, isVisible, + isRTL, reflow, typeCheckConfig } from './util/index' @@ -435,11 +436,11 @@ class Modal extends BaseComponent { const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight - if (!this._isBodyOverflowing && isModalOverflowing) { + if ((!this._isBodyOverflowing && isModalOverflowing && !isRTL) || (this._isBodyOverflowing && !isModalOverflowing && isRTL)) { this._element.style.paddingLeft = `${this._scrollbarWidth}px` } - if (this._isBodyOverflowing && !isModalOverflowing) { + if ((this._isBodyOverflowing && !isModalOverflowing && !isRTL) || (!this._isBodyOverflowing && isModalOverflowing && isRTL)) { this._element.style.paddingRight = `${this._scrollbarWidth}px` } } diff --git a/js/src/popover.js b/js/src/popover.js index 66dcb47b90..d8bd92eefb 100644 --- a/js/src/popover.js +++ b/js/src/popover.js @@ -115,7 +115,7 @@ class Popover extends Tooltip { // Private _addAttachmentClass(attachment) { - this.getTipElement().classList.add(`${CLASS_PREFIX}-${attachment}`) + this.getTipElement().classList.add(`${CLASS_PREFIX}-${this.updateAttachment(attachment)}`) } _getContent() { diff --git a/js/src/tooltip.js b/js/src/tooltip.js index 25599bb42f..17148ed9a6 100644 --- a/js/src/tooltip.js +++ b/js/src/tooltip.js @@ -14,6 +14,7 @@ import { getTransitionDurationFromElement, getUID, isElement, + isRTL, noop, typeCheckConfig } from './util/index' @@ -64,9 +65,9 @@ const DefaultType = { const AttachmentMap = { AUTO: 'auto', TOP: 'top', - RIGHT: 'right', + RIGHT: isRTL ? 'left' : 'right', BOTTOM: 'bottom', - LEFT: 'left' + LEFT: isRTL ? 'right' : 'left' } const Default = { @@ -453,6 +454,18 @@ class Tooltip extends BaseComponent { return title } + updateAttachment(attachment) { + if (attachment === 'right') { + return 'end' + } + + if (attachment === 'left') { + return 'start' + } + + return attachment + } + // Private _getPopperConfig(attachment) { @@ -485,7 +498,7 @@ class Tooltip extends BaseComponent { } _addAttachmentClass(attachment) { - this.getTipElement().classList.add(`${CLASS_PREFIX}-${attachment}`) + this.getTipElement().classList.add(`${CLASS_PREFIX}-${this.updateAttachment(attachment)}`) } _getOffset() { diff --git a/js/src/util/index.js b/js/src/util/index.js index 874827b168..96cadc65bc 100644 --- a/js/src/util/index.js +++ b/js/src/util/index.js @@ -186,6 +186,8 @@ const onDOMContentLoaded = callback => { } } +const isRTL = document.documentElement.dir === 'rtl' + export { TRANSITION_END, getUID, @@ -201,5 +203,6 @@ export { noop, reflow, getjQuery, - onDOMContentLoaded + onDOMContentLoaded, + isRTL } diff --git a/js/tests/unit/dropdown.spec.js b/js/tests/unit/dropdown.spec.js index 145763d20f..f6a5feb1b9 100644 --- a/js/tests/unit/dropdown.spec.js +++ b/js/tests/unit/dropdown.spec.js @@ -227,7 +227,7 @@ describe('Dropdown', () => { fixtureEl.innerHTML = [ '<div class="dropdown">', ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>', - ' <div class="dropdown-menu dropdown-menu-right">', + ' <div class="dropdown-menu dropdown-menu-end">', ' <a class="dropdown-item" href="#">Secondary link</a>', ' </div>', '</div>' @@ -273,7 +273,7 @@ describe('Dropdown', () => { fixtureEl.innerHTML = [ '<div class="dropup">', ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>', - ' <div class="dropdown-menu dropdown-menu-right">', + ' <div class="dropdown-menu dropdown-menu-end">', ' <a class="dropdown-item" href="#">Secondary link</a>', ' </div>', '</div>' @@ -292,9 +292,9 @@ describe('Dropdown', () => { dropdown.toggle() }) - it('should toggle a dropright', done => { + it('should toggle a dropend', done => { fixtureEl.innerHTML = [ - '<div class="dropright">', + '<div class="dropend">', ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>', ' <div class="dropdown-menu">', ' <a class="dropdown-item" href="#">Secondary link</a>', @@ -303,10 +303,10 @@ describe('Dropdown', () => { ].join('') const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - const droprightEl = fixtureEl.querySelector('.dropright') + const dropendEl = fixtureEl.querySelector('.dropend') const dropdown = new Dropdown(btnDropdown) - droprightEl.addEventListener('shown.bs.dropdown', () => { + dropendEl.addEventListener('shown.bs.dropdown', () => { expect(btnDropdown.classList.contains('show')).toEqual(true) expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true') done() @@ -315,9 +315,9 @@ describe('Dropdown', () => { dropdown.toggle() }) - it('should toggle a dropleft', done => { + it('should toggle a dropstart', done => { fixtureEl.innerHTML = [ - '<div class="dropleft">', + '<div class="dropstart">', ' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>', ' <div class="dropdown-menu">', ' <a class="dropdown-item" href="#">Secondary link</a>', @@ -326,10 +326,10 @@ describe('Dropdown', () => { ].join('') const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - const dropleftEl = fixtureEl.querySelector('.dropleft') + const dropstartEl = fixtureEl.querySelector('.dropstart') const dropdown = new Dropdown(btnDropdown) - dropleftEl.addEventListener('shown.bs.dropdown', () => { + dropstartEl.addEventListener('shown.bs.dropdown', () => { expect(btnDropdown.classList.contains('show')).toEqual(true) expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true') done() diff --git a/js/tests/unit/toast.spec.js b/js/tests/unit/toast.spec.js index a4ab4f76cd..cc873d1fe6 100644 --- a/js/tests/unit/toast.spec.js +++ b/js/tests/unit/toast.spec.js @@ -46,7 +46,7 @@ describe('Toast', () => { it('should close toast when close element with data-bs-dismiss attribute is set', done => { fixtureEl.innerHTML = [ '<div class="toast" data-bs-delay="1" data-bs-autohide="false" data-bs-animation="false">', - ' <button type="button" class="ml-2 mb-1 btn-close" data-bs-dismiss="toast" aria-label="Close"></button>', + ' <button type="button" class="ms-2 mb-1 btn-close" data-bs-dismiss="toast" aria-label="Close"></button>', '</div>' ].join('') @@ -78,7 +78,7 @@ describe('Toast', () => { fixtureEl.innerHTML = [ '<div class="toast" data-bs-autohide="false" data-bs-animation="false">', - ' <button type="button" class="ml-2 mb-1 btn-close" data-bs-dismiss="toast" aria-label="Close"></button>', + ' <button type="button" class="ms-2 mb-1 btn-close" data-bs-dismiss="toast" aria-label="Close"></button>', '</div>' ].join('') diff --git a/js/tests/unit/tooltip.spec.js b/js/tests/unit/tooltip.spec.js index b119807511..9ea9096de9 100644 --- a/js/tests/unit/tooltip.spec.js +++ b/js/tests/unit/tooltip.spec.js @@ -886,6 +886,40 @@ describe('Tooltip', () => { }) }) + describe('updateAttachment', () => { + it('should use end class name when right placement specified', done => { + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl, { + placement: 'right' + }) + + tooltipEl.addEventListener('inserted.bs.tooltip', () => { + expect(tooltip.getTipElement().classList.contains('bs-tooltip-end')).toEqual(true) + done() + }) + + tooltip.show() + }) + + it('should use start class name when left placement specified', done => { + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl, { + placement: 'left' + }) + + tooltipEl.addEventListener('inserted.bs.tooltip', () => { + expect(tooltip.getTipElement().classList.contains('bs-tooltip-start')).toEqual(true) + done() + }) + + tooltip.show() + }) + }) + describe('setElementContent', () => { it('should do nothing if the element is null', () => { fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' diff --git a/js/tests/visual/dropdown.html b/js/tests/visual/dropdown.html index 9dad43543e..930940a157 100644 --- a/js/tests/visual/dropdown.html +++ b/js/tests/visual/dropdown.html @@ -90,9 +90,9 @@ <div class="btn-group"> <button type="button" class="btn btn-secondary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false"> - This dropdown's menu is right-aligned + This dropdown's menu is end-aligned </button> - <div class="dropdown-menu dropdown-menu-right"> + <div class="dropdown-menu dropdown-menu-end"> <button class="dropdown-item" type="button">Action</button> <button class="dropdown-item" type="button">Another action</button> <button class="dropdown-item" type="button">Something else here</button> @@ -102,19 +102,19 @@ <div class="col-sm-12 mt-4"> <div class="btn-group dropup" role="group"> - <a href="#" class="btn btn-secondary">Dropup split align right</a> + <a href="#" class="btn btn-secondary">Dropup split align end</a> <button type="button" id="dropdown-page-subheader-button-3" class="btn btn-secondary dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false"> <span class="visually-hidden">Product actions</span> </button> - <div class="dropdown-menu dropdown-menu-right"> + <div class="dropdown-menu dropdown-menu-end"> <button class="dropdown-item" type="button">Action</button> <button class="dropdown-item" type="button">Another action</button> <button class="dropdown-item" type="button">Something else here with a long text</button> </div> </div> <div class="btn-group dropup"> - <button type="button" class="btn btn-secondary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropup align right</button> - <div class="dropdown-menu dropdown-menu-right"> + <button type="button" class="btn btn-secondary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropup align end</button> + <div class="dropdown-menu dropdown-menu-end"> <button class="dropdown-item" type="button">Action</button> <button class="dropdown-item" type="button">Another action</button> <button class="dropdown-item" type="button">Something else here with a long text</button> @@ -123,8 +123,8 @@ </div> <div class="col-sm-12 mt-4"> - <div class="btn-group dropright" role="group"> - <a href="#" class="btn btn-secondary">Dropright split</a> + <div class="btn-group dropend" role="group"> + <a href="#" class="btn btn-secondary">Dropend split</a> <button type="button" id="dropdown-page-subheader-button-4" class="btn btn-secondary dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false"> <span class="visually-hidden">Product actions</span> </button> @@ -134,9 +134,9 @@ <button class="dropdown-item" type="button">Something else here with a long text</button> </div> </div> - <div class="btn-group dropright"> + <div class="btn-group dropend"> <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuRight" data-bs-toggle="dropdown" aria-expanded="false"> - Dropright + Dropend </button> <div class="dropdown-menu" aria-labelledby="dropdownMenuRight"> <button class="dropdown-item" type="button">Action</button> @@ -144,9 +144,9 @@ <button class="dropdown-item" type="button">Something else here</button> </div> </div> - <!-- dropleft --> - <div class="btn-group dropleft" role="group"> - <a href="#" class="btn btn-secondary">Dropleft split</a> + <!-- dropstart --> + <div class="btn-group dropstart" role="group"> + <a href="#" class="btn btn-secondary">Dropstart split</a> <button type="button" id="dropdown-page-subheader-button-5" class="btn btn-secondary dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false"> <span class="visually-hidden">Product actions</span> </button> @@ -156,11 +156,11 @@ <button class="dropdown-item" type="button">Something else here with a long text</button> </div> </div> - <div class="btn-group dropleft"> - <button class="btn btn-secondary dropdown-toggle" type="button" id="dropleftMenu" data-bs-toggle="dropdown" aria-expanded="false"> - Dropleft + <div class="btn-group dropstart"> + <button class="btn btn-secondary dropdown-toggle" type="button" id="dropstartMenu" data-bs-toggle="dropdown" aria-expanded="false"> + Dropstart </button> - <div class="dropdown-menu" aria-labelledby="dropleftMenu"> + <div class="dropdown-menu" aria-labelledby="dropstartMenu"> <button class="dropdown-item" type="button">Action</button> <button class="dropdown-item" type="button">Another action</button> <button class="dropdown-item" type="button">Something else here</button> diff --git a/js/tests/visual/popover.html b/js/tests/visual/popover.html index e33de5f0bd..c758253969 100644 --- a/js/tests/visual/popover.html +++ b/js/tests/visual/popover.html @@ -19,7 +19,7 @@ </button> <button type="button" class="btn btn-secondary" data-bs-container="body" data-bs-toggle="popover" data-bs-placement="right" data-bs-content="Vivamus sagittis lacus vel augue laoreet rutrum faucibus."> - Popover on right + Popover on end </button> <button type="button" class="btn btn-secondary" data-bs-container="body" data-bs-toggle="popover" data-bs-placement="bottom" data-bs-content="Vivamus sagittis lacus vel augue laoreet rutrum faucibus."> @@ -27,7 +27,7 @@ </button> <button type="button" class="btn btn-secondary" data-bs-container="body" data-bs-toggle="popover" data-bs-placement="left" data-bs-content="Vivamus sagittis lacus vel augue laoreet rutrum faucibus."> - Popover on left + Popover on start </button> </div> diff --git a/js/tests/visual/scrollspy.html b/js/tests/visual/scrollspy.html index c86927d991..7b07932ebd 100644 --- a/js/tests/visual/scrollspy.html +++ b/js/tests/visual/scrollspy.html @@ -16,7 +16,7 @@ <span class="navbar-toggler-icon"></span> </button> <div class="navbar-collapse collapse" id="navbarSupportedContent"> - <ul class="navbar-nav mr-auto"> + <ul class="navbar-nav me-auto"> <li class="nav-item"> <a class="nav-link" href="#fat">@fat</a> </li> diff --git a/js/tests/visual/toast.html b/js/tests/visual/toast.html index c26278d948..4765026f33 100644 --- a/js/tests/visual/toast.html +++ b/js/tests/visual/toast.html @@ -28,8 +28,8 @@ <div class="notifications"> <div id="toastAutoHide" class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-bs-delay="2000"> <div class="toast-header"> - <span class="d-block bg-primary rounded mr-2" style="width: 20px; height: 20px;"></span> - <strong class="mr-auto">Bootstrap</strong> + <span class="d-block bg-primary rounded me-2" style="width: 20px; height: 20px;"></span> + <strong class="me-auto">Bootstrap</strong> <small>11 mins ago</small> </div> <div class="toast-body"> @@ -39,10 +39,10 @@ <div class="toast" data-bs-autohide="false" role="alert" aria-live="assertive" aria-atomic="true"> <div class="toast-header"> - <span class="d-block bg-primary rounded mr-2" style="width: 20px; height: 20px;"></span> - <strong class="mr-auto">Bootstrap</strong> + <span class="d-block bg-primary rounded me-2" style="width: 20px; height: 20px;"></span> + <strong class="me-auto">Bootstrap</strong> <small class="text-muted">2 seconds ago</small> - <button type="button" class="ml-2 mb-1 btn-close" data-bs-dismiss="toast" aria-label="Close"></button> + <button type="button" class="ms-2 mb-1 btn-close" data-bs-dismiss="toast" aria-label="Close"></button> </div> <div class="toast-body"> Heads up, toasts will stack automatically diff --git a/js/tests/visual/tooltip.html b/js/tests/visual/tooltip.html index 93536a0443..bade26a6c0 100644 --- a/js/tests/visual/tooltip.html +++ b/js/tests/visual/tooltip.html @@ -10,7 +10,6 @@ border: 1px solid; width: 100px; height: 50px; - border: 1px solid; margin-left: 50px; transform: rotate(270deg); margin-top: 100px; @@ -34,13 +33,13 @@ Tooltip on top </button> <button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="right" title="Tooltip on right"> - Tooltip on right + Tooltip on end </button> <button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Tooltip on bottom"> Tooltip on bottom </button> <button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="left" title="Tooltip on left"> - Tooltip on left + Tooltip on start </button> </p> </div> |