From 0b16c8c6d9a9690d537bd08eac8a8292ebf938cd Mon Sep 17 00:00:00 2001
From: Johann-S <johann.servoire@gmail.com>
Date: Mon, 21 Aug 2017 09:11:37 +0200
Subject: [PATCH] alert without jquery

---
 js/src/alert.js                          | 37 ++++++++---------
 js/src/dom/data.js                       | 51 ++++++++++++++++++++++++
 js/src/dom/{event.js => eventHandler.js} | 16 ++++----
 js/src/dom/selectorEngine.js             | 42 +++++++++++++++++++
 js/src/util.js                           |  4 +-
 js/tests/index.html                      |  4 +-
 js/tests/unit/.eslintrc.json             |  3 +-
 js/tests/unit/alert.js                   | 23 ++++++-----
 js/tests/visual/alert.html               |  4 +-
 js/tests/visual/button.html              |  2 +-
 js/tests/visual/carousel.html            |  2 +-
 js/tests/visual/collapse.html            |  2 +-
 js/tests/visual/dropdown.html            |  2 +-
 js/tests/visual/modal.html               |  3 +-
 js/tests/visual/popover.html             |  3 +-
 js/tests/visual/scrollspy.html           |  2 +-
 js/tests/visual/tab.html                 |  2 +-
 17 files changed, 149 insertions(+), 53 deletions(-)
 create mode 100644 js/src/dom/data.js
 rename js/src/dom/{event.js => eventHandler.js} (68%)
 create mode 100644 js/src/dom/selectorEngine.js

diff --git a/js/src/alert.js b/js/src/alert.js
index ab36a8d363..87209a8608 100644
--- a/js/src/alert.js
+++ b/js/src/alert.js
@@ -5,7 +5,9 @@
  * --------------------------------------------------------------------------
  */
 
-import $ from 'jquery'
+import Data from './dom/data'
+import EventHandler from './dom/eventHandler'
+import SelectorEngine from './dom/selectorEngine'
 import Util from './util'
 
 /**
@@ -64,7 +66,7 @@ class Alert {
 
     const customEvent = this._triggerCloseEvent(rootElement)
 
-    if (customEvent.isDefaultPrevented()) {
+    if (customEvent.defaultPrevented) {
       return
     }
 
@@ -72,7 +74,7 @@ class Alert {
   }
 
   dispose() {
-    $.removeData(this._element, DATA_KEY)
+    Data.removeData(this._element, DATA_KEY)
     this._element = null
   }
 
@@ -87,52 +89,45 @@ class Alert {
     }
 
     if (!parent) {
-      parent = $(element).closest(`.${ClassName.ALERT}`)[0]
+      parent = SelectorEngine.closest(element, `.${ClassName.ALERT}`)
     }
 
     return parent
   }
 
   _triggerCloseEvent(element) {
-    const closeEvent = $.Event(Event.CLOSE)
-
-    $(element).trigger(closeEvent)
-    return closeEvent
+    return EventHandler.trigger(element, Event.CLOSE)
   }
 
   _removeElement(element) {
-    $(element).removeClass(ClassName.SHOW)
+    element.classList.remove(ClassName.SHOW)
 
-    if (!$(element).hasClass(ClassName.FADE)) {
+    if (!element.classList.contains(ClassName.FADE)) {
       this._destroyElement(element)
       return
     }
 
     const transitionDuration = Util.getTransitionDurationFromElement(element)
 
-    $(element)
-      .one(Util.TRANSITION_END, (event) => this._destroyElement(element, event))
-
-    Util.emulateTransitionEnd(transitionDuration)
+    EventHandler
+      .one(element, Util.TRANSITION_END, (event) => this._destroyElement(element, event))
+    Util.emulateTransitionEnd(element, transitionDuration)
   }
 
   _destroyElement(element) {
-    $(element)
-      .detach()
-      .trigger(Event.CLOSED)
-      .remove()
+    EventHandler.trigger(element, Event.CLOSED)
+    element.parentNode.removeChild(element)
   }
 
   // Static
 
   static _jQueryInterface(config) {
     return this.each(function () {
-      const $element = $(this)
-      let data       = $element.data(DATA_KEY)
+      let data = Data.getData(this, DATA_KEY)
 
       if (!data) {
         data = new Alert(this)
-        $element.data(DATA_KEY, data)
+        Data.setData(this, DATA_KEY, data)
       }
 
       if (config === 'close') {
diff --git a/js/src/dom/data.js b/js/src/dom/data.js
new file mode 100644
index 0000000000..bbe807aac1
--- /dev/null
+++ b/js/src/dom/data.js
@@ -0,0 +1,51 @@
+/**
+ * --------------------------------------------------------------------------
+ * Bootstrap (v4.0.0-beta): dom/data.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+const mapData = (() => {
+  const storeData    = {}
+  return {
+    set(element, key, data) {
+      let id
+      if (element.key === undefined) {
+        element.key = {
+          key,
+          id
+        }
+      }
+
+      storeData[id] = data
+    },
+    get(element, key) {
+      if (element.key === undefined || element.key !== key) {
+        return null
+      }
+      const keyProperties = element.key
+      return storeData[keyProperties.id]
+    },
+    delete(element, key) {
+      if (element.key === undefined || element.key !== key) {
+        return
+      }
+      const keyProperties = element.key
+      delete storeData[keyProperties.id]
+    }
+  }
+})()
+
+const Data = {
+  setData(instance, key, data) {
+    mapData.set(instance, key, data)
+  },
+  getData(instance, key) {
+    mapData.get(instance, key)
+  },
+  removeData(instance, key) {
+    mapData.delete(instance, key)
+  }
+}
+
+export default Data
diff --git a/js/src/dom/event.js b/js/src/dom/eventHandler.js
similarity index 68%
rename from js/src/dom/event.js
rename to js/src/dom/eventHandler.js
index 5968e62e0f..0627ccd268 100644
--- a/js/src/dom/event.js
+++ b/js/src/dom/eventHandler.js
@@ -1,13 +1,13 @@
 /**
  * --------------------------------------------------------------------------
- * Bootstrap (v4.0.0-beta): dom/event.js
+ * Bootstrap (v4.0.0-beta): dom/eventHandler.js
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
  * --------------------------------------------------------------------------
  */
 
