flyonui
Version:
The easiest, free and open-source Tailwind CSS component library with semantic classes.
191 lines (149 loc) • 5.83 kB
text/typescript
/*
* HSTogglePassword
* @version: 3.2.2
* @author: Preline Labs Ltd.
* @license: Licensed under MIT and Preline UI Fair Use License (https://preline.co/docs/license.html)
* Copyright 2024 Preline Labs Ltd.
*/
import { isFormElement, dispatch } from '../../utils'
import { ITogglePasswordOptions, ITogglePassword } from './interfaces'
import HSBasePlugin from '../base-plugin'
import { ICollectionItem } from '../../interfaces'
class HSTogglePassword extends HSBasePlugin<ITogglePasswordOptions> implements ITogglePassword {
private readonly target: string | string[] | HTMLInputElement | HTMLInputElement[] | null
private isShown: boolean
private isMultiple: boolean
private eventType: string
private onElementActionListener: () => void
constructor(el: HTMLElement, options?: ITogglePasswordOptions) {
super(el, options)
const data = el.getAttribute('data-toggle-password')
const dataOptions: ITogglePasswordOptions = data ? JSON.parse(data) : {}
const concatOptions = {
...dataOptions,
...options
}
const targets: HTMLInputElement[] = []
if (concatOptions?.target && typeof concatOptions?.target === 'string') {
const ids = concatOptions?.target.split(',')
ids.forEach(id => {
targets.push(document.querySelector(id) as HTMLInputElement)
})
} else if (concatOptions?.target && typeof concatOptions?.target === 'object') {
;(concatOptions.target as string[]).forEach(el => targets.push(document.querySelector(el)))
} else {
;(concatOptions.target as HTMLInputElement[]).forEach(el => targets.push(el))
}
this.target = targets
this.isShown = this.el.hasAttribute('type') ? (this.el as HTMLInputElement).checked : false
this.eventType = isFormElement(this.el) ? 'change' : 'click'
this.isMultiple = this.target.length > 1 && !!this.el.closest('[data-toggle-password-group]')
if (this.target) this.init()
}
private elementAction() {
if (this.isShown) {
this.hide()
} else {
this.show()
}
this.fireEvent('toggle', this.target)
dispatch('toggle.toggle-select', this.el, this.target)
}
private init() {
this.createCollection(window.$hsTogglePasswordCollection, this)
if (!this.isShown) {
this.hide()
} else {
this.show()
}
this.onElementActionListener = () => this.elementAction()
this.el.addEventListener(this.eventType, this.onElementActionListener)
}
private getMultipleToggles(): HSTogglePassword[] {
const group = this.el.closest('[data-toggle-password-group]')
const toggles = group.querySelectorAll('[data-toggle-password]')
const togglesInCollection: HSTogglePassword[] = []
toggles.forEach((el: HTMLElement) => {
togglesInCollection.push(HSTogglePassword.getInstance(el) as HSTogglePassword)
})
return togglesInCollection
}
// Public methods
public show() {
if (this.isMultiple) {
const toggles = this.getMultipleToggles()
toggles.forEach((el: HSTogglePassword) => (el ? (el.isShown = true) : false))
this.el.closest('[data-toggle-password-group]').classList.add('active')
} else {
this.isShown = true
this.el.classList.add('active')
}
;(this.target as HTMLInputElement[]).forEach(el => {
;(el as HTMLInputElement).type = 'text'
})
}
public hide() {
if (this.isMultiple) {
const toggles = this.getMultipleToggles()
toggles.forEach((el: HSTogglePassword) => (el ? (el.isShown = false) : false))
this.el.closest('[data-toggle-password-group]').classList.remove('active')
} else {
this.isShown = false
this.el.classList.remove('active')
}
;(this.target as HTMLInputElement[]).forEach(el => {
;(el as HTMLInputElement).type = 'password'
})
}
public destroy() {
// Remove classes
if (this.isMultiple) {
this.el.closest('[data-toggle-password-group]').classList.remove('active')
} else {
this.el.classList.remove('active')
}
// Remove attributes
;(this.target as HTMLInputElement[]).forEach(el => {
;(el as HTMLInputElement).type = 'password'
})
// Remove listeners
this.el.removeEventListener(this.eventType, this.onElementActionListener)
this.isShown = false
window.$hsTogglePasswordCollection = window.$hsTogglePasswordCollection.filter(
({ element }) => element.el !== this.el
)
}
// Static methods
static getInstance(target: HTMLElement | string, isInstance?: boolean) {
const elInCollection = window.$hsTogglePasswordCollection.find(
el => el.element.el === (typeof target === 'string' ? document.querySelector(target) : target)
)
return elInCollection ? (isInstance ? elInCollection : elInCollection.element) : null
}
static autoInit() {
if (!window.$hsTogglePasswordCollection) window.$hsTogglePasswordCollection = []
if (window.$hsTogglePasswordCollection)
window.$hsTogglePasswordCollection = window.$hsTogglePasswordCollection.filter(({ element }) =>
document.contains(element.el)
)
document.querySelectorAll('[data-toggle-password]:not(.--prevent-on-load-init)').forEach((el: HTMLInputElement) => {
if (!window.$hsTogglePasswordCollection.find(elC => (elC?.element?.el as HTMLElement) === el))
new HSTogglePassword(el)
})
}
}
declare global {
interface Window {
HSTogglePassword: Function
$hsTogglePasswordCollection: ICollectionItem<HSTogglePassword>[]
}
}
window.addEventListener('load', () => {
HSTogglePassword.autoInit()
// Uncomment for debug
// console.log('Toggle password collection:', window.$hsTogglePasswordCollection);
})
if (typeof window !== 'undefined') {
window.HSTogglePassword = HSTogglePassword
}
export default HSTogglePassword