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)
})