-const Event = {
+const EventHandler = {
   on(element, event, handler) {
-    if (typeof event !== 'string') {
+    if (typeof event !== 'string' || typeof element === 'undefined') {
       return
     }
     element.addEventListener(event, handler, false)
@@ -19,12 +19,12 @@ const Event = {
       handler()
       element.removeEventListener(event, complete, false)
     }
-    Event.on(element, event, complete)
+    EventHandler.on(element, event, complete)
   },
 
   trigger(element, event) {
-    if (typeof event !== 'string') {
-      return
+    if (typeof event !== 'string' || typeof element === 'undefined') {
+      return null
     }
 
     const eventToDispatch = new CustomEvent(event, {
@@ -32,7 +32,9 @@ const Event = {
       cancelable: true
     })
     element.dispatchEvent(eventToDispatch)
+
+    return eventToDispatch
   }
 }
 
-export default Event
+export default EventHandler
diff --git a/js/src/dom/selectorEngine.js b/js/src/dom/selectorEngine.js
new file mode 100644
index 0000000000..f6bcf6da26
--- /dev/null
+++ b/js/src/dom/selectorEngine.js
@@ -0,0 +1,42 @@
+/**
+ * --------------------------------------------------------------------------
+ * Bootstrap (v4.0.0-beta): dom/selectorEngine.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+const SelectorEngine = {
+  matches: Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector,
+
+  find(selector) {
+    if (typeof selector !== 'string') {
+      return null
+    }
+
+    let selectorType = 'querySelectorAll'
+    if (selector.indexOf('#') === 0) {
+      selectorType = 'getElementById'
+      selector = selector.substr(1, selector.length)
+    }
+    return document[selectorType](selector)
+  },
+
+  closest(element, selector) {
+    let ancestor = element
+    if (!document.documentElement.contains(element)) {
+      return null
+    }
+
+    do {
+      if (SelectorEngine.matches.call(ancestor, selector)) {
+        return ancestor
+      }
+
+      ancestor = ancestor.parentElement
+    } while (ancestor !== null)
+
+    return null
+  }
+}
+
+export default SelectorEngine
diff --git a/js/src/util.js b/js/src/util.js
index 2ffdec999b..b5efeca14e 100644
--- a/js/src/util.js
+++ b/js/src/util.js
@@ -5,7 +5,7 @@
  * --------------------------------------------------------------------------
  */
 
-import Event from './dom/event'
+import EventHandler from './dom/eventHandler'
 
 /**
  * ------------------------------------------------------------------------
@@ -78,7 +78,7 @@ const Util = {
   },
 
   triggerTransitionEnd(element) {
-    Event.trigger(element, Util.TRANSITION_END)
+    EventHandler.trigger(element, Util.TRANSITION_END)
   },
 
   // TODO: Remove in v5
diff --git a/js/tests/index.html b/js/tests/index.html
index a3fd937c2d..db0743f0ff 100644
--- a/js/tests/index.html
+++ b/js/tests/index.html
@@ -97,7 +97,9 @@
     </script>
 
     <!-- Transpiled Plugins -->
-    <script src="../dist/dom/event.js"></script>
+    <script src="../dist/dom/eventHandler.js"></script>
+    <script src="../dist/dom/selectorEngine.js"></script>
+    <script src="../dist/dom/data.js"></script>
     <script src="../dist/util.js"></script>
     <script src="../dist/alert.js"></script>
     <script src="../dist/button.js"></script>
diff --git a/js/tests/unit/.eslintrc.json b/js/tests/unit/.eslintrc.json
index 86d851ad06..b07efd269d 100644
--- a/js/tests/unit/.eslintrc.json
+++ b/js/tests/unit/.eslintrc.json
@@ -12,7 +12,8 @@
     "Button": false,
     "Carousel": false,
     "Simulator": false,
-    "Toast": false
+    "Toast": false,
+    "EventHandler": false
   },
   "parserOptions": {
     "ecmaVersion": 5,
diff --git a/js/tests/unit/alert.js b/js/tests/unit/alert.js
index 65a8f9e767..32fcc6ceaf 100644
--- a/js/tests/unit/alert.js
+++ b/js/tests/unit/alert.js
@@ -70,16 +70,19 @@ $(function () {
   QUnit.test('should not fire closed when close is prevented', function (assert) {
     assert.expect(1)
     var done = assert.async()
-    $('<div class="alert"/>')
-      .on('close.bs.alert', function (e) {
-        e.preventDefault()
-        assert.ok(true, 'close event fired')
-        done()
-      })
-      .on('closed.bs.alert', function () {
-        assert.ok(false, 'closed event fired')
-      })
-      .bootstrapAlert('close')
+    var $alert = $('<div class="alert"/>')
+    $alert.appendTo('#qunit-fixture')
+
+    EventHandler.on($alert[0], 'close.bs.alert', function (e) {
+      e.preventDefault()
+      assert.ok(true, 'close event fired')
+      done()
+    })
+    EventHandler.on($alert[0], 'closed.bs.alert', function () {
+      assert.ok(false, 'closed event fired')
+    })
+
+    $alert.bootstrapAlert('close')
   })
 
   QUnit.test('close should use internal _element if no element provided', function (assert) {
diff --git a/js/tests/visual/alert.html b/js/tests/visual/alert.html
index d2befb8b8a..9111e35727 100644
--- a/js/tests/visual/alert.html
+++ b/js/tests/visual/alert.html
@@ -52,7 +52,9 @@
     </div>
 
     <script src="../../../node_modules/jquery/dist/jquery.slim.min.js"></script>
-    <script src="../../dist/dom/event.js"></script>
+    <script src="../../dist/dom/eventHandler.js"></script>
+    <script src="../../dist/dom/selectorEngine.js"></script>
+    <script src="../../dist/dom/data.js"></script>
     <script src="../../dist/util.js"></script>
     <script src="../../dist/alert.js"></script>
   </body>
diff --git a/js/tests/visual/button.html b/js/tests/visual/button.html
index ce900e471e..818160da3b 100644
--- a/js/tests/visual/button.html
+++ b/js/tests/visual/button.html
@@ -45,7 +45,7 @@
     </div>
 
     <script src="../../../node_modules/jquery/dist/jquery.slim.min.js"></script>
-    <script src="../../dist/dom/event.js"></script>
+    <script src="../../dist/dom/eventHandler.js"></script>
     <script src="../../dist/util.js"></script>
     <script src="../../dist/button.js"></script>
   </body>
diff --git a/js/tests/visual/carousel.html b/js/tests/visual/carousel.html
index 895a6422c4..d1376b39b9 100644
--- a/js/tests/visual/carousel.html
+++ b/js/tests/visual/carousel.html
@@ -46,7 +46,7 @@
     </div>
 
     <script src="../../../node_modules/jquery/dist/jquery.slim.min.js"></script>
-    <script src="../../dist/dom/event.js"></script>
+    <script src="../../dist/dom/eventHandler.js"></script>
     <script src="../../dist/util.js"></script>
     <script src="../../dist/carousel.js"></script>
     <script>
diff --git a/js/tests/visual/collapse.html b/js/tests/visual/collapse.html
index 2bc3c086ee..e084bd08bc 100644
--- a/js/tests/visual/collapse.html
+++ b/js/tests/visual/collapse.html
@@ -72,7 +72,7 @@
     </div>
 
     <script src="../../../node_modules/jquery/dist/jquery.slim.min.js"></script>
-    <script src="../../dist/dom/event.js"></script>
+    <script src="../../dist/dom/eventHandler.js"></script>
     <script src="../../dist/util.js"></script>
     <script src="../../dist/collapse.js"></script>
   </body>
diff --git a/js/tests/visual/dropdown.html b/js/tests/visual/dropdown.html
index 9e4a10cfb6..d1bb0ed350 100644
--- a/js/tests/visual/dropdown.html
+++ b/js/tests/visual/dropdown.html
@@ -205,7 +205,7 @@
 
     <script src="../../../node_modules/jquery/dist/jquery.slim.min.js"></script>
     <script src="../../../node_modules/popper.js/dist/umd/popper.min.js"></script>
-    <script src="../../dist/dom/event.js"></script>
+    <script src="../../dist/dom/eventHandler.js"></script>
     <script src="../../dist/util.js"></script>
     <script src="../../dist/dropdown.js"></script>
     <script src="../../dist/collapse.js"></script>
diff --git a/js/tests/visual/modal.html b/js/tests/visual/modal.html
index 53ad81a97a..30975b0c7b 100644
--- a/js/tests/visual/modal.html
+++ b/js/tests/visual/modal.html
@@ -207,13 +207,12 @@
 
     <script src="../../../node_modules/jquery/dist/jquery.slim.min.js"></script>
     <script src="../../../node_modules/popper.js/dist/umd/popper.min.js"></script>
-    <script src="../../dist/dom/event.js"></script>
+    <script src="../../dist/dom/eventHandler.js"></script>
     <script src="../../dist/util.js"></script>
     <script src="../../dist/modal.js"></script>
     <script src="../../dist/collapse.js"></script>
     <script src="../../dist/tooltip.js"></script>
     <script src="../../dist/popover.js"></script>
-
     <script>
       var firefoxTestDone = false
       function reportFirefoxTestResult(result) {
diff --git a/js/tests/visual/popover.html b/js/tests/visual/popover.html
index 38ab65a125..e422891dad 100644
--- a/js/tests/visual/popover.html
+++ b/js/tests/visual/popover.html
@@ -33,11 +33,10 @@
 
     <script src="../../../node_modules/jquery/dist/jquery.slim.min.js"></script>
     <script src="../../../node_modules/popper.js/dist/umd/popper.min.js"></script>
-    <script src="../../dist/dom/event.js"></script>
+    <script src="../../dist/dom/eventHandler.js"></script>
     <script src="../../dist/util.js"></script>
     <script src="../../dist/tooltip.js"></script>
     <script src="../../dist/popover.js"></script>
-
     <script>
       $(function () {
         $('[data-toggle="popover"]').popover()
diff --git a/js/tests/visual/scrollspy.html b/js/tests/visual/scrollspy.html
index 2fb4c1ac2b..f0149198d7 100644
--- a/js/tests/visual/scrollspy.html
+++ b/js/tests/visual/scrollspy.html
@@ -88,7 +88,7 @@
 
     <script src="../../../node_modules/jquery/dist/jquery.slim.min.js"></script>
     <script src="../../../site/docs/4.2/assets/js/vendor/popper.min.js"></script>
-    <script src="../../dist/dom/event.js"></script>
+    <script src="../../dist/dom/eventHandler.js"></script>
     <script src="../../dist/util.js"></script>
     <script src="../../dist/scrollspy.js"></script>
     <script src="../../dist/dropdown.js"></script>
diff --git a/js/tests/visual/tab.html b/js/tests/visual/tab.html
index 737679a780..3b8ce4026f 100644
--- a/js/tests/visual/tab.html
+++ b/js/tests/visual/tab.html
@@ -227,7 +227,7 @@
 
     <script src="../../../node_modules/jquery/dist/jquery.slim.min.js"></script>
     <script src="../../../node_modules/popper.js/dist/umd/popper.min.js"></script>
-    <script src="../../dist/dom/event.js"></script>
+    <script src="../../dist/dom/eventHandler.js"></script>
     <script src="../../dist/util.js"></script>
     <script src="../../dist/tab.js"></script>
     <script src="../../dist/dropdown.js"></script>
-- 
GitLab