|
284 | 284 | return trigger.dispatchEvent(event); |
285 | 285 | }; |
286 | 286 |
|
| 287 | + const hydrateNativeMemberSurface = (surface, containerName) => { |
| 288 | + if (!(surface instanceof HTMLElement)) { |
| 289 | + return; |
| 290 | + } |
| 291 | + const safeName = String(containerName || '').trim(); |
| 292 | + if (!safeName) { |
| 293 | + return; |
| 294 | + } |
| 295 | + const trigger = getNativeMemberTrigger(safeName); |
| 296 | + if (!(trigger instanceof HTMLElement)) { |
| 297 | + surface.addEventListener('click', (event) => { |
| 298 | + event.preventDefault(); |
| 299 | + event.stopPropagation(); |
| 300 | + proxyNativeMemberTrigger(safeName, 'click'); |
| 301 | + }); |
| 302 | + surface.addEventListener('contextmenu', (event) => { |
| 303 | + event.preventDefault(); |
| 304 | + event.stopPropagation(); |
| 305 | + proxyNativeMemberTrigger(safeName, 'contextmenu'); |
| 306 | + }); |
| 307 | + return; |
| 308 | + } |
| 309 | + const inlineClick = String(trigger.getAttribute('onclick') || '').trim(); |
| 310 | + const inlineContextMenu = String(trigger.getAttribute('oncontextmenu') || '').trim(); |
| 311 | + const title = String(trigger.getAttribute('title') || '').trim(); |
| 312 | + surface.classList.add('hand'); |
| 313 | + if (inlineClick) { |
| 314 | + surface.setAttribute('onclick', inlineClick); |
| 315 | + } else { |
| 316 | + surface.addEventListener('click', (event) => { |
| 317 | + event.preventDefault(); |
| 318 | + event.stopPropagation(); |
| 319 | + proxyNativeMemberTrigger(safeName, 'click'); |
| 320 | + }); |
| 321 | + } |
| 322 | + if (inlineContextMenu) { |
| 323 | + surface.setAttribute('oncontextmenu', inlineContextMenu); |
| 324 | + } else { |
| 325 | + surface.addEventListener('contextmenu', (event) => { |
| 326 | + event.preventDefault(); |
| 327 | + event.stopPropagation(); |
| 328 | + proxyNativeMemberTrigger(safeName, 'contextmenu'); |
| 329 | + }); |
| 330 | + } |
| 331 | + if (title) { |
| 332 | + surface.setAttribute('title', title); |
| 333 | + } |
| 334 | + }; |
| 335 | + |
287 | 336 | const computeOrderedFolderIds = (folders, prefs, hostOrder, unraidOrder) => { |
288 | 337 | const folderMap = folders && typeof folders === 'object' ? folders : {}; |
289 | 338 | const baseOrder = reorderFolderSlotsInBaseOrder(unraidOrder, folderMap, prefs); |
|
492 | 541 | </div> |
493 | 542 | </div> |
494 | 543 | `; |
| 544 | + root.querySelectorAll('[data-fv-command-member-surface="true"]').forEach((surface) => { |
| 545 | + if (!(surface instanceof HTMLElement)) { |
| 546 | + return; |
| 547 | + } |
| 548 | + hydrateNativeMemberSurface(surface, String(surface.getAttribute('data-member-name') || '').trim()); |
| 549 | + }); |
495 | 550 | return true; |
496 | 551 | }; |
497 | 552 |
|
|
532 | 587 | return; |
533 | 588 | } |
534 | 589 | } |
535 | | - const memberSurface = event.target instanceof Element |
536 | | - ? event.target.closest('[data-fv-command-member-surface="true"]') |
537 | | - : null; |
538 | | - if (memberSurface instanceof HTMLElement) { |
539 | | - const memberName = String(memberSurface.getAttribute('data-member-name') || '').trim(); |
540 | | - if (memberName) { |
541 | | - event.preventDefault(); |
542 | | - event.stopPropagation(); |
543 | | - proxyNativeMemberTrigger(memberName, 'click'); |
544 | | - } |
545 | | - return; |
546 | | - } |
547 | 590 | const button = event.target instanceof Element |
548 | 591 | ? event.target.closest('[data-fv-command-action]') |
549 | 592 | : null; |
|
608 | 651 | } |
609 | 652 | }; |
610 | 653 | rootNode.addEventListener('click', clickHandler); |
611 | | - if (contextMenuHandler) { |
612 | | - rootNode.removeEventListener('contextmenu', contextMenuHandler); |
613 | | - } |
614 | | - contextMenuHandler = (event) => { |
615 | | - const memberSurface = event.target instanceof Element |
616 | | - ? event.target.closest('[data-fv-command-member-surface="true"]') |
617 | | - : null; |
618 | | - if (!(memberSurface instanceof HTMLElement)) { |
619 | | - return; |
620 | | - } |
621 | | - const memberName = String(memberSurface.getAttribute('data-member-name') || '').trim(); |
622 | | - if (!memberName) { |
623 | | - return; |
624 | | - } |
625 | | - event.preventDefault(); |
626 | | - event.stopPropagation(); |
627 | | - proxyNativeMemberTrigger(memberName, 'contextmenu'); |
628 | | - }; |
629 | | - rootNode.addEventListener('contextmenu', contextMenuHandler); |
630 | 654 | }; |
631 | 655 |
|
632 | 656 | const resolveSnapshot = async (options = {}) => { |
|
638 | 662 | const folders = parseJsonPayloadSafe(foldersPayload); |
639 | 663 | const unraidOrder = Object.values(parseJsonPayloadSafe(orderPayload)); |
640 | 664 | const runtimeState = parseJsonPayloadSafe(statePayload); |
641 | | - const runtimeInfoByName = normalizeRuntimeInfoMap(runtimeState); |
| 665 | + let runtimeInfoByName = normalizeRuntimeInfoMap(runtimeState); |
| 666 | + if (requestBundle.fullInfo) { |
| 667 | + try { |
| 668 | + const runtimeFull = parseJsonPayloadSafe(await requestBundle.fullInfo); |
| 669 | + runtimeInfoByName = normalizeRuntimeInfoMap(runtimeFull, runtimeInfoByName); |
| 670 | + } catch (_error) { |
| 671 | + // The staged full-info hydration is optional for the experimental surface. |
| 672 | + } |
| 673 | + } |
642 | 674 | const prefsResponse = parseJsonPayloadSafe(prefsPayload); |
643 | 675 | const prefs = normalizePrefs(prefsResponse?.prefs || {}); |
644 | 676 | const hierarchy = buildFolderHierarchy(folders); |
|
0 commit comments