()
| 715 | |
| 716 | // 加载设置弹窗并绑定菜单行为。 |
| 717 | const loadMenu = function () { |
| 718 | if ($(".kmenu") !== null) { |
| 719 | return; |
| 720 | } |
| 721 | |
| 722 | const icon = GM_info.script.icon |
| 723 | ? GM_info.script.icon |
| 724 | : `${GM_info.script.namespace}raw/main/assets/logo.svg`; |
| 725 | const ndivmenu = document.createElement("div"); |
| 726 | ndivmenu.setAttribute("class", "kmenu khide"); |
| 727 | ndivmenu.setAttribute("aria-hidden", "true"); |
| 728 | ndivmenu.innerHTML = ` |
| 729 | <div class="kmenu-backdrop"></div> |
| 730 | <div class="kmenu-panel" role="dialog" aria-modal="true" aria-label="KeepChatGPT" tabindex="-1"> |
| 731 | <div class="kmenu-head"> |
| 732 | <div class="kmenu-brand"> |
| 733 | <img src="${icon}" alt="KeepChatGPT"> |
| 734 | <div class="kmenu-brand-text"> |
| 735 | <strong>KeepChatGPT</strong> |
| 736 | <span>by xcanwin</span> |
| 737 | </div> |
| 738 | </div> |
| 739 | <button type="button" class="kmenu-close" aria-label="Close">×</button> |
| 740 | </div> |
| 741 | <div class="kmenu-content"></div> |
| 742 | </div> |
| 743 | `; |
| 744 | |
| 745 | const nmenuContent = $(".kmenu-content", ndivmenu); |
| 746 | getMenuGroups().forEach((group) => { |
| 747 | const ngroup = document.createElement("section"); |
| 748 | ngroup.className = "kmenu-group"; |
| 749 | ngroup.innerHTML = `<h3 class="kmenu-group-title">${group.title}</h3>`; |
| 750 | |
| 751 | const ngroupBody = document.createElement("div"); |
| 752 | ngroupBody.className = "kmenu-group-body"; |
| 753 | group.items.forEach((item) => { |
| 754 | ngroupBody.appendChild(createMenuItem(item)); |
| 755 | }); |
| 756 | ngroup.appendChild(ngroupBody); |
| 757 | nmenuContent.appendChild(ngroup); |
| 758 | }); |
| 759 | document.body.appendChild(ndivmenu); |
| 760 | |
| 761 | // 点击遮罩或右上角关闭按钮都可以关闭设置弹窗。 |
| 762 | const closeMenu = function () { |
| 763 | toggleMenu("hide"); |
| 764 | }; |
| 765 | $(".kmenu-close", ndivmenu).onclick = closeMenu; |
| 766 | $(".kmenu-backdrop", ndivmenu).onclick = closeMenu; |
| 767 | |
| 768 | // 弹窗内使用 Tab 时保持焦点循环,避免焦点落到页面背景元素。 |
| 769 | ndivmenu.addEventListener("keydown", function (event) { |
| 770 | if (event.key !== "Tab") { |
| 771 | return; |
| 772 | } |
| 773 | const focusableSelector = `button, [href], input, textarea, [tabindex]:not([tabindex="-1"])`; |
| 774 | const focusables = Array.from( |
no test coverage detected