]> git.ipfire.org Git - thirdparty/bootstrap.git/commitdiff
Make carousel indicators actual buttons
authorPatrick H. Lauke <redux@splintered.co.uk>
Sun, 3 Jan 2021 11:06:58 +0000 (13:06 +0200)
committerXhmikosR <xhmikosr@gmail.com>
Thu, 28 Jan 2021 21:32:24 +0000 (23:32 +0200)
js/src/carousel.js
js/tests/integration/index.html
js/tests/unit/carousel.spec.js
js/tests/visual/carousel.html
scss/_carousel.scss
site/content/docs/5.0/components/carousel.md
site/content/docs/5.0/examples/carousel-rtl/index.html
site/content/docs/5.0/examples/carousel/index.html
site/content/docs/5.0/examples/cheatsheet-rtl/index.html

index 06a391419f0cd6ac68bee33bfd9edb57fe0d1137..9fd8aae3db30f1d95e7173ac6318f2436d84bae6 100644 (file)
@@ -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
+        }
       }
     }
   }
index 9855d5d34e03e18b05115611717ae21dc1ebed55..4c71bad9160d4bc543be7a00ee299300fad05205 100644 (file)
         </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">
index 6c98f20d1d48e3431c91944cb34d2ccc8c96f1c4..0571ac9af890d4b8dfaa59f12e2e879c89d7458a 100644 (file)
@@ -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()
       })
 
index 4658752e181567ccb29550e3d9ce2e3ea49b8f07..6b161812482e9d1b82de978ad9374f8f855ea1d7 100644 (file)
       <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">
index d9ff7e53529cbea4bf93f7f1677c4b6d949fc59b..43fa10077d2ef11570d41861e4584746e401e53d 100644 (file)
   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;
   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;
     filter: $carousel-dark-control-icon-filter;
   }
 
-  .carousel-indicators li {
+  .carousel-indicators [data-bs-target] {
     background-color: $carousel-dark-indicator-active-bg;
   }
 
index bee325bb4885e540d24a6e010bbe66dee69900aa..689e7a6aa28a8bd4c766d8c4a82e64f8a1ac9c6e 100644 (file)
@@ -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" >}}
index 30e7876f82c9a4cf3773b3966d680e63c2d1da50..7f162efd04c63306074cd7839199ded03dda4c55 100644 (file)
@@ -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" >}}
index d9d9f702b6cbdba4bdb5a6a7df74272ca2204da5..da5f3ab7aaecd72cf4598509d109f0df831050ae 100644 (file)
@@ -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" >}}
index 712c583dd5e403287c696e3d68964d6a1aee0a9b..1770067688a99ce13bcbd8f3fd585b6d58181889 100644 (file)
@@ -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="الشريحة الأولى" >}}