Javascript Custom Dialog

Javascript Custom Dialog
Time4VPS - VPS hosting in Europe

Javascript ile hazırlanmış custom dialog kütüphanesi

alert, confirm ve prompt metotları ile görsel olarak sade ve güzel bir kütüphanedir.

Kod ve örnek kullanım;

 class Dialog {
    constructor(settings = {}) {
        this.settings = Object.assign(
            {
                accept: 'OK',
                bodyClass: 'dialog-open',
                cancel: 'Cancel',
                dialogClass: '',
                message: '',
                template: ''
            },
            settings
        )
        this.init()
    }

    collectFormData(formData) {
        const object = {};
        formData.forEach((value, key) => {
            if (!Reflect.has(object, key)) {
                object[key] = value
                return
            }
            if (!Array.isArray(object[key])) {
                object[key] = [object[key]]
            }
            object[key].push(value)
        })
        return object
    }

    getFocusable() {
        return [...this.dialog.querySelectorAll('button,[href],select,textarea,input:not([type="hidden"]),[tabindex]:not([tabindex="-1"])')]
    }

    init() {
        if (!document.getElementById("dialog-style")) {
            this.style = document.createElement("style");
            this.style.id = 'dialog-style';
            this.style.innerHTML = `[data-component*="dialog"] * {box-sizing: border-box;outline-color: #3e83e4 }:where([data-component*="dialog"]) {--dlg-gap: 1em;background: var(--dlg-bg, #fff);border: var(--dlg-b, 0);border-radius: var(--dlg-bdrs, 0.25em);box-shadow: var(--dlg-bxsh, 0px 25px 50px -12px rgba(0, 0, 0, 0.25));font-family: var(--dlg-ff, ui-sansserif, system-ui, sans-serif);min-inline-size: var(--dlg-mis, auto);padding: var(--dlg-p, var(--dlg-gap));width: var(--dlg-w, fit-content);}:where([data-component="no-dialog"]:not([hidden])) {display: block;inset-block-start: var(--dlg-gap);inset-inline-start: 50%;position: fixed;transform: translateX(-50%);}:where([data-component*="dialog"] menu) {display: flex;gap: calc(var(--dlg-gap) / 2);justify-content: var(--dlg-menu-jc, flex-end);margin: 0;padding: 0;}:where([data-component*="dialog"] menu button) {background-color: var(--dlg-button-bgc);border: 0;border-radius: var(--dlg-bdrs, 0.25em);color: var(--dlg-button-c);font-size: var(--dlg-button-fz, 0.8em);padding: var(--dlg-button-p, 0.65em 1.5em);}:where([data-component*="dialog"] [data-ref="accept"]) {--dlg-button-bgc: var(--dlg-accept-bgc, hsl(218, 79.19%, 46.08%));--dlg-button-c: var(--dlg-accept-c, #fff);}:where([data-component*="dialog"] [data-ref="cancel"]) {--dlg-button-bgc: var(--dlg-cancel-bgc, transparent);--dlg-button-c: var(--dlg-cancel-c, inherit);}:where([data-component*="dialog"] [data-ref="fieldset"]) {border: 0;margin: unset;padding: unset;}:where([data-component*="dialog"] [data-ref="message"]) {font-size: var(--dlg-message-fz, 1.25em);margin-block-end: var(--dlg-gap);}:where([data-component*="dialog"] [data-ref="template"]:not(:empty)) {margin-block-end: var(--dlg-gap);width: 100%;}@-moz-document url-prefix() {[data-component="no-dialog"]:not([hidden]) {inset-inline-start: 0;transform: none;}}.dialog-open {background-color: rgba(0, 0, 0, .1);overflow: hidden;}[name="prompt"] {border: 1px solid silver;padding: .6em 1em;width: 100%;}.custom {--dlg-accept-bgc: hsl(215deg 75% 57%);--dlg-accept-c: #fff;--dlg-bg: #fff;--dlg-button-p: 0.75em 2em;--dlg-outline-c: #00D9F5;}.custom input {background-color: rgb(255 255 255);border-radius: 0.25em;border: 0;display: block;margin-block: 0.5em 1em;padding: 0.75em 1em;width: 100%;box-shadow: 0px 0px 0px 2px #4081e3;}.custom label {display: block;font-size: small;}dialog::backdrop {background: rgb(0 0 0 / 58%);}input[type="checkbox"] {width: auto !important;display: inline-block !important;vertical-align: sub;box-shadow: none !important;}`;
            document.head.append(this.style);
        }
        this.dialogSupported = typeof HTMLDialogElement === 'function'
        this.dialog = document.createElement('dialog')
        this.dialog.role = 'dialog'
        this.dialog.dataset.component = this.dialogSupported ? 'dialog' : 'no-dialog';
        this.dialog.innerHTML = `
      <form method="dialog" data-ref="form">
        <fieldset data-ref="fieldset" role="document">
          <legend data-ref="message" id="${(Math.round(Date.now())).toString(36)}"></legend>
          <div data-ref="template"></div>
        </fieldset>
        <menu>
          <button${this.dialogSupported ? '' : ` type="button"`} data-ref="cancel" value="cancel"></button>
          <button${this.dialogSupported ? '' : ` type="button"`} data-ref="accept" value="default"></button>
        </menu>
      </form>`
        document.body.appendChild(this.dialog)

        this.elements = {}
        this.focusable = []
        this.dialog.querySelectorAll('[data-ref]').forEach(el => this.elements[el.dataset.ref] = el)
        this.dialog.setAttribute('aria-labelledby', this.elements.message.id)
        this.elements.cancel.addEventListener('click', () => { this.dialog.dispatchEvent(new Event('cancel')) })
        this.dialog.addEventListener('keydown', e => {
            if (e.key === 'Enter') {
                if (!this.dialogSupported) e.preventDefault()
                this.elements.accept.dispatchEvent(new Event('click'))
            }
            if (e.key === 'Escape') this.dialog.dispatchEvent(new Event('cancel'))
            if (e.key === 'Tab') {
                e.preventDefault()
                const len = this.focusable.length - 1;
                let index = this.focusable.indexOf(e.target);
                index = e.shiftKey ? index - 1 : index + 1;
                if (index < 0) index = len;
                if (index > len) index = 0;
                this.focusable[index].focus();
            }
        })
        this.toggle()
    }

    open(settings = {}) {

        const dialog = Object.assign({}, this.settings, settings)
        this.dialog.className = dialog.dialogClass || ''
        this.elements.accept.innerText = dialog.accept
        this.elements.cancel.innerText = dialog.cancel
        this.elements.cancel.hidden = dialog.cancel === ''
        this.elements.message.innerText = dialog.message
        this.elements.target = dialog.target || ''
        this.elements.template.innerHTML = dialog.template || ''

        this.focusable = this.getFocusable()
        this.hasFormData = this.elements.fieldset.elements.length > 0


        this.toggle(true)

        if (this.hasFormData) {
            this.focusable[0].focus()
            this.focusable[0].select()
        }
        else {
            this.elements.accept.focus()
        }
    }

    toggle(open = false) {
        if (this.dialogSupported && open) this.dialog.showModal()
        if (!this.dialogSupported) {
            document.body.classList.toggle(this.settings.bodyClass, open)
            this.dialog.hidden = !open
            if (this.elements.target && !open) {
                this.elements.target.focus()
            }
        }
    }

    waitForUser() {
        return new Promise(resolve => {
            this.dialog.addEventListener('cancel', () => {
                this.toggle()
                resolve(false)
            }, { once: true })
            this.elements.accept.addEventListener('click', () => {
                let value = this.hasFormData ? this.collectFormData(new FormData(this.elements.form)) : true;
                this.toggle()
                resolve(value)
            }, { once: true })
        })
    }

    alert(message, config = { }) {
        const settings = Object.assign({}, config, { cancel: '', message, template: '' })
        this.open(settings)
        return this.waitForUser()
    }

    confirm(message, config = {  }) {
        const settings = Object.assign({}, config, { message, template: '' })
        this.open(settings)
        return this.waitForUser()
    }

    prompt(message, value, config = {  }) {
        const template = `<label aria-label="${message}"><input type="text" name="prompt" value="${value}"></label>`
        const settings = Object.assign({}, config, { message, template })
        this.open(settings)
        return this.waitForUser()
    }
}

Örnek Kullanım

var dialog = new Dialog();

//Dialog örneği
dialog.alert("İşlem başarıyla tamamlanmıştır");

//Confirm Örneği
var confirm = dialog.confirm("Silmek istediğinize emin misiniz");
confirm.then(a => {
    if (a === true) {
        console.log("Onaylandı")
    } else {
        console.log("Onaylanmadı")
    }
})

//Prompt Örneği
var confirm = dialog.prompt("Adınız", "name");
confirm.then(a => {
    console.log(a.prompt)
})
Tarih: