]> git.ipfire.org Git - thirdparty/bootstrap.git/commitdiff
add more gs/try-web-components
authorGeoSot <geo.sotis@gmail.com>
Sat, 17 Sep 2022 15:39:50 +0000 (18:39 +0300)
committerGeoSot <geo.sotis@gmail.com>
Sat, 17 Sep 2022 15:39:50 +0000 (18:39 +0300)
js/src/base.js
js/src/toa.js

index 3e52b98f10551ecd39112491fe717c0d471edc43..e85dc9be8808a06c19f9828dbe1d330dcb6d5b3b 100644 (file)
@@ -1,3 +1,35 @@
-class Base extends HTMLElement {}
+import { executeAfterTransition } from './util/index'
+import Manipulator from './dom/manipulator'
+
+class Base extends HTMLElement {
+  constructor(config) {
+    super()
+
+    this._config = this._mergeConfigObj(config, this)
+  }
+
+  _queueCallback(callback, element, isAnimated = true) {
+    executeAfterTransition(callback, element, isAnimated)
+  }
+
+  static get DATA_KEY() {
+    return `bs.${this.NAME}`
+  }
+
+  static get EVENT_KEY() {
+    return `.${this.DATA_KEY}`
+  }
+
+  _mergeConfigObj(config, element) {
+    const jsonConfig = Manipulator.getDataAttribute(element, 'config') // try to parse
+
+    return {
+      ...this.constructor.Default,
+      ...(typeof jsonConfig === 'object' ? jsonConfig : {}),
+      ...Manipulator.getDataAttributes(element),
+      ...(typeof config === 'object' ? config : {})
+    }
+  }
+}
 
 export default Base
index 85c2b90571df8f22c3c90d8f16589d0407d5af63..19bbe23b45c09b0f4d202ceb781ccce7c7d319c7 100644 (file)
  * --------------------------------------------------------------------------
  */
 import Base from './base'
+import EventHandler from './dom/event-handler'
+
+const NAME = 'toast'
+const DATA_KEY = 'bs.toast'
+const EVENT_KEY = `.${DATA_KEY}`
+
+const EVENT_MOUSEOVER = `mouseover${EVENT_KEY}`
+const EVENT_MOUSEOUT = `mouseout${EVENT_KEY}`
+const EVENT_FOCUSIN = `focusin${EVENT_KEY}`
+const EVENT_FOCUSOUT = `focusout${EVENT_KEY}`
+const EVENT_HIDE = `hide${EVENT_KEY}`
+const EVENT_HIDDEN = `hidden${EVENT_KEY}`
+const EVENT_SHOW = `show${EVENT_KEY}`
+const EVENT_SHOWN = `shown${EVENT_KEY}`
+
+const CLASS_NAME_FADE = 'fade'
+const CLASS_NAME_HIDE = 'hide' // @deprecated - kept here only for backwards compatibility
+const CLASS_NAME_SHOW = 'show'
+const CLASS_NAME_SHOWING = 'showing'
 //
 // const TEMPLATE = '<slot></slot>'
 
+const DefaultType = {
+  animation: 'boolean',
+  autohide: 'boolean',
+  delay: 'number'
+}
+
+const Default = {
+  animation: true,
+  autohide: true,
+  delay: 5000
+}
+
 export default class Toa extends Base {
   constructor() {
     super()
-    this.autohide = this.getAttribute('autohide') !== 'false'
-    console.log(this.autohide) // eslint-disable-line no-console
-    this.classList.add('toast', 'bg-danger', 'p-2')
+    console.log(this._config) // eslint-disable-line no-console
+    this.classList.add('toast', 'p-2')
     this.setAttribute('role', 'alert')
-    this.ariaLive = 'assertlive'
-    this.ariaAtomic = 'true'
+    this.setAttribute('aria-live', 'assertlive')
+    this.setAttribute('aria-atomic', 'true')
+    this._timeout = null
+    this._hasMouseInteraction = false
+    this._hasKeyboardInteraction = false
+  }
+
+  static get Default() {
+    return Default
+  }
+
+  static get DefaultType() {
+    return DefaultType
+  }
+
+  static get NAME() {
+    return NAME
   }
 
   show() {
-    this.classList.add('show')
-    this.style.display = 'block'
-    if (this.autohide) {
-      setTimeout(() => this.hide(), this.constructor.properties.delay.value)
+    const showEvent = EventHandler.trigger(this, EVENT_SHOW)
+
+    if (showEvent.defaultPrevented) {
+      return
+    }
+
+    this._clearTimeout()
+
+    if (this._config.animation) {
+      this.classList.add(CLASS_NAME_FADE)
+    }
+
+    const complete = () => {
+      this.classList.remove(CLASS_NAME_SHOWING)
+      EventHandler.trigger(this, EVENT_SHOWN)
+
+      this._maybeScheduleHide()
     }
+
+    this.classList.remove(CLASS_NAME_HIDE) // @deprecated
+    // reflow(this)
+    this.style.display = 'block'
+    this.classList.add(CLASS_NAME_SHOW, CLASS_NAME_SHOWING)
+
+    this._queueCallback(complete, this, this._config.animation)
   }
 
   hide() {
-    if (this._hasMouseInteraction) {
-      setTimeout(() => this.hide(), this.constructor.properties.delay.value)
+    if (!this.isShown()) {
       return
     }
 
-    this.style.removeProperty('display')
-    this.classList.remove('show')
-  }
+    const hideEvent = EventHandler.trigger(this, EVENT_HIDE)
+
+    if (hideEvent.defaultPrevented) {
+      return
+    }
 
-  // Button's properties.
-  static get properties() {
-    return {
-      animation: {
-        type: Boolean,
-        value: true
-      },
-      autohide: {
-        type: Boolean,
-        value: true
-      },
-      delay: {
-        type: Number,
-        value: 3000
-      }
+    const complete = () => {
+      this.classList.add(CLASS_NAME_HIDE) // @deprecated
+      this.classList.remove(CLASS_NAME_SHOWING, CLASS_NAME_SHOW)
+      EventHandler.trigger(this, EVENT_HIDDEN)
+      this.style.removeProperty('display')
     }
+
+    this.classList.add(CLASS_NAME_SHOWING)
+    this._queueCallback(complete, this, this._config.animation)
   }
 
-  connectedCallback() {
-    this.show()
+  isShown() {
+    return this.classList.contains(CLASS_NAME_SHOW)
+  }
+
+  // Private
+
+  _maybeScheduleHide() {
+    if (!this._config.autohide) {
+      return
+    }
+
+    if (this._hasMouseInteraction || this._hasKeyboardInteraction) {
+      return
+    }
 
-    this.addEventListener('pointerenter', event => this._onInteraction(event, true))
-    this.addEventListener('pointerleave', event => this._onInteraction(event, false))
+    this._timeout = setTimeout(() => {
+      this.hide()
+    }, this._config.delay)
   }
 
   _onInteraction(event, isInteracting) {
     switch (event.type) {
-      case 'pointerenter':
-      case 'pointerleave':
+      case 'mouseover':
+      case 'mouseout':
         this._hasMouseInteraction = isInteracting
         break
+      case 'focusin':
+      case 'focusout':
+        this._hasKeyboardInteraction = isInteracting
+        break
       default:
         break
     }
+
+    if (isInteracting) {
+      this._clearTimeout()
+      return
+    }
+
+    const nextElement = event.relatedTarget
+    if (this === nextElement || this.contains(nextElement)) {
+      return
+    }
+
+    this._maybeScheduleHide()
+  }
+
+  _setListeners() {
+    EventHandler.on(this, EVENT_MOUSEOVER, event => this._onInteraction(event, true))
+    EventHandler.on(this, EVENT_MOUSEOUT, event => this._onInteraction(event, false))
+    EventHandler.on(this, EVENT_FOCUSIN, event => this._onInteraction(event, true))
+    EventHandler.on(this, EVENT_FOCUSOUT, event => this._onInteraction(event, false))
   }
+
+  _clearTimeout() {
+    clearTimeout(this._timeout)
+    this._timeout = null
+  }
+
+  connectedCallback() {
+    this._setListeners()
+    this.show()
+  }
+
+  //
+  // static get observedAttributes() {
+  //   return ['duration'];
+  // }
+  //
+  // attributeChangedCallback(name, oldValue, newValue) {
+  //   if (name === 'duration') {
+  //     this.duration = newValue;
+  //   }
+  // }
 }