From 9434aaa22c75d04a285e24867a45c70e65b4ec44 Mon Sep 17 00:00:00 2001
From: Higor Anjos <higor.anjos@conductor.com.br>
Date: Fri, 11 Oct 2019 22:46:51 -0300
Subject: [PATCH 1/7] Added animation when modal backdrop is static

---
 js/src/modal.js              | 35 ++++++++++++++++++++++++++++++++---
 js/tests/units/modal.spec.js | 28 ++++++++++++++++++++++++++++
 scss/_modal.scss             |  5 +++++
 3 files changed, 65 insertions(+), 3 deletions(-)

diff --git a/js/src/modal.js b/js/src/modal.js
index bee5e23f88..5e7b0a921b 100644
--- a/js/src/modal.js
+++ b/js/src/modal.js
@@ -50,6 +50,7 @@ const DefaultType = {
 
 const Event = {
   HIDE: `hide${EVENT_KEY}`,
+  HIDE_PREVENTED: `hidePrevented${EVENT_KEY}`,
   HIDDEN: `hidden${EVENT_KEY}`,
   SHOW: `show${EVENT_KEY}`,
   SHOWN: `shown${EVENT_KEY}`,
@@ -68,7 +69,8 @@ const ClassName = {
   BACKDROP: 'modal-backdrop',
   OPEN: 'modal-open',
   FADE: 'fade',
-  SHOW: 'show'
+  SHOW: 'show',
+  SCALE: 'scale'
 }
 
 const Selector = {
@@ -307,8 +309,22 @@ class Modal {
     if (this._isShown && this._config.keyboard) {
       EventHandler.on(this._element, Event.KEYDOWN_DISMISS, event => {
         if (event.which === ESCAPE_KEYCODE) {
-          event.preventDefault()
-          this.hide()
+          if (this._config.backdrop === 'static') {
+            const hideEvent = EventHandler.trigger(this._element, Event.HIDE_PREVENTED)
+            if (hideEvent.defaultPrevented) {
+              return
+            }
+
+            this._element.classList.add(ClassName.SCALE)
+            const modalTransitionDuration = getTransitionDurationFromElement(this._element)
+            EventHandler.one(this._element, TRANSITION_END, () => {
+              this._element.classList.remove(ClassName.SCALE)
+            })
+            emulateTransitionEnd(this._element, modalTransitionDuration)
+            this._element.focus()
+          } else {
+            this.hide()
+          }
         }
       })
     } else {
@@ -368,6 +384,19 @@ class Modal {
         }
 
         if (this._config.backdrop === 'static') {
+          const hideEvent = EventHandler.trigger(this._element, Event.HIDE_PREVENTED)
+
+          if (hideEvent.defaultPrevented) {
+            return
+          }
+
+          this._element.classList.add(ClassName.SCALE)
+          const modalTransitionDuration = getTransitionDurationFromElement(this._element)
+          EventHandler.one(this._element, TRANSITION_END, () => {
+            this._element.classList.remove(ClassName.SCALE)
+          })
+          emulateTransitionEnd(this._element, modalTransitionDuration)
+
           this._element.focus()
         } else {
           this.hide()
diff --git a/js/tests/units/modal.spec.js b/js/tests/units/modal.spec.js
index 604934785a..5054de430f 100644
--- a/js/tests/units/modal.spec.js
+++ b/js/tests/units/modal.spec.js
@@ -540,6 +540,34 @@ describe('Modal', () => {
       modal.show()
     })
 
+    it('should not close modal when clicking outside of modal-content if backdrop = static', done => {
+      fixtureEl.innerHTML =
+        '<div class="modal" data-backdrop="static" ><div class="modal-dialog" /></div>'
+
+      const modalEl = fixtureEl.querySelector('.modal')
+      const modal = new Modal(modalEl, {
+        backdrop: 'static'
+      })
+
+      const shownCallback = () => {
+        setTimeout(() => {
+          expect(modal._isShown).toEqual(true)
+          done()
+        }, 10)
+      }
+
+      modalEl.addEventListener('shown.bs.modal', () => {
+        modalEl.click()
+        shownCallback()
+      })
+
+      modalEl.addEventListener('hidden.bs.modal', () => {
+        throw new Error('Should not hide a modal')
+      })
+
+      modal.show()
+    })
+
     it('should not adjust the inline body padding when it does not overflow', done => {
       fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog" /></div>'
 
diff --git a/scss/_modal.scss b/scss/_modal.scss
index 6001d040dd..187dc7019b 100644
--- a/scss/_modal.scss
+++ b/scss/_modal.scss
@@ -48,6 +48,11 @@
   .modal.show & {
     transform: $modal-show-transform;
   }
+
+  // When trying to close, animate focus to scale
+  .modal.scale & {
+    transform: scale(1.02);
+  }
 }
 
 .modal-dialog-scrollable {
-- 
GitLab


From 9a28600a1ceff30a2cb9646e25848530642714e9 Mon Sep 17 00:00:00 2001
From: XhmikosR <xhmikosr@gmail.com>
Date: Sat, 12 Oct 2019 16:21:43 +0300
Subject: [PATCH 2/7] Update modal.spec.js

---
 js/tests/unit/modal.spec.js | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/js/tests/unit/modal.spec.js b/js/tests/unit/modal.spec.js
index 5054de430f..2edef22b2c 100644
--- a/js/tests/unit/modal.spec.js
+++ b/js/tests/unit/modal.spec.js
@@ -541,8 +541,7 @@ describe('Modal', () => {
     })
 
     it('should not close modal when clicking outside of modal-content if backdrop = static', done => {
-      fixtureEl.innerHTML =
-        '<div class="modal" data-backdrop="static" ><div class="modal-dialog" /></div>'
+      fixtureEl.innerHTML = '<div class="modal" data-backdrop="static" ><div class="modal-dialog" /></div>'
 
       const modalEl = fixtureEl.querySelector('.modal')
       const modal = new Modal(modalEl, {
-- 
GitLab


From 85e1c041caa6b5cbd0973683be6832044e7b03c8 Mon Sep 17 00:00:00 2001
From: Higor Anjos <higor.anjos@conductor.com.br>
Date: Mon, 14 Oct 2019 15:35:15 -0300
Subject: [PATCH 3/7] Refactored modal js code and changed classname

---
 js/src/modal.js  | 61 +++++++++++++++++++++---------------------------
 scss/_modal.scss |  2 +-
 2 files changed, 27 insertions(+), 36 deletions(-)

diff --git a/js/src/modal.js b/js/src/modal.js
index 5e7b0a921b..7865c76e7a 100644
--- a/js/src/modal.js
+++ b/js/src/modal.js
@@ -70,7 +70,7 @@ const ClassName = {
   OPEN: 'modal-open',
   FADE: 'fade',
   SHOW: 'show',
-  SCALE: 'scale'
+  STATIC: 'modal-static'
 }
 
 const Selector = {
@@ -309,22 +309,8 @@ class Modal {
     if (this._isShown && this._config.keyboard) {
       EventHandler.on(this._element, Event.KEYDOWN_DISMISS, event => {
         if (event.which === ESCAPE_KEYCODE) {
-          if (this._config.backdrop === 'static') {
-            const hideEvent = EventHandler.trigger(this._element, Event.HIDE_PREVENTED)
-            if (hideEvent.defaultPrevented) {
-              return
-            }
-
-            this._element.classList.add(ClassName.SCALE)
-            const modalTransitionDuration = getTransitionDurationFromElement(this._element)
-            EventHandler.one(this._element, TRANSITION_END, () => {
-              this._element.classList.remove(ClassName.SCALE)
-            })
-            emulateTransitionEnd(this._element, modalTransitionDuration)
-            this._element.focus()
-          } else {
-            this.hide()
-          }
+          // This will trigger a scale transition if the backdrop is static
+          this._triggerBackdropTransition()
         }
       })
     } else {
@@ -383,24 +369,8 @@ class Modal {
           return
         }
 
-        if (this._config.backdrop === 'static') {
-          const hideEvent = EventHandler.trigger(this._element, Event.HIDE_PREVENTED)
-
-          if (hideEvent.defaultPrevented) {
-            return
-          }
-
-          this._element.classList.add(ClassName.SCALE)
-          const modalTransitionDuration = getTransitionDurationFromElement(this._element)
-          EventHandler.one(this._element, TRANSITION_END, () => {
-            this._element.classList.remove(ClassName.SCALE)
-          })
-          emulateTransitionEnd(this._element, modalTransitionDuration)
-
-          this._element.focus()
-        } else {
-          this.hide()
-        }
+        // This will trigger a scale transition if the backdrop is static
+        this._triggerBackdropTransition()
       })
 
       if (animate) {
@@ -438,6 +408,27 @@ class Modal {
     }
   }
 
+  // This function will trigger a HIDE_PREVENTED event and do a scale animation if
+  // the backdrop is static
+  _triggerBackdropTransition() {
+    if (this._config.backdrop === 'static') {
+      const hideEvent = EventHandler.trigger(this._element, Event.HIDE_PREVENTED)
+      if (hideEvent.defaultPrevented) {
+        return
+      }
+
+      this._element.classList.add(ClassName.STATIC)
+      const modalTransitionDuration = getTransitionDurationFromElement(this._element)
+      EventHandler.one(this._element, TRANSITION_END, () => {
+        this._element.classList.remove(ClassName.STATIC)
+      })
+      emulateTransitionEnd(this._element, modalTransitionDuration)
+      this._element.focus()
+    } else {
+      this.hide()
+    }
+  }
+
   // ----------------------------------------------------------------------
   // the following methods are used to handle overflowing modals
   // ----------------------------------------------------------------------
diff --git a/scss/_modal.scss b/scss/_modal.scss
index 187dc7019b..78a6b55ee9 100644
--- a/scss/_modal.scss
+++ b/scss/_modal.scss
@@ -50,7 +50,7 @@
   }
 
   // When trying to close, animate focus to scale
-  .modal.scale & {
+  .modal.modal-static & {
     transform: scale(1.02);
   }
 }
-- 
GitLab


From bc97ef0b771ba63c9be3ac8594f4ec08e6d16694 Mon Sep 17 00:00:00 2001
From: Higor Anjos <higor.anjos@conductor.com.br>
Date: Mon, 14 Oct 2019 15:36:34 -0300
Subject: [PATCH 4/7] Added static backdrop info on docs

---
 site/content/docs/4.3/components/modal.md | 65 ++++++++++++++++++++++-
 1 file changed, 64 insertions(+), 1 deletion(-)

diff --git a/site/content/docs/4.3/components/modal.md b/site/content/docs/4.3/components/modal.md
index f82ee774e5..bb06ed5f3e 100644
--- a/site/content/docs/4.3/components/modal.md
+++ b/site/content/docs/4.3/components/modal.md
@@ -140,6 +140,65 @@ Toggle a working modal demo by clicking the button below. It will slide down and
 </div>
 {{< /highlight >}}
 
+### Static backdrop
+
+When backdrop is set to static, the modal will not close when clicking outside it. Click the button below to try it.
+
+<div id="staticBackdropLive" class="modal fade" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="staticBackdropLiveLabel" aria-hidden="true">
+  <div class="modal-dialog" role="document">
+    <div class="modal-content">
+      <div class="modal-header">
+        <h5 class="modal-title" id="staticBackdropLiveLabel">Modal title</h5>
+        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+          <span aria-hidden="true">&times;</span>
+        </button>
+      </div>
+      <div class="modal-body">
+        <p>I'll not close if you click outside me. Don't even try to press escape key.</p>
+      </div>
+      <div class="modal-footer">
+        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
+        <button type="button" class="btn btn-primary">Understood</button>
+      </div>
+    </div>
+  </div>
+</div>
+
+<div class="bd-example">
+  <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#staticBackdropLive">
+    Launch static backdrop modal
+  </button>
+</div>
+
+{{< highlight html >}}
+<!-- Button trigger modal -->
+<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#staticBackdrop">
+  Launch static backdrop modal
+</button>
+
+<!-- Modal -->
+<div class="modal fade" id="staticBackdrop" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="staticBackdropLabel" aria-hidden="true">
+  <div class="modal-dialog" role="document">
+    <div class="modal-content">
+      <div class="modal-header">
+        <h5 class="modal-title" id="staticBackdropLabel">Modal title</h5>
+        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+          <span aria-hidden="true">&times;</span>
+        </button>
+      </div>
+      <div class="modal-body">
+        ...
+      </div>
+      <div class="modal-footer">
+        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
+        <button type="button" class="btn btn-primary">Understood</button>
+      </div>
+    </div>
+  </div>
+</div>
+{{< /highlight >}}
+
+
 ### Scrolling long content
 
 When modals become too long for the user's viewport or device, they scroll independent of the page itself. Try the demo below to see what we mean.
@@ -753,7 +812,7 @@ Options can be passed via data attributes or JavaScript. For data attributes, ap
       <td>backdrop</td>
       <td>boolean or the string <code>'static'</code></td>
       <td>true</td>
-      <td>Includes a modal-backdrop element. Alternatively, specify <code>static</code> for a backdrop which doesn't close the modal on click.</td>
+      <td>Includes a modal-backdrop element. Alternatively, specify <code>static</code> for a backdrop which doesn't close the modal on click or on escape key press.</td>
     </tr>
     <tr>
       <td>keyboard</td>
@@ -859,6 +918,10 @@ Bootstrap's modal class exposes a few events for hooking into modal functionalit
       <td>hidden.bs.modal</td>
       <td>This event is fired when the modal has finished being hidden from the user (will wait for CSS transitions to complete).</td>
     </tr>
+    <tr>
+      <td>hidePrevented.bs.modal</td>
+      <td>This event is fired when the modal is shown, its backdrop is <code>static</code> and a click outside the modal or a scape key press is performed.</td>
+    </tr>
   </tbody>
 </table>
 
-- 
GitLab


From efcc341ec6b0cf25dbd395aaa6cd6d8edbbef486 Mon Sep 17 00:00:00 2001
From: Higor Anjos <higor.anjos@conductor.com.br>
Date: Wed, 16 Oct 2019 10:23:18 -0300
Subject: [PATCH 5/7] Removed comments on JS code

---
 js/src/modal.js | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/js/src/modal.js b/js/src/modal.js
index 7865c76e7a..e2b711e5be 100644
--- a/js/src/modal.js
+++ b/js/src/modal.js
@@ -309,7 +309,6 @@ class Modal {
     if (this._isShown && this._config.keyboard) {
       EventHandler.on(this._element, Event.KEYDOWN_DISMISS, event => {
         if (event.which === ESCAPE_KEYCODE) {
-          // This will trigger a scale transition if the backdrop is static
           this._triggerBackdropTransition()
         }
       })
@@ -369,7 +368,6 @@ class Modal {
           return
         }
 
-        // This will trigger a scale transition if the backdrop is static
         this._triggerBackdropTransition()
       })
 
@@ -408,8 +406,6 @@ class Modal {
     }
   }
 
-  // This function will trigger a HIDE_PREVENTED event and do a scale animation if
-  // the backdrop is static
   _triggerBackdropTransition() {
     if (this._config.backdrop === 'static') {
       const hideEvent = EventHandler.trigger(this._element, Event.HIDE_PREVENTED)
-- 
GitLab


From 10e443bf59e02606e98d0a9748f6173ff199197c Mon Sep 17 00:00:00 2001
From: XhmikosR <xhmikosr@gmail.com>
Date: Thu, 17 Oct 2019 09:52:35 +0300
Subject: [PATCH 6/7] Update modal.md

---
 site/content/docs/4.3/components/modal.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/site/content/docs/4.3/components/modal.md b/site/content/docs/4.3/components/modal.md
index bb06ed5f3e..fd1a04a621 100644
--- a/site/content/docs/4.3/components/modal.md
+++ b/site/content/docs/4.3/components/modal.md
@@ -154,7 +154,7 @@ When backdrop is set to static, the modal will not close when clicking outside i
         </button>
       </div>
       <div class="modal-body">
-        <p>I'll not close if you click outside me. Don't even try to press escape key.</p>
+        <p>I will not close if you click outside me. Don't even try to press escape key.</p>
       </div>
       <div class="modal-footer">
         <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
-- 
GitLab


From 20108a135b222150a1556f25504da21dafb0b33c Mon Sep 17 00:00:00 2001
From: Higor Anjos <higor.anjos@conductor.com.br>
Date: Fri, 25 Oct 2019 14:09:13 -0300
Subject: [PATCH 7/7] Made scale transform a variable

---
 scss/_modal.scss     | 2 +-
 scss/_variables.scss | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/scss/_modal.scss b/scss/_modal.scss
index 78a6b55ee9..381b0685e5 100644
--- a/scss/_modal.scss
+++ b/scss/_modal.scss
@@ -51,7 +51,7 @@
 
   // When trying to close, animate focus to scale
   .modal.modal-static & {
-    transform: scale(1.02);
+    transform: $modal-scale-transform;
   }
 }
 
diff --git a/scss/_variables.scss b/scss/_variables.scss
index b4dff2cf59..1adc5f5a08 100644
--- a/scss/_variables.scss
+++ b/scss/_variables.scss
@@ -1073,6 +1073,7 @@ $modal-sm:                          300px !default;
 $modal-fade-transform:              translate(0, -50px) !default;
 $modal-show-transform:              none !default;
 $modal-transition:                  transform .3s ease-out !default;
+$modal-scale-transform:             scale(1.02) !default;
 
 
 // Alerts
-- 
GitLab