diff options
| author | Patrick H. Lauke <[email protected]> | 2021-01-03 13:06:58 +0200 |
|---|---|---|
| committer | XhmikosR <[email protected]> | 2021-01-28 23:32:24 +0200 |
| commit | a882614c455fa0fb3014bd474df382e085263f56 (patch) | |
| tree | daa71695c744920ffce65801ce869f963bb42357 | |
| parent | 1fd34a1a2cbda6bcb55c206a1bae584c9f969923 (diff) | |
| download | bootstrap-a882614c455fa0fb3014bd474df382e085263f56.tar.xz bootstrap-a882614c455fa0fb3014bd474df382e085263f56.zip | |
Make carousel indicators actual buttons
| -rw-r--r-- | js/src/carousel.js | 20 | ||||
| -rw-r--r-- | js/tests/integration/index.html | 10 | ||||
| -rw-r--r-- | js/tests/unit/carousel.spec.js | 14 | ||||
| -rw-r--r-- | js/tests/visual/carousel.html | 10 | ||||
| -rw-r--r-- | scss/_carousel.scss | 15 | ||||
| -rw-r--r-- | site/content/docs/5.0/components/carousel.md | 30 | ||||
| -rw-r--r-- | site/content/docs/5.0/examples/carousel-rtl/index.html | 10 | ||||
| -rw-r--r-- | site/content/docs/5.0/examples/carousel/index.html | 10 | ||||
| -rw-r--r-- | site/content/docs/5.0/examples/cheatsheet-rtl/index.html | 10 |
9 files changed, 70 insertions, 59 deletions
diff --git a/js/src/carousel.js b/js/src/carousel.js index 06a391419..9fd8aae3d 100644 --- a/js/src/carousel.js +++ b/js/src/carousel.js @@ -90,6 +90,7 @@ const SELECTOR_ITEM = '.carousel-item' const SELECTOR_ITEM_IMG = '.carousel-item img' const SELECTOR_NEXT_PREV = '.carousel-item-next, .carousel-item-prev' const SELECTOR_INDICATORS = '.carousel-indicators' +const SELECTOR_INDICATOR = '[data-bs-target]' const SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]' const SELECTOR_DATA_RIDE = '[data-bs-ride="carousel"]' @@ -405,18 +406,21 @@ class Carousel extends BaseComponent { _setActiveIndicatorElement(element) { if (this._indicatorsElement) { - const indicators = SelectorEngine.find(SELECTOR_ACTIVE, this._indicatorsElement) + const activeIndicators = SelectorEngine.find(SELECTOR_ACTIVE, this._indicatorsElement) - for (let i = 0; i < indicators.length; i++) { - indicators[i].classList.remove(CLASS_NAME_ACTIVE) + for (let i = 0; i < activeIndicators.length; i++) { + activeIndicators[i].classList.remove(CLASS_NAME_ACTIVE) + activeIndicators[i].removeAttribute('aria-current') } - const nextIndicator = this._indicatorsElement.children[ - this._getItemIndex(element) - ] + const indicators = SelectorEngine.find(SELECTOR_INDICATOR, this._indicatorsElement) - if (nextIndicator) { - nextIndicator.classList.add(CLASS_NAME_ACTIVE) + for (let i = 0; i < indicators.length; i++) { + if (Number.parseInt(indicators[i].getAttribute('data-bs-slide-to'), 10) === this._getItemIndex(element)) { + indicators[i].classList.add(CLASS_NAME_ACTIVE) + indicators[i].setAttribute('aria-current', 'true') + break + } } } } diff --git a/js/tests/integration/index.html b/js/tests/integration/index.html index 9855d5d34..4c71bad91 100644 --- a/js/tests/integration/index.html +++ b/js/tests/integration/index.html @@ -20,11 +20,11 @@ </button> <div id="carouselExampleIndicators" class="carousel slide mt-2" data-bs-ride="carousel"> - <ol class="carousel-indicators"> - <li data-bs-target="#carouselExampleIndicators" data-bs-slide-to="0"></li> - <li data-bs-target="#carouselExampleIndicators" data-bs-slide-to="1" class="active"></li> - <li data-bs-target="#carouselExampleIndicators" data-bs-slide-to="2"></li> - </ol> + <div class="carousel-indicators"> + <button type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide-to="0" aria-label="Slide 1"></button> + <button type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide-to="1" class="active" aria-current="true" aria-label="Slide 2"></button> + <button type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide-to="2" aria-label="Slide 3"></button> + </div> <div class="carousel-inner"> <div class="carousel-item"> diff --git a/js/tests/unit/carousel.spec.js b/js/tests/unit/carousel.spec.js index 6c98f20d1..0571ac9af 100644 --- a/js/tests/unit/carousel.spec.js +++ b/js/tests/unit/carousel.spec.js @@ -659,11 +659,11 @@ describe('Carousel', () => { it('should update indicators if present', done => { fixtureEl.innerHTML = [ '<div id="myCarousel" class="carousel slide">', - ' <ol class="carousel-indicators">', - ' <li data-bs-target="#myCarousel" data-bs-slide-to="0" class="active"></li>', - ' <li id="secondIndicator" data-bs-target="#myCarousel" data-bs-slide-to="1"></li>', - ' <li data-bs-target="#myCarousel" data-bs-slide-to="2"></li>', - ' </ol>', + ' <div class="carousel-indicators">', + ' <button type="button" id="firstIndicator" data-bs-target="myCarousel" data-bs-slide-to="0" class="active" aria-current="true" aria-label="Slide 1"></button>', + ' <button type="button" id="secondIndicator" data-bs-target="myCarousel" data-bs-slide-to="1" aria-label="Slide 2"></button>', + ' <button type="button" data-bs-target="myCarousel" data-bs-slide-to="2" aria-label="Slide 3"></button>', + ' </div>', ' <div class="carousel-inner">', ' <div class="carousel-item active">item 1</div>', ' <div class="carousel-item" data-bs-interval="7">item 2</div>', @@ -673,11 +673,15 @@ describe('Carousel', () => { ].join('') const carouselEl = fixtureEl.querySelector('#myCarousel') + const firstIndicator = fixtureEl.querySelector('#firstIndicator') const secondIndicator = fixtureEl.querySelector('#secondIndicator') const carousel = new Carousel(carouselEl) carouselEl.addEventListener('slid.bs.carousel', () => { + expect(firstIndicator.classList.contains('active')).toEqual(false) + expect(firstIndicator.hasAttribute('aria-current')).toEqual(false) expect(secondIndicator.classList.contains('active')).toEqual(true) + expect(secondIndicator.getAttribute('aria-current')).toEqual('true') done() }) diff --git a/js/tests/visual/carousel.html b/js/tests/visual/carousel.html index 4658752e1..6b1618124 100644 --- a/js/tests/visual/carousel.html +++ b/js/tests/visual/carousel.html @@ -18,11 +18,11 @@ <p>The transition duration should be around 2s. Also, the carousel shouldn't slide when its window/tab is hidden. Check the console log.</p> <div id="carousel-example-generic" class="carousel slide" data-bs-ride="carousel"> - <ol class="carousel-indicators"> - <li data-bs-target="#carousel-example-generic" data-bs-slide-to="0" class="active"></li> - <li data-bs-target="#carousel-example-generic" data-bs-slide-to="1"></li> - <li data-bs-target="#carousel-example-generic" data-bs-slide-to="2"></li> - </ol> + <div class="carousel-indicators"> + <button type="button" data-bs-target="#carousel-example-generic" data-bs-slide-to="0" class="active" aria-current="true" aria-label="Slide 1"></button> + <button type="button" data-bs-target="#carousel-example-generic" data-bs-slide-to="1" aria-label="Slide 2"></button> + <button type="button" data-bs-target="#carousel-example-generic" data-bs-slide-to="2" aria-label="Slide 3"></button> + </div> <div class="carousel-inner"> <div class="carousel-item active"> <img src="https://i.imgur.com/iEZgY7Y.jpg" alt="First slide"> diff --git a/scss/_carousel.scss b/scss/_carousel.scss index d9ff7e535..43fa10077 100644 --- a/scss/_carousel.scss +++ b/scss/_carousel.scss @@ -150,10 +150,10 @@ background-image: escape-svg($carousel-control-next-icon-bg); } -// Optional indicator pips +// Optional indicator pips/controls // -// Add an ordered list with the following class and add a list item for each -// slide your carousel holds. +// Add an container (such as a list) with the following class and add an item (ideally a focusable control, +// like a button) with data-bs-target for each slide your carousel holds. .carousel-indicators { position: absolute; @@ -163,23 +163,26 @@ z-index: 2; display: flex; justify-content: center; - padding-left: 0; // override <ol> default + padding: 0; // Use the .carousel-control's width as margin so we don't overlay those margin-right: $carousel-control-width; + margin-bottom: 1rem; margin-left: $carousel-control-width; list-style: none; - li { + [data-bs-target] { box-sizing: content-box; flex: 0 1 auto; width: $carousel-indicator-width; height: $carousel-indicator-height; + padding: 0; margin-right: $carousel-indicator-spacer; margin-left: $carousel-indicator-spacer; text-indent: -999px; cursor: pointer; background-color: $carousel-indicator-active-bg; background-clip: padding-box; + border: 0; // Use transparent borders to increase the hit area by 10px on top and bottom. border-top: $carousel-indicator-hit-area-height solid transparent; border-bottom: $carousel-indicator-hit-area-height solid transparent; @@ -216,7 +219,7 @@ filter: $carousel-dark-control-icon-filter; } - .carousel-indicators li { + .carousel-indicators [data-bs-target] { background-color: $carousel-dark-indicator-active-bg; } diff --git a/site/content/docs/5.0/components/carousel.md b/site/content/docs/5.0/components/carousel.md index bee325bb4..689e7a6aa 100644 --- a/site/content/docs/5.0/components/carousel.md +++ b/site/content/docs/5.0/components/carousel.md @@ -78,11 +78,11 @@ You can also add the indicators to the carousel, alongside the controls, too. {{< example >}} <div id="carouselExampleIndicators" class="carousel slide" data-bs-ride="carousel"> - <ol class="carousel-indicators"> - <li data-bs-target="#carouselExampleIndicators" data-bs-slide-to="0" class="active"></li> - <li data-bs-target="#carouselExampleIndicators" data-bs-slide-to="1"></li> - <li data-bs-target="#carouselExampleIndicators" data-bs-slide-to="2"></li> - </ol> + <div class="carousel-indicators"> + <button type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide-to="0" class="active" aria-current="true" aria-label="Slide 1"></button> + <button type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide-to="1" aria-label="Slide 2"></button> + <button type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide-to="2" aria-label="Slide 3"></button> + </div> <div class="carousel-inner"> <div class="carousel-item active"> {{< placeholder width="800" height="400" class="bd-placeholder-img-lg d-block w-100" color="#555" background="#777" text="First slide" >}} @@ -111,11 +111,11 @@ Add captions to your slides easily with the `.carousel-caption` element within a {{< example >}} <div id="carouselExampleCaptions" class="carousel slide" data-bs-ride="carousel"> - <ol class="carousel-indicators"> - <li data-bs-target="#carouselExampleCaptions" data-bs-slide-to="0" class="active"></li> - <li data-bs-target="#carouselExampleCaptions" data-bs-slide-to="1"></li> - <li data-bs-target="#carouselExampleCaptions" data-bs-slide-to="2"></li> - </ol> + <div class="carousel-indicators"> + <button type="button" data-bs-target="#carouselExampleCaptions" data-bs-slide-to="0" class="active" aria-current="true" aria-label="Slide 1"></button> + <button type="button" data-bs-target="#carouselExampleCaptions" data-bs-slide-to="1" aria-label="Slide 2"></button> + <button type="button" data-bs-target="#carouselExampleCaptions" data-bs-slide-to="2" aria-label="Slide 3"></button> + </div> <div class="carousel-inner"> <div class="carousel-item active"> {{< placeholder width="800" height="400" class="bd-placeholder-img-lg d-block w-100" color="#555" background="#777" text="First slide" >}} @@ -240,11 +240,11 @@ Add `.carousel-dark` to the `.carousel` for darker controls, indicators, and cap {{< example >}} <div id="carouselExampleDark" class="carousel carousel-dark slide" data-bs-ride="carousel"> - <ol class="carousel-indicators"> - <li data-bs-target="#carouselExampleDark" data-bs-slide-to="0" class="active"></li> - <li data-bs-target="#carouselExampleDark" data-bs-slide-to="1"></li> - <li data-bs-target="#carouselExampleDark" data-bs-slide-to="2"></li> - </ol> + <div class="carousel-indicators"> + <button type="button" data-bs-target="#carouselExampleDark" data-bs-slide-to="0" class="active" aria-current="true" aria-label="Slide 1"></button> + <button type="button" data-bs-target="#carouselExampleDark" data-bs-slide-to="1" aria-label="Slide 2"></button> + <button type="button" data-bs-target="#carouselExampleDark" data-bs-slide-to="2" aria-label="Slide 3"></button> + </div> <div class="carousel-inner"> <div class="carousel-item active" data-bs-interval="10000"> {{< placeholder width="800" height="400" class="bd-placeholder-img-lg d-block w-100" color="#aaa" background="#f5f5f5" text="First slide" >}} diff --git a/site/content/docs/5.0/examples/carousel-rtl/index.html b/site/content/docs/5.0/examples/carousel-rtl/index.html index 30e7876f8..7f162efd0 100644 --- a/site/content/docs/5.0/examples/carousel-rtl/index.html +++ b/site/content/docs/5.0/examples/carousel-rtl/index.html @@ -37,11 +37,11 @@ extra_css: <main> <div id="myCarousel" class="carousel slide" data-bs-ride="carousel"> - <ol class="carousel-indicators"> - <li data-bs-target="#myCarousel" data-bs-slide-to="0" class="active"></li> - <li data-bs-target="#myCarousel" data-bs-slide-to="1"></li> - <li data-bs-target="#myCarousel" data-bs-slide-to="2"></li> - </ol> + <div class="carousel-indicators"> + <button type="button" data-bs-target="#myCarousel" data-bs-slide-to="0" class="active" aria-current="true" aria-label="Slide 1"></button> + <button type="button" data-bs-target="#myCarousel" data-bs-slide-to="1" aria-label="Slide 2"></button> + <button type="button" data-bs-target="#myCarousel" data-bs-slide-to="2" aria-label="Slide 3"></button> + </div> <div class="carousel-inner"> <div class="carousel-item active"> {{< placeholder width="100%" height="100%" background="#777" color="#777" text="false" title="false" >}} diff --git a/site/content/docs/5.0/examples/carousel/index.html b/site/content/docs/5.0/examples/carousel/index.html index d9d9f702b..da5f3ab7a 100644 --- a/site/content/docs/5.0/examples/carousel/index.html +++ b/site/content/docs/5.0/examples/carousel/index.html @@ -36,11 +36,11 @@ extra_css: <main> <div id="myCarousel" class="carousel slide" data-bs-ride="carousel"> - <ol class="carousel-indicators"> - <li data-bs-target="#myCarousel" data-bs-slide-to="0" class="active"></li> - <li data-bs-target="#myCarousel" data-bs-slide-to="1"></li> - <li data-bs-target="#myCarousel" data-bs-slide-to="2"></li> - </ol> + <div class="carousel-indicators"> + <button type="button" data-bs-target="#myCarousel" data-bs-slide-to="0" class="active" aria-current="true" aria-label="Slide 1"></button> + <button type="button" data-bs-target="#myCarousel" data-bs-slide-to="1" aria-label="Slide 2"></button> + <button type="button" data-bs-target="#myCarousel" data-bs-slide-to="2" aria-label="Slide 3"></button> + </div> <div class="carousel-inner"> <div class="carousel-item active"> {{< placeholder width="100%" height="100%" background="#777" color="#777" text="false" title="false" >}} diff --git a/site/content/docs/5.0/examples/cheatsheet-rtl/index.html b/site/content/docs/5.0/examples/cheatsheet-rtl/index.html index 712c583dd..177006768 100644 --- a/site/content/docs/5.0/examples/cheatsheet-rtl/index.html +++ b/site/content/docs/5.0/examples/cheatsheet-rtl/index.html @@ -862,11 +862,11 @@ direction: rtl <div> {{< example show_markup="false" >}} <div id="carouselExampleCaptions" class="carousel slide" data-bs-ride="carousel"> - <ol class="carousel-indicators"> - <li data-bs-target="#carouselExampleCaptions" data-bs-slide-to="0" class="active"></li> - <li data-bs-target="#carouselExampleCaptions" data-bs-slide-to="1"></li> - <li data-bs-target="#carouselExampleCaptions" data-bs-slide-to="2"></li> - </ol> + <div class="carousel-indicators"> + <button type="button" data-bs-target="#carouselExampleCaptions" data-bs-slide-to="0" class="active" aria-current="true" aria-label="Slide 1"></button> + <button type="button" data-bs-target="#carouselExampleCaptions" data-bs-slide-to="1" aria-label="Slide 2"></button> + <button type="button" data-bs-target="#carouselExampleCaptions" data-bs-slide-to="2" aria-label="Slide 3"></button> + </div> <div class="carousel-inner"> <div class="carousel-item active"> {{< placeholder width="800" height="400" class="bd-placeholder-img-lg d-block w-100" color="#555" background="#777" text="الشريحة الأولى" >}} |
