@mdbootstrap/bootstrap-dark-mode
Version:
Responsive Dark Mode theme built with Bootstrap 5 with Dark Mode toggle button that switches between dark and light themes.
444 lines (383 loc) • 12.8 kB
JavaScript
import { element, getjQuery, onDOMContentLoaded } from '../mdb/util/index';
import Data from '../mdb/dom/data';
import EventHandler from '../mdb/dom/event-handler';
import Manipulator from '../mdb/dom/manipulator';
import SelectorEngine from '../mdb/dom/selector-engine';
import 'detect-autofill';
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
const NAME = 'input';
const DATA_KEY = 'mdb.input';
const CLASSNAME_WRAPPER = 'form-outline';
const CLASSNAME_ACTIVE = 'active';
const CLASSNAME_NOTCH = 'form-notch';
const CLASSNAME_NOTCH_LEADING = 'form-notch-leading';
const CLASSNAME_NOTCH_MIDDLE = 'form-notch-middle';
const CLASSNAME_NOTCH_TRAILING = 'form-notch-trailing';
const CLASSNAME_PLACEHOLDER_ACTIVE = 'placeholder-active';
const CLASSNAME_HELPER = 'form-helper';
const CLASSNAME_COUNTER = 'form-counter';
const SELECTOR_OUTLINE_INPUT = `.${CLASSNAME_WRAPPER} input`;
const SELECTOR_OUTLINE_TEXTAREA = `.${CLASSNAME_WRAPPER} textarea`;
const SELECTOR_NOTCH = `.${CLASSNAME_NOTCH}`;
const SELECTOR_NOTCH_LEADING = `.${CLASSNAME_NOTCH_LEADING}`;
const SELECTOR_NOTCH_MIDDLE = `.${CLASSNAME_NOTCH_MIDDLE}`;
const SELECTOR_HELPER = `.${CLASSNAME_HELPER}`;
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
class Input {
constructor(element) {
this._element = element;
this._label = null;
this._labelWidth = 0;
this._labelMarginLeft = 0;
this._notchLeading = null;
this._notchMiddle = null;
this._notchTrailing = null;
this._initiated = false;
this._helper = null;
this._counter = false;
this._counterElement = null;
this._maxLength = 0;
this._leadingIcon = null;
if (this._element) {
Data.setData(element, DATA_KEY, this);
this.init();
}
}
// Getters
static get NAME() {
return NAME;
}
get input() {
const inputElement =
SelectorEngine.findOne('input', this._element) ||
SelectorEngine.findOne('textarea', this._element);
return inputElement;
}
// Public
init() {
if (this._initiated) {
return;
}
this._getLabelData();
this._applyDivs();
this._applyNotch();
this._activate();
this._getHelper();
this._getCounter();
this._initiated = true;
}
update() {
this._getLabelData();
this._getNotchData();
this._applyNotch();
this._activate();
this._getHelper();
this._getCounter();
}
forceActive() {
Manipulator.addClass(this.input, CLASSNAME_ACTIVE);
}
forceInactive() {
Manipulator.removeClass(this.input, CLASSNAME_ACTIVE);
}
dispose() {
this._removeBorder();
Data.removeData(this._element, DATA_KEY);
this._element = null;
}
// Private
/*
_getIcons() {
this._leadingIcon = SelectorEngine.findOne('i.leading', this._element);
if (this._leadingIcon !== null) {
this._applyLeadingIcon();
}
}
_applyLeadingIcon() {
this._label.innerHTML = ` ${this._label.innerHTML}`;
this._label.insertBefore(this._leadingIcon, this._label.firstChild);
}
*/
_getLabelData() {
this._label = SelectorEngine.findOne('label', this._element);
if (this._label === null) {
this._showPlaceholder();
} else {
this._getLabelWidth();
this._getLabelPositionInInputGroup();
this._toggleDefaultDatePlaceholder();
}
}
_getHelper() {
this._helper = SelectorEngine.findOne(SELECTOR_HELPER, this._element);
}
_getCounter() {
this._counter = Manipulator.getDataAttribute(this.input, 'showcounter');
if (this._counter) {
this._maxLength = this.input.maxLength;
this._showCounter();
}
}
_showCounter() {
const counters = SelectorEngine.find('.form-counter', this._element);
if (counters.length > 0) {
return;
}
this._counterElement = document.createElement('div');
Manipulator.addClass(this._counterElement, CLASSNAME_COUNTER);
const actualLength = this.input.value.length;
this._counterElement.innerHTML = `${actualLength} / ${this._maxLength}`;
this._helper.appendChild(this._counterElement);
this._bindCounter();
}
_bindCounter() {
EventHandler.on(this.input, 'input', () => {
const actualLength = this.input.value.length;
this._counterElement.innerHTML = `${actualLength} / ${this._maxLength}`;
});
}
_toggleDefaultDatePlaceholder(input = this.input) {
const isTypeDate = input.getAttribute('type') === 'date';
if (!isTypeDate) {
return;
}
const isInputFocused = document.activeElement === input;
if (!isInputFocused && !input.value) {
input.style.opacity = 0;
} else {
input.style.opacity = 1;
}
}
_showPlaceholder() {
Manipulator.addClass(this.input, CLASSNAME_PLACEHOLDER_ACTIVE);
}
_getNotchData() {
this._notchMiddle = SelectorEngine.findOne(SELECTOR_NOTCH_MIDDLE, this._element);
this._notchLeading = SelectorEngine.findOne(SELECTOR_NOTCH_LEADING, this._element);
}
_getLabelWidth() {
this._labelWidth = this._label.clientWidth * 0.8 + 8;
}
_getLabelPositionInInputGroup() {
this._labelMarginLeft = 0;
if (!this._element.classList.contains('input-group')) return;
const input = this.input;
const prefix = SelectorEngine.prev(input, '.input-group-text')[0];
if (prefix === undefined) {
this._labelMarginLeft = 0;
} else {
this._labelMarginLeft = prefix.offsetWidth - 1;
}
}
_applyDivs() {
const allNotchWrappers = SelectorEngine.find(SELECTOR_NOTCH, this._element);
const notchWrapper = element('div');
Manipulator.addClass(notchWrapper, CLASSNAME_NOTCH);
this._notchLeading = element('div');
Manipulator.addClass(this._notchLeading, CLASSNAME_NOTCH_LEADING);
this._notchMiddle = element('div');
Manipulator.addClass(this._notchMiddle, CLASSNAME_NOTCH_MIDDLE);
this._notchTrailing = element('div');
Manipulator.addClass(this._notchTrailing, CLASSNAME_NOTCH_TRAILING);
if (allNotchWrappers.length >= 1) {
return;
}
notchWrapper.append(this._notchLeading);
notchWrapper.append(this._notchMiddle);
notchWrapper.append(this._notchTrailing);
this._element.append(notchWrapper);
}
_applyNotch() {
this._notchMiddle.style.width = `${this._labelWidth}px`;
this._notchLeading.style.width = `${this._labelMarginLeft + 9}px`;
if (this._label === null) return;
this._label.style.marginLeft = `${this._labelMarginLeft}px`;
}
_removeBorder() {
const border = SelectorEngine.findOne(SELECTOR_NOTCH, this._element);
if (border) border.remove();
}
_activate(event) {
onDOMContentLoaded(() => {
this._getElements(event);
const input = event ? event.target : this.input;
if (input.value !== '') {
Manipulator.addClass(input, CLASSNAME_ACTIVE);
}
this._toggleDefaultDatePlaceholder(input);
});
}
_getElements(event) {
if (event) {
this._element = event.target.parentNode;
this._label = SelectorEngine.findOne('label', this._element);
}
if (event && this._label) {
const prevLabelWidth = this._labelWidth;
this._getLabelData();
if (prevLabelWidth !== this._labelWidth) {
this._notchMiddle = SelectorEngine.findOne('.form-notch-middle', event.target.parentNode);
this._notchLeading = SelectorEngine.findOne(
SELECTOR_NOTCH_LEADING,
event.target.parentNode
);
this._applyNotch();
}
}
}
_deactivate(event) {
const input = event ? event.target : this.input;
if (input.value === '') {
input.classList.remove(CLASSNAME_ACTIVE);
}
this._toggleDefaultDatePlaceholder(input);
}
static activate(instance) {
return function (event) {
instance._activate(event);
};
}
static deactivate(instance) {
return function (event) {
instance._deactivate(event);
};
}
static jQueryInterface(config, options) {
return this.each(function () {
let data = Data.getData(this, DATA_KEY);
const _config = typeof config === 'object' && config;
if (!data && /dispose/.test(config)) {
return;
}
if (!data) {
data = new Input(this, _config);
}
if (typeof config === 'string') {
if (typeof data[config] === 'undefined') {
throw new TypeError(`No method named "${config}"`);
}
data[config](options);
}
});
}
static getInstance(element) {
return Data.getData(element, DATA_KEY);
}
static getOrCreateInstance(element, config = {}) {
return (
this.getInstance(element) || new this(element, typeof config === 'object' ? config : null)
);
}
}
EventHandler.on(document, 'focus', SELECTOR_OUTLINE_INPUT, Input.activate(new Input()));
EventHandler.on(document, 'input', SELECTOR_OUTLINE_INPUT, Input.activate(new Input()));
EventHandler.on(document, 'blur', SELECTOR_OUTLINE_INPUT, Input.deactivate(new Input()));
EventHandler.on(document, 'focus', SELECTOR_OUTLINE_TEXTAREA, Input.activate(new Input()));
EventHandler.on(document, 'input', SELECTOR_OUTLINE_TEXTAREA, Input.activate(new Input()));
EventHandler.on(document, 'blur', SELECTOR_OUTLINE_TEXTAREA, Input.deactivate(new Input()));
EventHandler.on(window, 'shown.bs.modal', (e) => {
SelectorEngine.find(SELECTOR_OUTLINE_INPUT, e.target).forEach((element) => {
const instance = Input.getInstance(element.parentNode);
if (!instance) {
return;
}
instance.update();
});
SelectorEngine.find(SELECTOR_OUTLINE_TEXTAREA, e.target).forEach((element) => {
const instance = Input.getInstance(element.parentNode);
if (!instance) {
return;
}
instance.update();
});
});
EventHandler.on(window, 'shown.bs.dropdown', (e) => {
const target = e.target.parentNode.querySelector('.dropdown-menu');
if (target) {
SelectorEngine.find(SELECTOR_OUTLINE_INPUT, target).forEach((element) => {
const instance = Input.getInstance(element.parentNode);
if (!instance) {
return;
}
instance.update();
});
SelectorEngine.find(SELECTOR_OUTLINE_TEXTAREA, target).forEach((element) => {
const instance = Input.getInstance(element.parentNode);
if (!instance) {
return;
}
instance.update();
});
}
});
EventHandler.on(window, 'shown.bs.tab', (e) => {
let targetId;
if (e.target.href) {
targetId = e.target.href.split('#')[1];
} else {
targetId = Manipulator.getDataAttribute(e.target, 'target').split('#')[1];
}
const target = SelectorEngine.findOne(`#${targetId}`);
SelectorEngine.find(SELECTOR_OUTLINE_INPUT, target).forEach((element) => {
const instance = Input.getInstance(element.parentNode);
if (!instance) {
return;
}
instance.update();
});
SelectorEngine.find(SELECTOR_OUTLINE_TEXTAREA, target).forEach((element) => {
const instance = Input.getInstance(element.parentNode);
if (!instance) {
return;
}
instance.update();
});
});
// auto-init
SelectorEngine.find(`.${CLASSNAME_WRAPPER}`).map((element) => new Input(element));
// form reset handler
EventHandler.on(window, 'reset', (e) => {
SelectorEngine.find(SELECTOR_OUTLINE_INPUT, e.target).forEach((element) => {
const instance = Input.getInstance(element.parentNode);
if (!instance) {
return;
}
instance.forceInactive();
});
SelectorEngine.find(SELECTOR_OUTLINE_TEXTAREA, e.target).forEach((element) => {
const instance = Input.getInstance(element.parentNode);
if (!instance) {
return;
}
instance.forceInactive();
});
});
// auto-fill
EventHandler.on(window, 'onautocomplete', (e) => {
const instance = Input.getInstance(e.target.parentNode);
if (!instance || !e.cancelable) {
return;
}
instance.forceActive();
});
onDOMContentLoaded(() => {
const $ = getjQuery();
if ($) {
const JQUERY_NO_CONFLICT = $.fn[NAME];
$.fn[NAME] = Input.jQueryInterface;
$.fn[NAME].Constructor = Input;
$.fn[NAME].noConflict = () => {
$.fn[NAME] = JQUERY_NO_CONFLICT;
return Input.jQueryInterface;
};
}
});
export default Input;