1(function (window, document) { 2 var namespace = window.EditorumUi = window.EditorumUi || {}; 3 var internals = namespace.__internals = namespace.__internals || {}; 4 var flashStylesInjected = false; 5 6 function injectFlashStyles() { 7 var style; 8 9 if (flashStylesInjected) { 10 return; 11 } 12 13 style = document.createElement('style'); 14 style.textContent = '' 15 // Toast stack: top-right, narrow column, stacked vertically. 16 + '.editorum-flashes{position:fixed;top:16px;right:16px;left:auto;transform:none;display:flex;flex-direction:column;gap:10px;width:min(380px,calc(100% - 32px));z-index:10000;pointer-events:none;}' 17 // Individual toast: compact card with colored left accent and an icon. 18 + '.editorum-flash{align-items:flex-start;background:#fff;border:1px solid #e5e7eb;border-left:4px solid #6b7280;border-radius:8px;box-shadow:0 10px 25px -5px rgba(15,23,42,0.15),0 4px 6px -2px rgba(15,23,42,0.05);display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:10px;padding:10px 12px;pointer-events:auto;animation:editorum-flash-in 0.25s cubic-bezier(0.16,1,0.3,1);}' 19 + '@keyframes editorum-flash-in{from{opacity:0;transform:translateX(24px);}to{opacity:1;transform:translateX(0);}}' 20 + '.editorum-flash__icon{align-items:center;color:#6b7280;display:inline-flex;flex:0 0 auto;height:20px;justify-content:center;margin-top:1px;width:20px;}' 21 + '.editorum-flash__icon svg{height:20px;width:20px;}' 22 + '.editorum-flash__body{display:flex;flex-direction:column;gap:2px;min-width:0;}' 23 // Title: sentence-case, subtle weight â no more SHOUTY UPPERCASE banner. 24 + '.editorum-flash__title{color:#111827;display:block;font-size:13px;font-weight:600;letter-spacing:0;line-height:1.35;margin:0;text-transform:none;}' 25 + '.editorum-flash__title:empty{display:none;}' 26 + '.editorum-flash__message{color:#4b5563;font-size:13px;line-height:1.5;min-width:0;word-wrap:break-word;}' 27 + '.editorum-flash__close{align-items:center;background:transparent;border:0;border-radius:4px;color:#9ca3af;cursor:pointer;display:inline-flex;flex:0 0 auto;font-size:18px;font-weight:400;height:20px;justify-content:center;line-height:1;margin:0;padding:0;transition:background-color 0.15s,color 0.15s;width:20px;}' 28 + '.editorum-flash__close:hover,.editorum-flash__close:focus{background:#f3f4f6;color:#111827;outline:none;}' 29 // Type variants: accent-color left border + icon color only. 30 + '.editorum-flash--success{border-left-color:#16a34a;}' 31 + '.editorum-flash--success .editorum-flash__icon{color:#16a34a;}' 32 + '.editorum-flash--info{border-left-color:#2563eb;}' 33 + '.editorum-flash--info .editorum-flash__icon{color:#2563eb;}' 34 + '.editorum-flash--warning{border-left-color:#d97706;}' 35 + '.editorum-flash--warning .editorum-flash__icon{color:#d97706;}' 36 + '.editorum-flash--danger{border-left-color:#dc2626;}' 37 + '.editorum-flash--danger .editorum-flash__icon{color:#dc2626;}'; 38 document.head.appendChild(style); 39 flashStylesInjected = true; 40 } 41 42 function getFlashIconSvg(type) { 43 var icons = { 44 success: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>', 45 info: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>', 46 warning: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/>
46<line x1="12" y1="17" x2="12.01" y2="17"/></svg>', 47 danger: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>' 48 }; 49 return icons[type] || icons.info; 50 } 51 52 function normalizeFlashType(type) { 53 if (type === 'error') { 54 return 'danger'; 55 } 56 57 if (type === 'notice') { 58 return 'info'; 59 } 60 61 return type || 'info'; 62 } 63 64 // Titles like "ÐÐФÐÐ ÐÐЦÐЯ!", "ÐнÑоÑмаÑиÑ", "Success", "Error" are redundant 65 // when we already have a typed icon and colored accent bar â drop them so 66 // the toast shows just the useful message text. 67 function isGenericTitle(title, type) { 68 if (!title) return true; 69 var normalized = String(title).replace(/[!:\s]+/g, '').toLowerCase(); 70 var generic = ['info', 'information', 'инÑоÑмаÑиÑ', 'success', 'ÑÑÐ¿ÐµÑ ', 71 'warning', 'внимание', 'error', 'оÑибка', 'danger']; 72 for (var i = 0; i < generic.length; i++) { 73 if (normalized === generic[i]) return true; 74 } 75 return false; 76 } 77 78 function createFlashMessage(group) { 79 var alert = document.createElement('div'); 80 var iconEl = document.createElement('span'); 81 var body = document.createElement('div'); 82 var title = document.createElement('strong'); 83 var messageContainer = document.createElement('div'); 84 var button = document.createElement('button'); 85 var type = normalizeFlashType(group.type); 86 87 alert.className = 'editorum-flash editorum-flash--' + type; 88 alert.setAttribute('role', 'alert'); 89 alert.setAttribute('data-flash-timer', typeof group.timer === 'number' ? group.timer : 4000); 90 91 iconEl.className = 'editorum-flash__icon'; 92 iconEl.setAttribute('aria-hidden', 'true'); 93 iconEl.innerHTML = getFlashIconSvg(type); 94 95 body.className = 'editorum-flash__body'; 96 title.className = 'editorum-flash__title'; 97 messageContainer.className = 'editorum-flash__message'; 98 99 if (!isGenericTitle(group.title, type)) { 100 title.textContent = group.title; 101 body.appendChild(title); 102 } 103 104 internals.each(group.messages || [], function (message, index) { 105 if (index > 0) { 106 messageContainer.appendChild(document.createElement('br')); 107 } 108 109 messageContainer.appendChild(document.createTextNode(message)); 110 }); 111 112 body.appendChild(messageContainer); 113 114 button.type = 'button'; 115 button.className = 'editorum-flash__close'; 116 button.setAttribute('aria-label', 'Close'); 117 button.innerHTML = '×'; 118 button.addEventListener('click', function () { 119 if (alert.parentNode) { 120 alert.parentNode.removeChild(alert); 121 } 122 }); 123 124 alert.appendChild(iconEl); 125 alert.appendChild(body); 126 alert.appendChild(button); 127 128 window.setTimeout(function () { 129 if (alert.parentNode) { 130 alert.parentNode.removeChild(alert); 131 } 132 }, typeof group.timer === 'number' ? group.timer : 4000); 133 134 return alert; 135 } 136 137 function showFlashMessages(groups) { 138 var container; 139 140 if (!groups || !groups.length) { 141 return false; 142 } 143 144 injectFlashStyles(); 145 container = internals.query('.editorum-flashes'); 146 147 if (!container) { 148 container = document.createElement('div'); 149 container.className = 'editorum-flashes'; 150 document.body.appendChild(container); 151 } 152 153 internals.each(groups, function (group) { 154 container.appendChild(createFlashMessage(group)); 155 }); 156 157 return true; 158 } 159 160 function resolveWithin(root, selector) { 161 if (!selector) { 162 return null; 163 } 164 165 if (selector.charAt(0) === '#') { 166 return internals.query(selector); 167 } 168 169 return internals.query(selector, root) || internals.query(selector); 170 } 171 172 function resolveListItems(settings) { 173 var root = settings.root || document; 174 var itemRootSelector = settings.itemRootSelector || settings.itemsRoot; 175 var itemRoot = itemRootSelector ? resolveWithin(root, itemRootSelector) : document; 176 177 return internals.queryAll(settings.itemSelector || '.author-list-item', itemRoot || document); 178 } 179 180 function initListFilter(options) { 181 var settings = options || {}; 182 var root = settings.searchSelector ? internals.query(settings.searchSelector) : settings.root || null; 183 var input = resolveWithin(root || document, settings.inputSelector || 'input[type="search"], input[type="text"]'); 184 var reset = resolveWithin(root || document, settings.resetSelector || ''); 185 var counter = resolveWithin(root || document, settings.counterSelector || ''); 186 var noResults = resolveWithin(root || document, settings.noResultsSelector || ''); 187 var textCache = []; 188 var debounceTimer = null; 189 var debounceMs = 200; 190 191 function buildCache() { 192 var items = resolveListItems(settings); 193 var i; 194 195 textCache = []; 196 for (i = 0; i < items.length; i++) { 197 textCache.push({ 198 el: items[i], 199 text: (items[i].textContent || items[i].innerText || '').toLowerCase() 200 }); 201 } 202 } 203 204 function updateCounter(visibleCount, totalCount) { 205 var strong; 206 var shouldHideCounter = visibleCount <= 0 || visibleCount === totalCount || visibleCount === totalCount - 1; 207 208 if (!counter) { 209 return; 210 } 211 212 if (shouldHideCounter) { 213 internals.hide(counter); 214 return; 215 } 216 217 internals.show(counter); 218 strong = internals.query('strong', counter); 219 if (strong) { 220 strong.textContent = visibleCount; 221 } else { 222 counter.textContent = visibleCount; 223 } 224 } 225 226 function filter() { 227 var value; 228 var visibleCount = 0; 229 var isEmpty; 230 var i, entry; 231 232 if (!input) { 233 return; 234 } 235 236 value = (input.value || '').toLowerCase(); 237 isEmpty = value === ''; 238 239 for (i = 0; i < textCache.length; i++) { 240 entry = textCache[i]; 241 242 if (isEmpty || entry.text.indexOf(value) !== -1) { 243 entry.el.style.display = ''; 244 visibleCount += 1; 245 } else { 246 entry.el.style.display = 'none'; 247 } 248 } 249 250 updateCounter(visibleCount, textCache.length); 251 252 if (noResults) { 253 internals.toggle(noResults, !isEmpty && visibleCount === 0); 254 } 255 256 if (reset) { 257 internals.toggle(reset, !isEmpty); 258 } 259 260 if (typeof settings.onAfter === 'function') { 261 settings.onAfter({ 262 total: textCache.length, 263 visible: visibleCount, 264 root: root, 265 input: input 266 }); 267 } 268 } 269 270 function debouncedFilter() { 271 if (debounceTimer) { 272 clearTimeout(debounceTimer); 273 } 274 275 debounceTimer = setTimeout(function () { 276 debounceTimer = null; 277 filter(); 278 }, debounceMs); 279 } 280 281 if (!root || !input) { 282 return false;
283 } 284 285 buildCache(); 286 input.value = ''; 287 input.addEventListener('input', debouncedFilter); 288 input.addEventListener('keyup', debouncedFilter); 289 290 if (reset) { 291 reset.addEventListener('click', function (event) { 292 event.preventDefault(); 293 input.value = ''; 294 295 if (typeof settings.onReset === 'function') { 296 settings.onReset(root, input, reset); 297 } 298 299 filter(); 300 }); 301 } 302 303 filter(); 304 305 return { 306 refresh: function () { 307 buildCache(); 308 filter(); 309 }, 310 reset: function () { 311 input.value = ''; 312 filter(); 313 } 314 }; 315 } 316 317 function getJson(url, onSuccess, onError) { 318 var request = new window.XMLHttpRequest(); 319 320 request.open('GET', url, true); 321 request.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); 322 request.onreadystatechange = function () { 323 var response; 324 325 if (request.readyState !== 4) { 326 return; 327 } 328 329 if (request.status >= 200 && request.status < 300) { 330 try { 331 response = JSON.parse(request.responseText); 332 } catch (error) { 333 if (typeof onError === 'function') { 334 onError(error, request); 335 } 336 return; 337 } 338 339 if (typeof onSuccess === 'function') { 340 onSuccess(response, request); 341 } 342 343 return; 344 } 345 346 if (typeof onError === 'function') { 347 onError(request); 348 } 349 }; 350 request.send(); 351 352 return request; 353 } 354 355 internals.showFlashMessages = showFlashMessages; 356 internals.resolveWithin = resolveWithin; 357 internals.initListFilter = initListFilter; 358 internals.getJson = getJson; 359})(window, document);
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.