1/** 2 * Shared Brand Bridge dialogs (alert / confirm / prompt). 3 * Prefer these over window.alert / confirm / prompt site-wide. 4 */ 5(function (global) { 6 'use strict'; 7 8 var ROOT_ID = 'kp-bb-dialog-root'; 9 var activeReject = null; 10 11 function ensureRoot() { 12 var root = document.getElementById(ROOT_ID); 13 if (root) { 14 return root; 15 } 16 root = document.createElement('div'); 17 root.id = ROOT_ID; 18 root.className = 'kp-bb-dialog-root'; 19 root.innerHTML = 20 '<dialog class="kp-bb-dialog" data-kp-bb-dialog aria-labelledby="kp-bb-dialog-title">' + 21 '<form method="dialog" class="kp-bb-dialog__form" data-kp-bb-dialog-form>' + 22 '<h2 class="kp-bb-dialog__title" id="kp-bb-dialog-title" data-kp-bb-dialog-title></h2>' + 23 '<p class="kp-bb-dialog__message" data-kp-bb-dialog-message></p>' + 24 '<label class="kp-bb-dialog__field" data-kp-bb-dialog-field hidden>' + 25 '<span class="screen-reader-text" data-kp-bb-dialog-field-label>Input</span>' + 26 '<input type="text" class="kp-bb-dialog__input" data-kp-bb-dialog-input autocomplete="off" />' + 27 '</label>' + 28 '<div class="kp-bb-dialog__actions">' + 29 '<button type="submit" value="cancel" class="kp-bb-dialog__btn kp-bb-dialog__btn--ghost" data-kp-bb-dialog-cancel>Cancel</button>' + 30 '<button type="submit" value="ok" class="kp-bb-dialog__btn kp-bb-dialog__btn--primary" data-kp-bb-dialog-ok>OK</button>' + 31 '</div>' + 32 '</form>' + 33 '</dialog>'; 34 document.body.appendChild(root); 35 return root; 36 } 37 38 function openDialog(opts) { 39 opts = opts || {}; 40 var root = ensureRoot(); 41 var dialog = root.querySelector('[data-kp-bb-dialog]'); 42 var titleEl = root.querySelector('[data-kp-bb-dialog-title]'); 43 var msgEl = root.querySelector('[data-kp-bb-dialog-message]'); 44 var fieldEl = root.querySelector('[data-kp-bb-dialog-field]'); 45 var fieldLabel = root.querySelector('[data-kp-bb-dialog-field-label]'); 46 var inputEl = root.querySelector('[data-kp-bb-dialog-input]'); 47 var cancelBtn = root.querySelector('[data-kp-bb-dialog-cancel]'); 48 var okBtn = root.querySelector('[data-kp-bb-dialog-ok]'); 49 var mode = opts.mode || 'alert'; 50 51 if (activeReject) { 52 try { 53 activeReject(new Error('superseded')); 54 } catch (e) { 55 /* ignore */ 56 } 57 activeReject = null; 58 } 59 60 titleEl.textContent = opts.title || (mode === 'confirm' ? 'Please confirm' : mode === 'prompt' ? 'Input needed' : 'Notice'); 61 msgEl.textContent = opts.message || ''; 62 okBtn.textContent = opts.okLabel || 'OK'; 63 cancelBtn.textContent = opts.cancelLabel || 'Cancel'; 64 65 if (mode === 'alert') { 66 cancelBtn.hidden = true; 67 } else { 68 cancelBtn.hidden = false; 69 } 70 71 if (mode === 'prompt') { 72 fieldEl.hidden = false; 73 fieldLabel.textContent = opts.fieldLabel || 'Value'; 74 inputEl.value = opts.defaultValue != null ? String(opts.defaultValue) : ''; 75 inputEl.placeholder = opts.placeholder || ''; 76 } else { 77 fieldEl.hidden = true; 78 inputEl.value = ''; 79 } 80 81 return new Promise(function (resolve, reject) { 82 activeReject = reject; 83 84 function cleanup() { 85 dialog.removeEventListener('close', onClose); 86 dialog.removeEventListener('cancel', onCancel); 87 activeReject = null; 88 } 89 90 function onClose() { 91 cleanup(); 92 var val = dialog.returnValue; 93 if (mode === 'alert') { 94 resolve(true); 95 return; 96 } 97 if (mode === 'confirm') { 98 resolve(val === 'ok'); 99 return; 100 } 101 if (val === 'ok') { 102 resolve(inputEl.value); 103 } else { 104 resolve(null); 105 } 106 } 107 108 function onCancel(e) { 109 e.preventDefault(); 110 dialog.close('cancel'); 111 } 112 113 dialog.addEventListener('close', onClose); 114 dialog.addEventListener('cancel', onCancel); 115 116 if (typeof dialog.showModal === 'function') { 117 dialog.showModal(); 118 } else { 119 dialog.setAttribute('open', ''); 120 } 121 122 window.setTimeout(function () { 123 if (mode === 'prompt') { 124 inputEl.focus(); 125 inputEl.select(); 126 } else { 127 okBtn.focus(); 128 } 129 }, 30); 130 }); 131 } 132 133 var api = { 134 alert: function (message, opts) { 135 opts = opts || {}; 136 return openDialog({ 137 mode: 'alert', 138 title: opts.title || 'Notice', 139 message: message, 140 okLabel: opts.okLabel || 'OK', 141 }); 142 }, 143 confirm: function (message, opts) { 144 opts = opts || {}; 145 return openDialog({ 146 mode: 'confirm', 147 title: opts.title || 'Please confirm', 148 message: message, 149 okLabel: opts.okLabel || 'Confirm', 150 cancelLabel: opts.cancelLabel || 'Cancel', 151 }); 152 }, 153 prompt: function (message, opts) { 154 opts = opts || {}; 155 return openDialog({ 156 mode: 'prompt', 157 title: opts.title || 'Input needed', 158 message: message, 159 okLabel: opts.okLabel || 'Continue', 160 cancelLabel: opts.cancelLabel || 'Cancel', 161 defaultValue: opts.defaultValue, 162 placeholder: opts.placeholder, 163 fieldLabel: opts.fieldLabel, 164 }); 165 }, 166 }; 167 168 global.kpBbDialog = api; 169 170 /** Convenience wrappers used across Brand Bridge features. */ 171 global.kpBbAlert = function (message, title) { 172 return api.alert(message, { title: title || 'Notice' }); 173 }; 174 global.kpBbConfirm = function (message, title) { 175 return api.confirm(message, { title: title || 'Please confirm' }); 176 }; 177 global.kpBbPrompt = function (message, title, defaultValue) { 178 return api.prompt(message, { 179 title: title || 'Input needed', 180 defaultValue: defaultValue, 181 }); 182 }; 183})(window);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.