This repository has been archived on 2024-07-21. You can view files and clone it, but cannot push or open issues or pull requests.
java_ee_project/project/web/src/js/free/dropdown.js
2023-06-04 10:07:23 +08:00

279 lines
7.2 KiB
JavaScript

import { getjQuery, typeCheckConfig, onDOMContentLoaded } from '../mdb/util/index';
import EventHandler from '../mdb/dom/event-handler';
import SelectorEngine from '../mdb/dom/selector-engine';
import Manipulator from '../mdb/dom/manipulator';
import BSDropdown from '../bootstrap/mdb-prefix/dropdown';
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
const NAME = 'dropdown';
const DATA_KEY = `mdb.${NAME}`;
const EVENT_KEY = `.${DATA_KEY}`;
const SELECTOR_EXPAND = '[data-mdb-toggle="dropdown"]';
const Default = {
offset: [0, 2],
flip: true,
boundary: 'clippingParents',
reference: 'toggle',
display: 'dynamic',
popperConfig: null,
dropdownAnimation: 'on',
};
const DefaultType = {
offset: '(array|string|function)',
flip: 'boolean',
boundary: '(string|element)',
reference: '(string|element|object)',
display: 'string',
popperConfig: '(null|object|function)',
dropdownAnimation: 'string',
};
const EVENT_HIDE = 'hide.bs.dropdown';
const EVENT_HIDDEN = 'hidden.bs.dropdown';
const EVENT_SHOW = 'show.bs.dropdown';
const EVENT_SHOWN = 'shown.bs.dropdown';
const EVENT_HIDE_MDB = `hide${EVENT_KEY}`;
const EVENT_HIDDEN_MDB = `hidden${EVENT_KEY}`;
const EVENT_SHOW_MDB = `show${EVENT_KEY}`;
const EVENT_SHOWN_MDB = `shown${EVENT_KEY}`;
const ANIMATION_CLASS = 'animation';
const ANIMATION_SHOW_CLASS = 'fade-in';
const ANIMATION_HIDE_CLASS = 'fade-out';
class Dropdown extends BSDropdown {
constructor(element, data) {
super(element, data);
this._config = this._getConfig(data);
this._menuStyle = '';
this._popperPlacement = '';
this._mdbPopperConfig = '';
//* prevents dropdown close issue when system animation is turned off
const isPrefersReducedMotionSet = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (this._config.dropdownAnimation === 'on' && !isPrefersReducedMotionSet) {
this._init();
}
}
dispose() {
EventHandler.off(this._element, EVENT_SHOW);
EventHandler.off(this._parent, EVENT_SHOWN);
EventHandler.off(this._parent, EVENT_HIDE);
EventHandler.off(this._parent, EVENT_HIDDEN);
super.dispose();
}
// Getters
static get NAME() {
return NAME;
}
// Private
_init() {
this._bindShowEvent();
this._bindShownEvent();
this._bindHideEvent();
this._bindHiddenEvent();
}
_getConfig(options) {
const config = {
...Default,
...Manipulator.getDataAttributes(this._element),
...options,
};
typeCheckConfig(NAME, config, DefaultType);
return config;
}
_getOffset() {
const { offset } = this._config;
if (typeof offset === 'string') {
return offset.split(',').map((val) => Number.parseInt(val, 10));
}
if (typeof offset === 'function') {
return (popperData) => offset(popperData, this._element);
}
return offset;
}
_getPopperConfig() {
const popperConfig = {
placement: this._getPlacement(),
modifiers: [
{
name: 'preventOverflow',
options: {
altBoundary: this._config.flip,
boundary: this._config.boundary,
},
},
{
name: 'offset',
options: {
offset: this._getOffset(),
},
},
],
};
// Disable Popper if we have a static display
if (this._config.display === 'static') {
Manipulator.setDataAttribute(this._menu, 'popper', 'static');
popperConfig.modifiers = [
{
name: 'applyStyles',
enabled: false,
},
];
}
return {
...popperConfig,
/* eslint no-extra-parens: "off" */
...(typeof this._config.popperConfig === 'function'
? this._config.popperConfig(popperConfig)
: this._config.popperConfig),
};
}
_bindShowEvent() {
EventHandler.on(this._element, EVENT_SHOW, (e) => {
const showEvent = EventHandler.trigger(this._element, EVENT_SHOW_MDB, {
relatedTarget: e.relatedTarget,
});
if (showEvent.defaultPrevented) {
e.preventDefault();
return;
}
this._dropdownAnimationStart('show');
});
}
_bindShownEvent() {
EventHandler.on(this._parent, EVENT_SHOWN, (e) => {
const shownEvent = EventHandler.trigger(this._parent, EVENT_SHOWN_MDB, {
relatedTarget: e.relatedTarget,
});
if (shownEvent.defaultPrevented) {
e.preventDefault();
return;
}
});
}
_bindHideEvent() {
EventHandler.on(this._parent, EVENT_HIDE, (e) => {
const hideEvent = EventHandler.trigger(this._parent, EVENT_HIDE_MDB, {
relatedTarget: e.relatedTarget,
});
if (hideEvent.defaultPrevented) {
e.preventDefault();
return;
}
this._menuStyle = this._menu.style.cssText;
this._popperPlacement = this._menu.getAttribute('data-popper-placement');
this._mdbPopperConfig = this._menu.getAttribute('data-mdb-popper');
});
}
_bindHiddenEvent() {
EventHandler.on(this._parent, EVENT_HIDDEN, (e) => {
const hiddenEvent = EventHandler.trigger(this._parent, EVENT_HIDDEN_MDB, {
relatedTarget: e.relatedTarget,
});
if (hiddenEvent.defaultPrevented) {
e.preventDefault();
return;
}
if (this._config.display !== 'static' && this._menuStyle !== '') {
this._menu.style.cssText = this._menuStyle;
}
this._menu.setAttribute('data-popper-placement', this._popperPlacement);
this._menu.setAttribute('data-mdb-popper', this._mdbPopperConfig);
this._dropdownAnimationStart('hide');
});
}
_dropdownAnimationStart(action) {
switch (action) {
case 'show':
this._menu.classList.add(ANIMATION_CLASS, ANIMATION_SHOW_CLASS);
this._menu.classList.remove(ANIMATION_HIDE_CLASS);
break;
default:
// hide
this._menu.classList.add(ANIMATION_CLASS, ANIMATION_HIDE_CLASS);
this._menu.classList.remove(ANIMATION_SHOW_CLASS);
break;
}
this._bindAnimationEnd();
}
_bindAnimationEnd() {
EventHandler.one(this._menu, 'animationend', () => {
this._menu.classList.remove(ANIMATION_CLASS, ANIMATION_HIDE_CLASS, ANIMATION_SHOW_CLASS);
});
}
}
/**
* ------------------------------------------------------------------------
* Data Api implementation - auto initialization
* ------------------------------------------------------------------------
*/
SelectorEngine.find(SELECTOR_EXPAND).forEach((el) => {
let instance = Dropdown.getInstance(el);
if (!instance) {
instance = new Dropdown(el);
}
});
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
* add .rating to jQuery only if jQuery is present
*/
onDOMContentLoaded(() => {
const $ = getjQuery();
if ($) {
const JQUERY_NO_CONFLICT = $.fn[NAME];
$.fn[NAME] = Dropdown.jQueryInterface;
$.fn[NAME].Constructor = Dropdown;
$.fn[NAME].noConflict = () => {
$.fn[NAME] = JQUERY_NO_CONFLICT;
return Dropdown.jQueryInterface;
};
}
});
export default Dropdown;