ChatGPT-input-helper

Help organize commonly used spells quickly

  1. // ==UserScript==
  2. // @name ChatGPT-input-helper
  3. // @name:zh-TW ChatGPT-input-helper 快速輸入常用咒文
  4. // @namespace https://github.com/we684123/ChatGPT-input-helper
  5. // @version 0.0.13
  6. // @author we684123
  7. // @description Help organize commonly used spells quickly
  8. // @description:zh-TW 幫助快速組織常用咒文
  9. // @license MIT
  10. // @icon https://chat.openai.com/favicon.ico
  11. // @match https://chat.openai.com/chat
  12. // @match https://chat.openai.com/chat/*
  13. // @match https://chat.openai.com/chat?*
  14. // @match https://chat.openai.com/?model=*
  15. // @match https://chat.openai.com/c/*
  16. // @match https://chat.openai.com/
  17. // @match https://chatgpt.com/c/*
  18. // @match https://chatgpt.com/
  19. // @grant GM_getValue
  20. // @grant GM_setValue
  21. // @grant GM_deleteValue
  22. // @run-at document-end
  23. // ==/UserScript==
  24.  
  25. (function (factory) {
  26. typeof define === 'function' && define.amd ? define(factory) :
  27. factory();
  28. })((function () { 'use strict';
  29.  
  30. const sentinel = (() => {
  31. const isArray = Array.isArray;
  32. let selectorToAnimationMap = {};
  33. let animationCallbacks = {};
  34. let styleEl;
  35. let styleSheet;
  36. let cssRules;
  37. return {
  38. // `on` 方法用於添加 CSS 選擇器的監聽器。
  39. // cssSelectors: 一個字符串或字符串數組,包含要監聽的 CSS 選擇器。
  40. // callback: 用於處理觸發的事件的回調函數。
  41. on: function (cssSelectors, callback) {
  42. // 如果沒有提供回調函數,則直接返回。
  43. if (!callback)
  44. return;
  45. // 如果 `styleEl` 未定義,創建一個新的 `style` 標籤並將其添加到文檔的 `head` 中。
  46. // 還會為 `animationstart` 事件添加事件監聽器。
  47. if (!styleEl) {
  48. const doc = document;
  49. const head = doc.head;
  50. doc.addEventListener("animationstart", function (ev) {
  51. const callbacks = animationCallbacks[ev.animationName];
  52. if (!callbacks)
  53. return;
  54. ev.stopImmediatePropagation();
  55. for (const cb of callbacks) {
  56. cb(ev.target);
  57. }
  58. }, true);
  59. styleEl = doc.createElement("style");
  60. // head.insertBefore(styleEl, head.firstChild); // 這個是原版的,改用下面的
  61. head.append(styleEl); // 感謝 chatgpt-exporter 搞好久 (┬┬﹏┬┬)
  62. styleSheet = styleEl.sheet;
  63. cssRules = styleSheet.cssRules;
  64. }
  65. // 根據提供的選擇器創建一個新的動畫。
  66. const selectors = isArray(cssSelectors) ? cssSelectors : [cssSelectors];
  67. selectors.forEach((selector) => {
  68. // 獲取或創建動畫 ID。
  69. let animIds = selectorToAnimationMap[selector];
  70. if (!animIds) {
  71. const isCustomName = selector[0] == "!";
  72. const animId = isCustomName
  73. ? selector.slice(1)
  74. : "sentinel-" + Math.random().toString(16).slice(2);
  75. // 創建新的 keyframes 規則。
  76. const keyframeRule = cssRules[styleSheet.insertRule("@keyframes " +
  77. animId +
  78. "{from{transform:none;}to{transform:none;}}", cssRules.length)];
  79. keyframeRule._id = selector;
  80. // 如果選擇器不是自定義名稱,則為其創建對應的CSS 規則。
  81. if (!isCustomName) {
  82. const selectorRule = cssRules[styleSheet.insertRule(selector + "{animation-duration:0.0001s;animation-name:" + animId + ";}", cssRules.length)];
  83. selectorRule._id = selector;
  84. }
  85. animIds = [animId];
  86. selectorToAnimationMap[selector] = animIds;
  87. }
  88. // 遍歷動畫 ID,將回調函數添加到動畫回調列表中。
  89. animIds.forEach((animId) => {
  90. animationCallbacks[animId] = animationCallbacks[animId] || [];
  91. animationCallbacks[animId].push(callback);
  92. });
  93. });
  94. },
  95. // `off` 方法用於移除 CSS 選擇器的監聽器。
  96. // cssSelectors: 一個字符串或字符串數組,包含要停止監聽的 CSS 選擇器。
  97. // callback: 可選的回調函數。如果提供,則僅移除與之匹配的監聽器。
  98. off: function (cssSelectors, callback) {
  99. // 將提供的選擇器轉換為數組形式。
  100. const selectors = isArray(cssSelectors) ? cssSelectors : [cssSelectors];
  101. // 遍歷選擇器,移除對應的監聽器。
  102. selectors.forEach((selector) => {
  103. const animIds = selectorToAnimationMap[selector];
  104. if (!animIds)
  105. return;
  106. animIds.forEach((animId) => {
  107. const callbacks = animationCallbacks[animId];
  108. if (!callbacks)
  109. return;
  110. // 如果提供了回調函數,則僅移除與之匹配的監聽器。
  111. if (callback) {
  112. const index = callbacks.indexOf(callback);
  113. if (index !== -1) {
  114. callbacks.splice(index, 1);
  115. }
  116. }
  117. else {
  118. delete animationCallbacks[animId];
  119. }
  120. // 如果該選擇器沒有任何回調函數,則從選擇器映射和 CSS 規則中移除它。
  121. if (callbacks.length === 0) {
  122. delete selectorToAnimationMap[selector];
  123. const rulesToDelete = [];
  124. for (let i = 0, len = cssRules.length; i < len; i++) {
  125. const rule = cssRules[i];
  126. if (rule._id === selector) {
  127. rulesToDelete.push(rule);
  128. }
  129. }
  130. rulesToDelete.forEach((rule) => {
  131. const index = Array.prototype.indexOf.call(cssRules, rule);
  132. if (index !== -1) {
  133. styleSheet.deleteRule(index);
  134. }
  135. });
  136. }
  137. });
  138. });
  139. }
  140. };
  141. })();
  142.  
  143. function onloadSafe(fn) {
  144. if (document.readyState === "complete") {
  145. fn();
  146. }
  147. else {
  148. window.addEventListener("load", fn);
  149. }
  150. }
  151.  
  152. function styleInject(css, ref) {
  153. if ( ref === void 0 ) ref = {};
  154. var insertAt = ref.insertAt;
  155.  
  156. if (!css || typeof document === 'undefined') { return; }
  157.  
  158. var head = document.head || document.getElementsByTagName('head')[0];
  159. var style = document.createElement('style');
  160. style.type = 'text/css';
  161.  
  162. if (insertAt === 'top') {
  163. if (head.firstChild) {
  164. head.insertBefore(style, head.firstChild);
  165. } else {
  166. head.appendChild(style);
  167. }
  168. } else {
  169. head.appendChild(style);
  170. }
  171.  
  172. if (style.styleSheet) {
  173. style.styleSheet.cssText = css;
  174. } else {
  175. style.appendChild(document.createTextNode(css));
  176. }
  177. }
  178.  
  179. var css_248z$2 = ".buttonStyles-module_container__l-r9Y{align-items:center;border:1px solid #fff;border-radius:5px;box-sizing:border-box;display:flex;justify-content:center;position:relative;width:100%}.buttonStyles-module_mainButton__b08pW{border:1px solid #fff;border-radius:5px;margin:0 auto;padding:8px 12px;width:85%}.buttonStyles-module_mainButton__b08pW,.buttonStyles-module_settingButton__-opQi{background-color:#202123;box-sizing:border-box;color:#fff;cursor:pointer;font-size:14px}.buttonStyles-module_settingButton__-opQi{border:none;border-radius:5px;padding:8px 14px;width:15%}.buttonStyles-module_menu__aeYDY{background-color:#202123;border:1px solid #fff;border-radius:15px;display:none;left:14%;max-height:240px;overflow-y:auto;position:absolute;top:0;width:100%;z-index:9999}.buttonStyles-module_menuButton__eg9D8{background-color:#202123;border:1px solid #fff;border-radius:5px;color:#fff;cursor:pointer;display:block;font-size:14px;height:100%;padding:8px 12px;width:100%}.buttonStyles-module_containerNode_class__1rDgQ{position:relative}";
  180. var styles$2 = {"container":"buttonStyles-module_container__l-r9Y","mainButton":"buttonStyles-module_mainButton__b08pW","settingButton":"buttonStyles-module_settingButton__-opQi","menu":"buttonStyles-module_menu__aeYDY","menuButton":"buttonStyles-module_menuButton__eg9D8","containerNode_class":"buttonStyles-module_containerNode_class__1rDgQ"};
  181. styleInject(css_248z$2);
  182.  
  183. // library.ts
  184. const config = {
  185. name: "aims-helper",
  186. init_customize: [
  187. {
  188. name: '繁體中文初始化',
  189. position: 'start',
  190. autoEnter: true,
  191. content: [
  192. `以下問答請使用繁體中文,並使用台灣用語。\n`,
  193. ].join("")
  194. }, {
  195. name: '請繼續',
  196. position: 'start',
  197. autoEnter: true,
  198. content: [
  199. `請繼續`,
  200. ].join("")
  201. }, {
  202. name: '請從""繼續',
  203. position: 'start',
  204. autoEnter: false,
  205. content: [
  206. `請從""繼續`,
  207. ].join("")
  208. }
  209. ],
  210. // ↓ 左邊選單的定位(上層)
  211. NAV_MENU: 'nav > div.overflow-y-auto',
  212. // ↓ 輸入框的定位
  213. TEXT_INPUTBOX_POSITION: 'textarea.m-0',
  214. // ↓ 送出按鈕的定位
  215. SUBMIT_BUTTON_POSITION: 'button.absolute',
  216. // ↓ 選單按鈕
  217. MAIN_BUTTON_CLASS: 'main_button',
  218. // ↓ 控制按鈕
  219. SETTING_BUTTON_CLASS: 'setting_button',
  220. // ↓ 選單
  221. MENU_CLASS: 'main_menu',
  222. // ↓ 按鈕文字
  223. HELPER_MENU_TEXT: 'input helper',
  224. // ↓ 按鈕用容器
  225. CONTAINER_CLASS: 'helper_textcontainer',
  226. // ↓ 模擬輸入於輸入框的事件
  227. INPUT_EVENT: new Event('input', { bubbles: true }),
  228. };
  229.  
  230. // 將自定義內容插入到輸入框中
  231. const insertCustomize = (customize, name) => {
  232. const textInputbox = document.querySelector(config.TEXT_INPUTBOX_POSITION);
  233. const item = customize.find((i) => i.name === name);
  234. if (item) {
  235. if (item.position === 'start') {
  236. textInputbox.value = item.content + textInputbox.value;
  237. }
  238. else {
  239. textInputbox.value += item.content;
  240. }
  241. textInputbox.dispatchEvent(config.INPUT_EVENT);
  242. textInputbox.focus();
  243. if (item.autoEnter) {
  244. setTimeout(() => {
  245. const submitButton = document.querySelector(config.SUBMIT_BUTTON_POSITION);
  246. submitButton.click();
  247. }, 100);
  248. }
  249. }
  250. else {
  251. console.error(`找不到名稱為 ${name} 的元素`);
  252. }
  253. };
  254.  
  255. // 創造主按鈕
  256. const createMainButton = (buttonText) => {
  257. const mainButton = document.createElement("button");
  258. mainButton.innerText = buttonText;
  259. mainButton.classList.add(styles$2.mainButton);
  260. mainButton.style.width = "86%";
  261. return mainButton;
  262. };
  263. // 創造設定按鈕
  264. const createSettingButton = () => {
  265. const settingButton = document.createElement("button");
  266. settingButton.innerText = "⚙️";
  267. settingButton.classList.add(styles$2.settingButton);
  268. settingButton.style.width = "14%";
  269. settingButton.id = "settingButton";
  270. return settingButton;
  271. };
  272. // 創造選項
  273. const createMenuItem = (element, customize) => {
  274. const menuItem = document.createElement("button");
  275. menuItem.innerText = element.name;
  276. menuItem.id = element.name;
  277. menuItem.classList.add(styles$2.menuButton);
  278. menuItem.addEventListener("click", (event) => {
  279. insertCustomize(customize, event.target.id);
  280. });
  281. return menuItem;
  282. };
  283. // 創造選單(包含多個選項)
  284. const createMenu = (containerNode, customize) => {
  285. // 創造選單
  286. const menu = document.createElement("div");
  287. menu.id = "helper_menu";
  288. menu.classList.add(styles$2.menu);
  289. menu.style.display = "none";
  290. menu.style.width = `${containerNode.offsetWidth / 100 * 86}px`;
  291. // 創造選項
  292. customize.forEach((element) => {
  293. const menuItem = createMenuItem(element, customize);
  294. menu.appendChild(menuItem);
  295. });
  296. // 設定選單的高度
  297. const windowHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
  298. const customizeUnitHeight = 39;
  299. const menuMaxHeight = windowHeight - customizeUnitHeight * 2;
  300. const MaxCustomizeLen = Number(menuMaxHeight / customizeUnitHeight);
  301. let customizeLen = customize.length > MaxCustomizeLen ? MaxCustomizeLen : customize.length;
  302. console.log(`customize.length = ${customize.length}`);
  303. console.log(`CustomizeLen = ${customizeLen}`);
  304. console.log(`menuMaxHeight = ${menuMaxHeight}`);
  305. if (customizeLen > 2) {
  306. let offset = (customizeLen - 2) * customizeUnitHeight;
  307. menu.style.top = `-${offset}px`;
  308. console.log(`offset = ${offset}`);
  309. }
  310. // 設定選單最大高度
  311. menu.style.maxHeight = `${menuMaxHeight}px`;
  312. return menu;
  313. };
  314.  
  315. const bindElementContainer = (elements, containerClass) => {
  316. const container = document.createElement("div");
  317. if (containerClass) {
  318. container.classList.add(containerClass);
  319. }
  320. elements.forEach((element) => {
  321. container.appendChild(element);
  322. });
  323. return container;
  324. };
  325.  
  326. // addMenuBtn 函數用於新增包含主按鈕和設定按鈕的選單按鈕
  327. function addMenuBtnWrapper(containerNode, customize, buttonText = "Click Me" // 主按鈕的文字,預設值為 "Click Me"
  328. ) {
  329. // 創建主按鈕和設定按鈕
  330. const mainButton = createMainButton(buttonText);
  331. const settingButton = createSettingButton();
  332. // 將主按鈕和設定按鈕組合在一個容器中
  333. const assButton = bindElementContainer([settingButton, mainButton], config.CONTAINER_CLASS);
  334. // 根據客製化選單項目創建選單
  335. const menu = createMenu(containerNode, customize);
  336. // 當滑鼠移到按鈕上時,顯示選單
  337. assButton.addEventListener("mouseenter", () => {
  338. menu.style.display = "block";
  339. });
  340. // 創建按鈕包裹器,並將組合按鈕和選單加入其中
  341. const buttonWrapper = document.createElement("div");
  342. buttonWrapper.style.width = `${containerNode.offsetWidth}px`;
  343. buttonWrapper.appendChild(assButton);
  344. buttonWrapper.appendChild(menu);
  345. // 將按鈕包裹器加入到容器節點中
  346. containerNode.appendChild(buttonWrapper);
  347. // 當滑鼠離開按鈕包裹器時,隱藏選單
  348. buttonWrapper.addEventListener("mouseleave", () => {
  349. setTimeout(() => {
  350. menu.style.display = "none";
  351. }, 300);
  352. });
  353. console.log("已新增按鈕");
  354. }
  355.  
  356. var css_248z$1 = ".formPopupStyles-module_form-popup__cpX-x{background-color:#40414f;border:1px solid #000;height:60%;left:50%;max-height:1200px;max-width:800px;padding:30px;position:fixed;top:50%;transform:translate(-50%,-50%);width:80%;z-index:9999}.formPopupStyles-module_form__A8xi3{display:flex;flex-direction:column;gap:15px}.formPopupStyles-module_form-row__sMrG8{display:flex;flex-direction:column;gap:5px}.formPopupStyles-module_input__f-v3V{background-color:#545766;border:1px solid #fff;color:#fff;margin-left:4px;padding:4px 8px}textarea.formPopupStyles-module_input__f-v3V{min-height:100px;width:100%}";
  357. var styles$1 = {"form-popup":"formPopupStyles-module_form-popup__cpX-x","form":"formPopupStyles-module_form__A8xi3","form-row":"formPopupStyles-module_form-row__sMrG8","input":"formPopupStyles-module_input__f-v3V"};
  358. styleInject(css_248z$1);
  359.  
  360. // createFormPopup.ts
  361. function createFormPopup(options) {
  362. // 創建彈出視窗
  363. const formPopup = document.createElement('div');
  364. formPopup.className = styles$1['form-popup'];
  365. // 創建標題
  366. const titleLabel = document.createElement('h2');
  367. titleLabel.textContent = options.title;
  368. formPopup.appendChild(titleLabel);
  369. // 創建表單
  370. const form = document.createElement('form');
  371. formPopup.appendChild(form);
  372. form.className = styles$1.form;
  373. // 創建名稱輸入框
  374. const nameLabel = document.createElement('label');
  375. nameLabel.textContent = '名稱(name)';
  376. form.appendChild(nameLabel);
  377. const nameInput = document.createElement('input');
  378. nameInput.type = 'text';
  379. nameInput.className = styles$1.input;
  380. form.appendChild(nameInput);
  381. // 創建位置選擇
  382. const positionLabel = document.createElement('label');
  383. positionLabel.textContent = '位置(position)';
  384. form.appendChild(positionLabel);
  385. const positionSelect = document.createElement('select');
  386. positionSelect.className = styles$1.input;
  387. const positionStartOption = document.createElement('option');
  388. positionStartOption.value = 'start';
  389. positionStartOption.textContent = 'start';
  390. const positionEndOption = document.createElement('option');
  391. positionEndOption.value = 'end';
  392. positionEndOption.textContent = 'end';
  393. positionSelect.appendChild(positionStartOption);
  394. positionSelect.appendChild(positionEndOption);
  395. form.appendChild(positionSelect);
  396. // 創建是否自動輸入選擇
  397. const autoEnterLabel = document.createElement('label');
  398. autoEnterLabel.textContent = '是否自動輸入(AutoEnter)';
  399. form.appendChild(autoEnterLabel);
  400. const autoEnterInput = document.createElement('input');
  401. autoEnterInput.type = 'checkbox';
  402. form.appendChild(autoEnterInput);
  403. // 創建內容輸入框
  404. const contentLabel = document.createElement('label');
  405. contentLabel.textContent = '內容(content)';
  406. form.appendChild(contentLabel);
  407. const contentTextarea = document.createElement('textarea');
  408. contentTextarea.className = `${styles$1.input} ${styles$1['textarea-input']}`;
  409. form.appendChild(contentTextarea);
  410. // 創建提交按鈕
  411. const submitButton = document.createElement('button');
  412. submitButton.type = 'submit';
  413. submitButton.textContent = '提交';
  414. form.appendChild(submitButton);
  415. // 根據編輯模式,填充初始值
  416. if (options.mode === 'edit' && options.initialValues) {
  417. nameInput.value = options.initialValues.name;
  418. positionSelect.value = options.initialValues.position;
  419. autoEnterInput.checked = options.initialValues.autoEnter;
  420. contentTextarea.value = options.initialValues.content;
  421. }
  422. // 提交表單時的處理
  423. form.addEventListener('submit', (event) => {
  424. event.preventDefault();
  425. const values = {
  426. name: nameInput.value,
  427. position: positionSelect.value,
  428. autoEnter: autoEnterInput.checked,
  429. content: contentTextarea.value,
  430. };
  431. console.log('values', values);
  432. options.onSubmit(values);
  433. document.body.removeChild(formPopup);
  434. });
  435. // 點擊彈窗外的地方關閉彈窗
  436. formPopup.addEventListener('click', (event) => {
  437. if (event.target === formPopup) {
  438. document.body.removeChild(formPopup);
  439. }
  440. });
  441. // 將彈出視窗加入頁面中
  442. document.body.appendChild(formPopup);
  443. }
  444.  
  445. var css_248z = ".setCustomizeBtn-module_popup__uF6hF{background:#525467;border:1px solid #000;height:80%;left:50%;max-height:1200px;max-width:800px;padding:30px;position:fixed;top:50%;transform:translate(-50%,-50%);width:80%;z-index:9999}.setCustomizeBtn-module_add-button__IASCv,.setCustomizeBtn-module_delete-button__8I8BH,.setCustomizeBtn-module_edit-button__NqnT6{border:2px solid #fff;margin:10px}.setCustomizeBtn-module_close-button__uw4Q6{position:absolute;right:5px;top:5px}.setCustomizeBtn-module_table-wrapper__LY27P{margin-bottom:20px;max-height:612px;overflow-y:auto}";
  446. var styles = {"popup":"setCustomizeBtn-module_popup__uF6hF","add-button":"setCustomizeBtn-module_add-button__IASCv","edit-button":"setCustomizeBtn-module_edit-button__NqnT6","delete-button":"setCustomizeBtn-module_delete-button__8I8BH","close-button":"setCustomizeBtn-module_close-button__uw4Q6","table-wrapper":"setCustomizeBtn-module_table-wrapper__LY27P"};
  447. styleInject(css_248z);
  448.  
  449. function setCustomizeBtn(customize) {
  450. // 找到 settingButton 元素
  451. const settingButton = document.getElementById('settingButton');
  452. // 當點擊 settingButton 時觸發事件
  453. settingButton.addEventListener('click', () => {
  454. // 創建彈出視窗
  455. const popup = document.createElement('div');
  456. popup.classList.add(styles.popup);
  457. // 創建新增按鈕
  458. const addButton = document.createElement('button');
  459. addButton.textContent = '新增(add)';
  460. addButton.classList.add(styles['add-button']);
  461. // 當點擊 addButton 時觸發事件
  462. addButton.addEventListener('click', () => {
  463. // 使用 createFormPopup 函數
  464. createFormPopup({
  465. title: '新增',
  466. mode: 'add',
  467. onSubmit: (values) => {
  468. const newItem = {
  469. name: values.name,
  470. position: values.position,
  471. autoEnter: values.autoEnter,
  472. content: values.content,
  473. };
  474. customize.push(newItem);
  475. renderTable();
  476. },
  477. });
  478. });
  479. popup.appendChild(addButton);
  480. // 創建編輯按鈕
  481. const editButton = document.createElement('button');
  482. editButton.textContent = '編輯(edit)';
  483. editButton.classList.add(styles['edit-button']);
  484. editButton.addEventListener('click', () => {
  485. // 編輯一個 item
  486. const index = prompt('請輸入要編輯的編號(edit index)');
  487. if (index && Number(index) >= 1 && index <= customize.length) {
  488. const item = customize[Number(index) - 1];
  489. createFormPopup({
  490. title: '編輯',
  491. mode: 'edit',
  492. initialValues: {
  493. name: item.name,
  494. position: item.position,
  495. autoEnter: item.autoEnter,
  496. content: item.content,
  497. },
  498. onSubmit: (newValues) => {
  499. item.name = newValues.name;
  500. item.position = newValues.position;
  501. item.autoEnter = newValues.autoEnter;
  502. item.content = newValues.content;
  503. // 重新渲染表格
  504. renderTable();
  505. },
  506. });
  507. }
  508. else {
  509. alert('輸入的編號不合法');
  510. }
  511. });
  512. popup.appendChild(editButton);
  513. // 創建刪除按鈕
  514. const deleteButton = document.createElement('button');
  515. deleteButton.textContent = '刪除(delete)';
  516. deleteButton.classList.add(styles['delete-button']);
  517. deleteButton.addEventListener('click', () => {
  518. // 刪除一個 item
  519. const index = prompt('請輸入要刪除的編號(delete index)');
  520. if (index && Number(index) >= 1 && index <= customize.length) {
  521. customize.splice(Number(index) - 1, 1);
  522. renderTable();
  523. }
  524. else {
  525. alert('輸入的編號不合法 (invalid index)');
  526. }
  527. });
  528. popup.appendChild(deleteButton);
  529. // 創建關閉按鈕
  530. const closeButton = document.createElement('button');
  531. closeButton.textContent = '儲存並離開(save&exit)';
  532. closeButton.classList.add(styles['close-button']);
  533. closeButton.addEventListener('click', () => {
  534. console.log(customize);
  535. // 儲存修改後的 customize 資料
  536. GM_setValue('customizeData', customize);
  537. // // 重寫一次 helper_menu
  538. // const helper_menu = document.getElementById('helper_menu');
  539. // const menu = createMenu(helper_menu);
  540. // helper_menu.replaceWith(menu);
  541. // 上面的做不出來
  542. // 所以只好重新整理頁面
  543. location.reload();
  544. document.body.removeChild(popup);
  545. });
  546. popup.appendChild(closeButton);
  547. // 創建表格
  548. const table = document.createElement('table');
  549. const tableWrapper = document.createElement('div');
  550. tableWrapper.classList.add(styles['table-wrapper']);
  551. tableWrapper.appendChild(table);
  552. popup.appendChild(tableWrapper);
  553. // 創建表頭
  554. const thead = document.createElement('thead');
  555. const tr = document.createElement('tr');
  556. const th1 = document.createElement('th');
  557. const th2 = document.createElement('th');
  558. const th3 = document.createElement('th');
  559. const th4 = document.createElement('th');
  560. const th5 = document.createElement('th');
  561. th1.textContent = '編號(index)';
  562. th2.textContent = '名稱(name)';
  563. th3.textContent = '位置(position)';
  564. th4.textContent = '自動輸入(autoEnter)?';
  565. th5.textContent = '內容(content)';
  566. tr.appendChild(th1);
  567. tr.appendChild(th2);
  568. tr.appendChild(th3);
  569. tr.appendChild(th4);
  570. tr.appendChild(th5);
  571. thead.appendChild(tr);
  572. table.appendChild(thead);
  573. // 創建表身
  574. const tbody = document.createElement('tbody');
  575. table.appendChild(tbody);
  576. // 渲染表格
  577. function renderTable() {
  578. // 先清空表格內容
  579. tbody.innerHTML = '';
  580. // 重新渲染表格
  581. customize.forEach((item, index) => {
  582. const tr = document.createElement('tr');
  583. const td1 = document.createElement('td');
  584. const td2 = document.createElement('td');
  585. const td3 = document.createElement('td');
  586. const td4 = document.createElement('td');
  587. const td5 = document.createElement('td');
  588. td1.textContent = index + 1;
  589. td2.textContent = item.name;
  590. td3.textContent = item.position;
  591. td4.textContent = item.autoEnter;
  592. td5.textContent = item.content;
  593. tr.appendChild(td1);
  594. tr.appendChild(td2);
  595. tr.appendChild(td3);
  596. tr.appendChild(td4);
  597. tr.appendChild(td5);
  598. tbody.appendChild(tr);
  599. });
  600. }
  601. // 渲染初始表格
  602. renderTable();
  603. // 點擊彈窗外的地方關閉彈窗
  604. popup.addEventListener('click', (event) => {
  605. if (event.target === popup) {
  606. document.body.removeChild(popup);
  607. }
  608. });
  609. // 將彈出視窗加入頁面中
  610. document.body.appendChild(popup);
  611. });
  612. }
  613.  
  614. main();
  615. function main() {
  616. // 頁面載入完成後執行
  617. onloadSafe(() => {
  618. // 監聽 nav 元素
  619. console.log("=====監聽 nav 元素=====");
  620. // 定義常用咒文
  621. let customize;
  622. sentinel.on("nav", (nav) => {
  623. console.log("===== trigger sentinel.on nav =====");
  624. // 讀取 customize 設定
  625. let GM_customize = GM_getValue("customizeData", customize);
  626. // 如果 user 已經有設定了就用 user 的,沒有就用預設值
  627. if (GM_customize) {
  628. customize = GM_customize;
  629. }
  630. else {
  631. customize = config.init_customize;
  632. GM_setValue("customizeData", customize);
  633. }
  634. //找不到就新增
  635. const container = document.getElementById("helper_menu");
  636. if (!container) {
  637. // 獲得目標元素
  638. const aimsNode = document.querySelector(config.NAV_MENU);
  639. // 新增一個容器
  640. const container = document.createElement("div");
  641. container.classList.add(styles$2.containerNode_class);
  642. container.id = "helper_menu";
  643. if (aimsNode) {
  644. // 設定 container 寬度為父元素寬度
  645. container.style.width = `${aimsNode.offsetWidth}px`; // 設定 container 寬度為父元素寬度
  646. // 將容器元素插入到目標元素後面
  647. aimsNode.parentNode?.insertBefore(container, aimsNode.nextSibling);
  648. // 新增一個按鈕元素
  649. addMenuBtnWrapper(container, customize, config.HELPER_MENU_TEXT);
  650. // 設定 "設定按鈕"的點擊事件
  651. setCustomizeBtn(customize);
  652. }
  653. }
  654. });
  655. });
  656. }
  657.  
  658. }));