CookieManager

简单而强大的Cookie编辑器,允许您快速创建、编辑和删除Cookie

  1. // ==UserScript==
  2. // @name CookieManager
  3. // @namespace https://github.com/WhiteSevs/TamperMonkeyScript
  4. // @version 2025.7.12
  5. // @author WhiteSevs
  6. // @description 简单而强大的Cookie编辑器,允许您快速创建、编辑和删除Cookie
  7. // @license GPL-3.0-only
  8. // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAAA/NJREFUeF7tWm1u4jAQjVHusfR3jMQNlp5ky0l2e5K2Jym9ARLO79JzEMgyKF5FqeN5YzuwQPoHqRl/zPObN5NxVHbnf+rO/c9GAEYG3DkCYwjcOQFGETxbCGitF1mWLeq6/qGUmtZ1PW1+t0qpN2PMn0uwcTAA5vP5tKqqp8bhJ8C5R2PMCrBLajIIAFprOs3fkp0eGfFaluVSMiaFbVIAQhy3Tlw1AA3dXyjGQ0/lagFoxO091PGrZkAq5wmEq2NASuevDgCB889HXVjleb6tqmraaASbHeq6ptpgm+f5cr1eb2PDyzdenAUawfsENuXM60VRvBydQ+oCWmJljHkE1go2EQOgtSbB86q9L54FAJIubMuyfAj2DhgoAmA2m1FlR+nO+6eUWm42m9c+IwREO9YYI9ojt7fuc9HkRVF8Uv0OLPLsq+0F82T/DQDCKs8bu1rrGgDxZELh5LKdTCYfPpah88MMkGy6WdwpghL6A054mQaMx/oBaOy3F2xS2ZtNg/SsqqqocrnrUAqRhBggTF0I8MlsYjUCAiCA/skc5CYaHACO/rZq42oDzpHQ55RyXWNRgWQZ0Ef/xvFlu4sjzBShPkPjXPtzDQwGIM/zB1edzjEG2n06I7aUZgFwpS3u1dVX6LSyg83zv8DiKgSWeABczkSUut82ZJun0h4iggaSJhEGuKq20FLXWRylaKm5ABkMAN/Efb0CbjNDCSiXJlkGeOL5GwuYk/TG4xDiyYFOrGEB8NXuVtCoe0M3Pb445jbDVZs0/rRhpegX7T4nEUFJB8erTX3iyTVJulkHFU4uW6EMEN/y9KFgGdPuFQAC2HuK3JtlKgCIbtF9f8ebom12euncV3DRfFxzlkvXEAM4eiL5OMbGp+Lc3rgMAAHQIM02QmOcZMb23hr7AEDoLwEgeRgIAOstuny1A0J/GACOagJnxKYu4UTiH6E/DAAZpipUQvsHRGlqhDb1Bm3Jd8ME9wrZQsgeGbFgt9u9h765nbN/gJ6+iAGxLDhX/wCNfXuwMANoAFC0OGOcU2TJRQkjImzp2x0vAsCCIA0F7lS4ig5RTu5do28OMQAtJiA3xHbd0P4B4ru1CfrKLAgAqR6E9A8knmdZFuS8WAS7mxI2MaT9AxSDYOejAZBqgqR/wHmPtr25eYJDoD1xbI3AbbL7PFTwXOskAaAljPQBxWBt7r6yWApg2z4ZAO2Kkb4RTtnmHsLxoEJIgjSFxX6/XxwOh5+Cj6L+LdF6Z/gY8kvy5AxwgdQG46S8nc/lm/9RY5U+j/uixid6uSk5lEE1IHYjlxp/FgZcyjlk3REABKVbthkZcMuni/g2MgBB6ZZt/gJwetZfo7objAAAAABJRU5ErkJggg==
  9. // @supportURL https://github.com/WhiteSevs/TamperMonkeyScript/issues
  10. // @match *://*/*
  11. // @require https://fastly.jsdelivr.net/gh/WhiteSevs/TamperMonkeyScript@86be74b83fca4fa47521cded28377b35e1d7d2ac/lib/CoverUMD/index.js
  12. // @require https://fastly.jsdelivr.net/npm/@whitesev/utils@2.7.0/dist/index.umd.js
  13. // @require https://fastly.jsdelivr.net/npm/@whitesev/domutils@1.5.11/dist/index.umd.js
  14. // @require https://fastly.jsdelivr.net/npm/@whitesev/pops@2.1.13/dist/index.umd.js
  15. // @require https://fastly.jsdelivr.net/npm/qmsg@1.3.8/dist/index.umd.js
  16. // @connect *
  17. // @grant GM.cookie
  18. // @grant GM_cookie
  19. // @grant GM_deleteValue
  20. // @grant GM_getValue
  21. // @grant GM_info
  22. // @grant GM_registerMenuCommand
  23. // @grant GM_setValue
  24. // @grant GM_unregisterMenuCommand
  25. // @grant GM_xmlhttpRequest
  26. // @grant unsafeWindow
  27. // @run-at document-start
  28. // ==/UserScript==
  29.  
  30. (function (Qmsg, DOMUtils, Utils, pops) {
  31. 'use strict';
  32.  
  33. var _GM = /* @__PURE__ */ (() => typeof GM != "undefined" ? GM : void 0)();
  34. var _GM_cookie = /* @__PURE__ */ (() => typeof GM_cookie != "undefined" ? GM_cookie : void 0)();
  35. var _GM_deleteValue = /* @__PURE__ */ (() => typeof GM_deleteValue != "undefined" ? GM_deleteValue : void 0)();
  36. var _GM_getValue = /* @__PURE__ */ (() => typeof GM_getValue != "undefined" ? GM_getValue : void 0)();
  37. var _GM_info = /* @__PURE__ */ (() => typeof GM_info != "undefined" ? GM_info : void 0)();
  38. var _GM_registerMenuCommand = /* @__PURE__ */ (() => typeof GM_registerMenuCommand != "undefined" ? GM_registerMenuCommand : void 0)();
  39. var _GM_setValue = /* @__PURE__ */ (() => typeof GM_setValue != "undefined" ? GM_setValue : void 0)();
  40. var _GM_unregisterMenuCommand = /* @__PURE__ */ (() => typeof GM_unregisterMenuCommand != "undefined" ? GM_unregisterMenuCommand : void 0)();
  41. var _GM_xmlhttpRequest = /* @__PURE__ */ (() => typeof GM_xmlhttpRequest != "undefined" ? GM_xmlhttpRequest : void 0)();
  42. var _unsafeWindow = /* @__PURE__ */ (() => typeof unsafeWindow != "undefined" ? unsafeWindow : void 0)();
  43. var _monkeyWindow = /* @__PURE__ */ (() => window)();
  44. const KEY = "GM_Panel";
  45. const ATTRIBUTE_INIT = "data-init";
  46. const ATTRIBUTE_KEY = "data-key";
  47. const ATTRIBUTE_DEFAULT_VALUE = "data-default-value";
  48. const ATTRIBUTE_INIT_MORE_VALUE = "data-init-more-value";
  49. const PROPS_STORAGE_API = "data-storage-api";
  50. const PanelUISize = {
  51. /**
  52. * 一般设置界面的尺寸
  53. */
  54. setting: {
  55. get width() {
  56. if (window.innerWidth < 550) {
  57. return "88vw";
  58. } else if (window.innerWidth < 700) {
  59. return "550px";
  60. } else {
  61. return "700px";
  62. }
  63. },
  64. get height() {
  65. if (window.innerHeight < 450) {
  66. return "70vh";
  67. } else if (window.innerHeight < 550) {
  68. return "450px";
  69. } else {
  70. return "550px";
  71. }
  72. }
  73. },
  74. /**
  75. * 信息界面,一般用于提示信息之类
  76. */
  77. info: {
  78. get width() {
  79. return window.innerWidth < 350 ? "350px" : "350px";
  80. },
  81. get height() {
  82. return window.innerHeight < 250 ? "250px" : "250px";
  83. }
  84. }
  85. };
  86. class StorageUtils {
  87. /** 存储的键名 */
  88. storageKey;
  89. listenerData;
  90. /**
  91. * 存储的键名,可以是多层的,如:a.b.c
  92. *
  93. * 那就是
  94. * {
  95. * "a": {
  96. * "b": {
  97. * "c": {
  98. * ...你的数据
  99. * }
  100. * }
  101. * }
  102. * }
  103. * @param key
  104. */
  105. constructor(key) {
  106. if (typeof key === "string") {
  107. let trimKey = key.trim();
  108. if (trimKey == "") {
  109. throw new Error("key参数不能为空字符串");
  110. }
  111. this.storageKey = trimKey;
  112. } else {
  113. throw new Error("key参数类型错误,必须是字符串");
  114. }
  115. this.listenerData = new Utils.Dictionary();
  116. }
  117. /**
  118. * 获取本地值
  119. */
  120. getLocalValue() {
  121. let localValue = _GM_getValue(this.storageKey);
  122. if (localValue == null) {
  123. localValue = {};
  124. this.setLocalValue(localValue);
  125. }
  126. return localValue;
  127. }
  128. /**
  129. * 设置本地值
  130. * @param value
  131. */
  132. setLocalValue(value) {
  133. _GM_setValue(this.storageKey, value);
  134. }
  135. /**
  136. * 设置值
  137. * @param key 键
  138. * @param value 值
  139. */
  140. set(key, value) {
  141. let oldValue = this.get(key);
  142. let localValue = this.getLocalValue();
  143. Reflect.set(localValue, key, value);
  144. this.setLocalValue(localValue);
  145. this.triggerValueChangeListener(key, oldValue, value);
  146. }
  147. /**
  148. * 获取值
  149. * @param key 键
  150. * @param defaultValue 默认值
  151. */
  152. get(key, defaultValue) {
  153. let localValue = this.getLocalValue();
  154. return Reflect.get(localValue, key) ?? defaultValue;
  155. }
  156. /**
  157. * 获取所有值
  158. */
  159. getAll() {
  160. let localValue = this.getLocalValue();
  161. return localValue;
  162. }
  163. /**
  164. * 删除值
  165. * @param key 键
  166. */
  167. delete(key) {
  168. let oldValue = this.get(key);
  169. let localValue = this.getLocalValue();
  170. Reflect.deleteProperty(localValue, key);
  171. this.setLocalValue(localValue);
  172. this.triggerValueChangeListener(key, oldValue, void 0);
  173. }
  174. /**
  175. * 判断是否存在该值
  176. */
  177. has(key) {
  178. let localValue = this.getLocalValue();
  179. return Reflect.has(localValue, key);
  180. }
  181. /**
  182. * 获取所有键
  183. */
  184. keys() {
  185. let localValue = this.getLocalValue();
  186. return Reflect.ownKeys(localValue);
  187. }
  188. /**
  189. * 获取所有值
  190. */
  191. values() {
  192. let localValue = this.getLocalValue();
  193. return Reflect.ownKeys(localValue).map(
  194. (key) => Reflect.get(localValue, key)
  195. );
  196. }
  197. /**
  198. * 清空所有值
  199. */
  200. clear() {
  201. _GM_deleteValue(this.storageKey);
  202. }
  203. /**
  204. * 监听值改变
  205. * + .set
  206. * + .delete
  207. * @param key 监听的键
  208. * @param callback 值改变的回调函数
  209. */
  210. addValueChangeListener(key, callback) {
  211. let listenerId = Math.random();
  212. let listenerData = this.listenerData.get(key) || [];
  213. listenerData.push({
  214. id: listenerId,
  215. key,
  216. callback
  217. });
  218. this.listenerData.set(key, listenerData);
  219. return listenerId;
  220. }
  221. /**
  222. * 移除监听
  223. * @param listenerId 监听的id或键名
  224. */
  225. removeValueChangeListener(listenerId) {
  226. let flag = false;
  227. for (const [key, listenerData] of this.listenerData.entries()) {
  228. for (let index = 0; index < listenerData.length; index++) {
  229. const value = listenerData[index];
  230. if (typeof listenerId === "string" && value.key === listenerId || typeof listenerId === "number" && value.id === listenerId) {
  231. listenerData.splice(index, 1);
  232. index--;
  233. flag = true;
  234. }
  235. }
  236. this.listenerData.set(key, listenerData);
  237. }
  238. return flag;
  239. }
  240. /**
  241. * 主动触发监听器
  242. * @param key 键
  243. * @param oldValue (可选)旧值
  244. * @param newValue (可选)新值
  245. */
  246. triggerValueChangeListener(key, oldValue, newValue) {
  247. if (!this.listenerData.has(key)) {
  248. return;
  249. }
  250. let listenerData = this.listenerData.get(key);
  251. for (let index = 0; index < listenerData.length; index++) {
  252. const data = listenerData[index];
  253. if (typeof data.callback === "function") {
  254. let value = this.get(key);
  255. let __newValue;
  256. let __oldValue;
  257. if (typeof oldValue !== "undefined" && arguments.length >= 2) {
  258. __oldValue = oldValue;
  259. } else {
  260. __oldValue = value;
  261. }
  262. if (typeof newValue !== "undefined" && arguments.length > 2) {
  263. __newValue = newValue;
  264. } else {
  265. __newValue = value;
  266. }
  267. data.callback(key, __oldValue, __newValue);
  268. }
  269. }
  270. }
  271. }
  272. const PopsPanelStorageApi = new StorageUtils(KEY);
  273. const PanelMenu = {
  274. $data: {
  275. __menuOption: [
  276. {
  277. key: "show_pops_panel_setting",
  278. text: "⚙ 设置",
  279. autoReload: false,
  280. isStoreValue: false,
  281. showText(text) {
  282. return text;
  283. },
  284. callback: () => {
  285. Panel.showPanel(PanelContent.getConfig(0));
  286. }
  287. }
  288. ],
  289. get menuOption() {
  290. return this.__menuOption;
  291. }
  292. },
  293. init() {
  294. this.initExtensionsMenu();
  295. },
  296. /**
  297. * 初始化菜单项
  298. */
  299. initExtensionsMenu() {
  300. if (!Panel.isTopWindow()) {
  301. return;
  302. }
  303. GM_Menu.add(this.$data.menuOption);
  304. },
  305. /**
  306. * 添加菜单项
  307. * @param option 菜单配置
  308. */
  309. addMenuOption(option) {
  310. if (!Array.isArray(option)) {
  311. option = [option];
  312. }
  313. this.$data.menuOption.push(...option);
  314. },
  315. /**
  316. * 更新菜单项
  317. * @param option 菜单配置
  318. */
  319. updateMenuOption(option) {
  320. if (!Array.isArray(option)) {
  321. option = [option];
  322. }
  323. option.forEach((optionItem) => {
  324. let findIndex = this.$data.menuOption.findIndex((it) => {
  325. return it.key === optionItem.key;
  326. });
  327. if (findIndex !== -1) {
  328. this.$data.menuOption[findIndex] = optionItem;
  329. }
  330. });
  331. },
  332. /**
  333. * 获取菜单项
  334. * @param [index=0] 索引
  335. */
  336. getMenuOption(index = 0) {
  337. return this.$data.menuOption[index];
  338. },
  339. /**
  340. * 删除菜单项
  341. * @param [index=0] 索引
  342. */
  343. deleteMenuOption(index = 0) {
  344. this.$data.menuOption.splice(index, 1);
  345. }
  346. };
  347. const Panel = {
  348. /** 数据 */
  349. $data: {
  350. /**
  351. * @private
  352. */
  353. __configDefaultValueData: null,
  354. /**
  355. * @private
  356. */
  357. __onceExecMenuData: null,
  358. /**
  359. * @private
  360. */
  361. __onceExecData: null,
  362. /**
  363. * @private
  364. */
  365. __panelConfig: {},
  366. $panel: null,
  367. /**
  368. * 菜单项的默认值
  369. */
  370. get configDefaultValueData() {
  371. if (this.__configDefaultValueData == null) {
  372. this.__configDefaultValueData = new utils.Dictionary();
  373. }
  374. return this.__configDefaultValueData;
  375. },
  376. /**
  377. * 成功只执行了一次的项
  378. */
  379. get onceExecMenuData() {
  380. if (this.__onceExecMenuData == null) {
  381. this.__onceExecMenuData = new utils.Dictionary();
  382. }
  383. return this.__onceExecMenuData;
  384. },
  385. /**
  386. * 成功只执行了一次的项
  387. */
  388. get onceExecData() {
  389. if (this.__onceExecData == null) {
  390. this.__onceExecData = new utils.Dictionary();
  391. }
  392. return this.__onceExecData;
  393. },
  394. /** 脚本名,一般用在设置的标题上 */
  395. get scriptName() {
  396. return SCRIPT_NAME;
  397. },
  398. /**
  399. * pops.panel的默认配置
  400. */
  401. get panelConfig() {
  402. return this.__panelConfig;
  403. },
  404. set panelConfig(value) {
  405. this.__panelConfig = value;
  406. },
  407. /** 菜单项的总值在本地数据配置的键名 */
  408. key: KEY,
  409. /** 菜单项在attributes上配置的菜单键 */
  410. attributeKeyName: ATTRIBUTE_KEY,
  411. /** 菜单项在attributes上配置的菜单默认值 */
  412. attributeDefaultValueName: ATTRIBUTE_DEFAULT_VALUE
  413. },
  414. init() {
  415. this.initContentDefaultValue();
  416. PanelMenu.init();
  417. },
  418. /** 判断是否是顶层窗口 */
  419. isTopWindow() {
  420. return _unsafeWindow.top === _unsafeWindow.self;
  421. },
  422. /** 初始化菜单项的默认值保存到本地数据中 */
  423. initContentDefaultValue() {
  424. const initDefaultValue = (config) => {
  425. if (!config.attributes) {
  426. return;
  427. }
  428. if (config.type === "button" || config.type === "forms" || config.type === "deepMenu") {
  429. return;
  430. }
  431. let needInitConfig = {};
  432. let key = config.attributes[ATTRIBUTE_KEY];
  433. if (key != null) {
  434. needInitConfig[key] = config.attributes[ATTRIBUTE_DEFAULT_VALUE];
  435. }
  436. let __attr_init__ = config.attributes[ATTRIBUTE_INIT];
  437. if (typeof __attr_init__ === "function") {
  438. let __attr_result__ = __attr_init__();
  439. if (typeof __attr_result__ === "boolean" && !__attr_result__) {
  440. return;
  441. }
  442. }
  443. let initMoreValue = config.attributes[ATTRIBUTE_INIT_MORE_VALUE];
  444. if (initMoreValue && typeof initMoreValue === "object") {
  445. Object.assign(needInitConfig, initMoreValue);
  446. }
  447. let needInitConfigList = Object.keys(needInitConfig);
  448. if (!needInitConfigList.length) {
  449. log.warn(["请先配置键", config]);
  450. return;
  451. }
  452. needInitConfigList.forEach((__key) => {
  453. let __defaultValue = needInitConfig[__key];
  454. this.setDefaultValue(__key, __defaultValue);
  455. });
  456. };
  457. const loopInitDefaultValue = (configList) => {
  458. for (let index = 0; index < configList.length; index++) {
  459. let configItem = configList[index];
  460. initDefaultValue(configItem);
  461. let childForms = configItem.forms;
  462. if (childForms && Array.isArray(childForms)) {
  463. loopInitDefaultValue(childForms);
  464. }
  465. }
  466. };
  467. const contentConfigList = [...PanelContent.getAllContentConfig()];
  468. for (let index = 0; index < contentConfigList.length; index++) {
  469. let leftContentConfigItem = contentConfigList[index];
  470. if (!leftContentConfigItem.forms) {
  471. continue;
  472. }
  473. const rightContentConfigList = leftContentConfigItem.forms;
  474. if (rightContentConfigList && Array.isArray(rightContentConfigList)) {
  475. loopInitDefaultValue(rightContentConfigList);
  476. }
  477. }
  478. },
  479. /**
  480. * 设置初始化使用的默认值
  481. */
  482. setDefaultValue(key, defaultValue) {
  483. if (this.$data.configDefaultValueData.has(key)) {
  484. log.warn("请检查该key(已存在): " + key);
  485. }
  486. this.$data.configDefaultValueData.set(key, defaultValue);
  487. },
  488. /**
  489. * 设置值
  490. * @param key 键
  491. * @param value 值
  492. */
  493. setValue(key, value) {
  494. PopsPanelStorageApi.set(key, value);
  495. },
  496. /**
  497. * 获取值
  498. * @param key 键
  499. * @param defaultValue 默认值
  500. */
  501. getValue(key, defaultValue) {
  502. let localValue = PopsPanelStorageApi.get(key);
  503. if (localValue == null) {
  504. if (this.$data.configDefaultValueData.has(key)) {
  505. return this.$data.configDefaultValueData.get(key);
  506. }
  507. return defaultValue;
  508. }
  509. return localValue;
  510. },
  511. /**
  512. * 删除值
  513. * @param key 键
  514. */
  515. deleteValue(key) {
  516. PopsPanelStorageApi.delete(key);
  517. },
  518. /**
  519. * 判断该键是否存在
  520. * @param key 键
  521. */
  522. hasKey(key) {
  523. return PopsPanelStorageApi.has(key);
  524. },
  525. /**
  526. * 监听调用setValue、deleteValue
  527. * @param key 需要监听的键
  528. * @param callback
  529. */
  530. addValueChangeListener(key, callback) {
  531. let listenerId = PopsPanelStorageApi.addValueChangeListener(
  532. key,
  533. (__key, __newValue, __oldValue) => {
  534. callback(key, __oldValue, __newValue);
  535. }
  536. );
  537. return listenerId;
  538. },
  539. /**
  540. * 移除监听
  541. * @param listenerId 监听的id
  542. */
  543. removeValueChangeListener(listenerId) {
  544. PopsPanelStorageApi.removeValueChangeListener(listenerId);
  545. },
  546. /**
  547. * 主动触发菜单值改变的回调
  548. * @param key 菜单键
  549. * @param newValue 想要触发的新值,默认使用当前值
  550. * @param oldValue 想要触发的旧值,默认使用当前值
  551. */
  552. triggerMenuValueChange(key, newValue, oldValue) {
  553. PopsPanelStorageApi.triggerValueChangeListener(key, oldValue, newValue);
  554. },
  555. /**
  556. * 移除已执行的仅执行一次的菜单
  557. * @param key 键
  558. */
  559. deleteExecMenuOnce(key) {
  560. this.$data.onceExecMenuData.delete(key);
  561. let flag = PopsPanelStorageApi.removeValueChangeListener(key);
  562. return flag;
  563. },
  564. /**
  565. * 移除已执行的仅执行一次的菜单
  566. * @param key 键
  567. */
  568. deleteOnceExec(key) {
  569. this.$data.onceExecData.delete(key);
  570. },
  571. /**
  572. * 执行菜单
  573. *
  574. * @param queryKey 键|键数组
  575. * @param callback 执行的回调函数
  576. * @param checkExec 判断是否执行回调
  577. *
  578. * (默认)如果想要每个菜单是`与`关系,即每个菜单都判断为开启,那么就判断它们的值&就行
  579. *
  580. * 如果想要任意菜单存在true再执行,那么判断它们的值|就行
  581. *
  582. * + 返回值都为`true`,执行回调,如果回调返回了<style>元素,该元素会在监听到值改变时被移除掉
  583. * + 返回值有一个为`false`,则不执行回调,且移除之前回调函数返回的<style>元素
  584. * @param once 是否只执行一次,默认true
  585. *
  586. * + true (默认)只执行一次,且会监听键的值改变
  587. * + false 不会监听键的值改变
  588. */
  589. exec(queryKey, callback, checkExec, once = true) {
  590. const that = this;
  591. let queryKeyFn;
  592. if (typeof queryKey === "string" || Array.isArray(queryKey)) {
  593. queryKeyFn = () => queryKey;
  594. } else {
  595. queryKeyFn = queryKey;
  596. }
  597. let isArrayKey = false;
  598. let queryKeyResult = queryKeyFn();
  599. let keyList = [];
  600. if (Array.isArray(queryKeyResult)) {
  601. isArrayKey = true;
  602. keyList = queryKeyResult;
  603. } else {
  604. keyList.push(queryKeyResult);
  605. }
  606. let findNotInDataKey = keyList.find(
  607. (it) => !this.$data.configDefaultValueData.has(it)
  608. );
  609. if (findNotInDataKey) {
  610. log.warn(`${findNotInDataKey} 键不存在`);
  611. return;
  612. }
  613. let storageKey = JSON.stringify(keyList);
  614. if (once) {
  615. if (this.$data.onceExecMenuData.has(storageKey)) {
  616. return;
  617. }
  618. this.$data.onceExecMenuData.set(storageKey, 1);
  619. }
  620. let storeValueList = [];
  621. let listenerIdList = [];
  622. let dynamicAddStyleNodeCallback = (value, $style) => {
  623. let dynamicResultList = [];
  624. if (!Array.isArray($style)) {
  625. $style = [$style];
  626. }
  627. $style.forEach(($styleItem) => {
  628. if ($styleItem == null) {
  629. return;
  630. }
  631. if ($styleItem instanceof HTMLStyleElement) {
  632. dynamicResultList.push($styleItem);
  633. return;
  634. }
  635. });
  636. {
  637. storeValueList = storeValueList.concat(dynamicResultList);
  638. }
  639. };
  640. let getMenuValue = (key) => {
  641. let value = this.getValue(key);
  642. return value;
  643. };
  644. let clearBeforeStoreValue = () => {
  645. for (let index = 0; index < storeValueList.length; index++) {
  646. let $css = storeValueList[index];
  647. $css.remove();
  648. storeValueList.splice(index, 1);
  649. index--;
  650. }
  651. };
  652. let checkMenuExec = () => {
  653. let flag = false;
  654. if (typeof checkExec === "function") {
  655. flag = checkExec(keyList);
  656. } else {
  657. flag = keyList.every((key) => getMenuValue(key));
  658. }
  659. return flag;
  660. };
  661. let valueChangeCallback = (valueOption) => {
  662. let execFlag = checkMenuExec();
  663. let resultList = [];
  664. if (execFlag) {
  665. let valueList = keyList.map((key) => this.getValue(key));
  666. let callbackResult = callback({
  667. value: isArrayKey ? valueList : valueList[0],
  668. addStyleElement: (...args) => {
  669. return dynamicAddStyleNodeCallback(true, ...args);
  670. }
  671. });
  672. if (!Array.isArray(callbackResult)) {
  673. callbackResult = [callbackResult];
  674. }
  675. callbackResult.forEach((it) => {
  676. if (it == null) {
  677. return;
  678. }
  679. if (it instanceof HTMLStyleElement) {
  680. resultList.push(it);
  681. return;
  682. }
  683. });
  684. }
  685. clearBeforeStoreValue();
  686. storeValueList = [...resultList];
  687. };
  688. once && keyList.forEach((key) => {
  689. let listenerId = this.addValueChangeListener(
  690. key,
  691. (key2, newValue, oldValue) => {
  692. valueChangeCallback();
  693. }
  694. );
  695. listenerIdList.push(listenerId);
  696. });
  697. valueChangeCallback();
  698. let result = {
  699. /**
  700. * 清空菜单执行情况
  701. *
  702. * + 清空存储的元素列表
  703. * + 清空值改变的监听器
  704. * + 清空存储的一次执行的键
  705. */
  706. clear() {
  707. this.clearStoreStyleElements();
  708. this.removeValueChangeListener();
  709. once && that.$data.onceExecMenuData.delete(storageKey);
  710. },
  711. /**
  712. * 清空存储的元素列表
  713. */
  714. clearStoreStyleElements: () => {
  715. return clearBeforeStoreValue();
  716. },
  717. /**
  718. * 移除值改变的监听器
  719. */
  720. removeValueChangeListener: () => {
  721. listenerIdList.forEach((listenerId) => {
  722. this.removeValueChangeListener(listenerId);
  723. });
  724. }
  725. };
  726. return result;
  727. },
  728. /**
  729. * 自动判断菜单是否启用,然后执行回调
  730. * @param key
  731. * @param callback 回调
  732. * @param [isReverse=false] 逆反判断菜单启用
  733. */
  734. execMenu(key, callback, isReverse = false) {
  735. return this.exec(
  736. key,
  737. (option) => {
  738. return callback(option);
  739. },
  740. (keyList) => {
  741. let execFlag = keyList.every((__key__) => {
  742. let flag = !!this.getValue(__key__);
  743. isReverse && (flag = !flag);
  744. return flag;
  745. });
  746. return execFlag;
  747. },
  748. false
  749. );
  750. },
  751. /**
  752. * 自动判断菜单是否启用,然后执行回调,只会执行一次
  753. *
  754. * 它会自动监听值改变(设置中的修改),改变后如果未执行,则执行一次
  755. * @param key
  756. * @param callback 回调
  757. * @param getValueFn 自定义处理获取当前值,值true是启用并执行回调,值false是不执行回调
  758. * @param handleValueChangeFn 自定义处理值改变时的回调,值true是启用并执行回调,值false是不执行回调
  759. */
  760. execMenuOnce(key, callback) {
  761. return this.exec(
  762. key,
  763. callback,
  764. (keyList) => {
  765. let execFlag = keyList.every((__key__) => {
  766. let flag = !!this.getValue(__key__);
  767. return flag;
  768. });
  769. return execFlag;
  770. },
  771. true
  772. );
  773. },
  774. /**
  775. * 根据key执行一次
  776. * @param key 键
  777. * @param callback 回调
  778. */
  779. onceExec(key, callback) {
  780. if (typeof key !== "string") {
  781. throw new TypeError("key 必须是字符串");
  782. }
  783. if (this.$data.onceExecData.has(key)) {
  784. return;
  785. }
  786. callback();
  787. this.$data.onceExecData.set(key, 1);
  788. },
  789. /**
  790. * 显示设置面板
  791. * @param content 显示的内容配置
  792. * @param [title] 标题
  793. * @param [preventDefaultContentConfig=false] 是否阻止默认添加内容配置(版本号)
  794. */
  795. showPanel(content, title = `${SCRIPT_NAME}-设置`, preventDefaultContentConfig = false) {
  796. let notHasBottomVersionContentConfig = content.some((it) => {
  797. let isBottom = typeof it.isBottom === "function" ? it.isBottom() : Boolean(it.isBottom);
  798. return !isBottom && it.id !== "script-version";
  799. });
  800. if (!preventDefaultContentConfig && notHasBottomVersionContentConfig) {
  801. content.push(...PanelContent.getDefaultBottomContentConfig());
  802. }
  803. let $panel = __pops.panel({
  804. ...{
  805. title: {
  806. text: title,
  807. position: "center",
  808. html: false,
  809. style: ""
  810. },
  811. content,
  812. btn: {
  813. close: {
  814. enable: true,
  815. callback: (details, event) => {
  816. details.close();
  817. this.$data.$panel = null;
  818. }
  819. }
  820. },
  821. mask: {
  822. enable: true,
  823. clickEvent: {
  824. toClose: true,
  825. toHide: false
  826. },
  827. clickCallBack: (originalRun, config) => {
  828. originalRun();
  829. this.$data.$panel = null;
  830. }
  831. },
  832. width: PanelUISize.setting.width,
  833. height: PanelUISize.setting.height,
  834. drag: true,
  835. only: true
  836. },
  837. ...this.$data.panelConfig
  838. });
  839. this.$data.$panel = $panel;
  840. }
  841. };
  842. const PanelSettingConfig = {
  843. /** Toast位置 */
  844. qmsg_config_position: {
  845. key: "qmsg-config-position",
  846. defaultValue: "bottom"
  847. },
  848. /** 最多显示的数量 */
  849. qmsg_config_maxnums: {
  850. key: "qmsg-config-maxnums",
  851. defaultValue: 3
  852. },
  853. /** 逆序弹出 */
  854. qmsg_config_showreverse: {
  855. key: "qmsg-config-showreverse",
  856. defaultValue: false
  857. }
  858. };
  859. const utils = Utils.noConflict();
  860. const domUtils = DOMUtils.noConflict();
  861. const __pops = pops;
  862. const log = new utils.Log(
  863. _GM_info,
  864. _unsafeWindow.console || _monkeyWindow.console
  865. );
  866. let SCRIPT_NAME = _GM_info?.script?.name || void 0;
  867. pops.config.Utils.AnyTouch();
  868. const DEBUG = false;
  869. log.config({
  870. debug: DEBUG,
  871. logMaxCount: 1e3,
  872. autoClearConsole: true,
  873. tag: true
  874. });
  875. Qmsg.config(
  876. Object.defineProperties(
  877. {
  878. html: true,
  879. autoClose: true,
  880. showClose: false
  881. },
  882. {
  883. position: {
  884. get() {
  885. return Panel.getValue(
  886. PanelSettingConfig.qmsg_config_position.key,
  887. PanelSettingConfig.qmsg_config_position.defaultValue
  888. );
  889. }
  890. },
  891. maxNums: {
  892. get() {
  893. return Panel.getValue(
  894. PanelSettingConfig.qmsg_config_maxnums.key,
  895. PanelSettingConfig.qmsg_config_maxnums.defaultValue
  896. );
  897. }
  898. },
  899. showReverse: {
  900. get() {
  901. return Panel.getValue(
  902. PanelSettingConfig.qmsg_config_showreverse.key,
  903. PanelSettingConfig.qmsg_config_showreverse.defaultValue
  904. );
  905. }
  906. },
  907. zIndex: {
  908. get() {
  909. let maxZIndex = Utils.getMaxZIndex();
  910. let popsMaxZIndex = pops.config.InstanceUtils.getPopsMaxZIndex().zIndex;
  911. return Utils.getMaxValue(maxZIndex, popsMaxZIndex) + 100;
  912. }
  913. }
  914. }
  915. )
  916. );
  917. __pops.GlobalConfig.setGlobalConfig({
  918. zIndex: () => {
  919. let maxZIndex = Utils.getMaxZIndex(void 0, void 0, ($ele) => {
  920. if ($ele?.classList?.contains("qmsg-shadow-container")) {
  921. return false;
  922. }
  923. if ($ele?.closest("qmsg") && $ele.getRootNode() instanceof ShadowRoot) {
  924. return false;
  925. }
  926. });
  927. let popsMaxZIndex = pops.config.InstanceUtils.getPopsMaxZIndex().zIndex;
  928. return Utils.getMaxValue(maxZIndex, popsMaxZIndex) + 100;
  929. },
  930. mask: {
  931. // 开启遮罩层
  932. enable: true,
  933. // 取消点击遮罩层的事件
  934. clickEvent: {
  935. toClose: false,
  936. toHide: false
  937. }
  938. }
  939. });
  940. const GM_Menu = new utils.GM_Menu({
  941. GM_getValue: _GM_getValue,
  942. GM_setValue: _GM_setValue,
  943. GM_registerMenuCommand: _GM_registerMenuCommand,
  944. GM_unregisterMenuCommand: _GM_unregisterMenuCommand
  945. });
  946. const httpx = new utils.Httpx({
  947. xmlHttpRequest: _GM_xmlhttpRequest,
  948. logDetails: DEBUG
  949. });
  950. httpx.interceptors.request.use((data) => {
  951. return data;
  952. });
  953. httpx.interceptors.response.use(void 0, (data) => {
  954. log.error("拦截器-请求错误", data);
  955. if (data.type === "onabort") {
  956. Qmsg.warning("请求取消", { consoleLogContent: true });
  957. } else if (data.type === "onerror") {
  958. Qmsg.error("请求异常", { consoleLogContent: true });
  959. } else if (data.type === "ontimeout") {
  960. Qmsg.error("请求超时", { consoleLogContent: true });
  961. } else {
  962. Qmsg.error("其它错误", { consoleLogContent: true });
  963. }
  964. return data;
  965. });
  966. ({
  967. Object: {
  968. defineProperty: _unsafeWindow.Object.defineProperty
  969. },
  970. Function: {
  971. apply: _unsafeWindow.Function.prototype.apply,
  972. call: _unsafeWindow.Function.prototype.call
  973. },
  974. Element: {
  975. appendChild: _unsafeWindow.Element.prototype.appendChild
  976. },
  977. setTimeout: _unsafeWindow.setTimeout
  978. });
  979. utils.addStyle.bind(utils);
  980. document.querySelector.bind(document);
  981. document.querySelectorAll.bind(document);
  982. const cookieManager = new utils.GM_Cookie();
  983. const PanelContent = {
  984. $data: {
  985. /**
  986. * @private
  987. */
  988. __contentConfig: null,
  989. get contentConfig() {
  990. if (this.__contentConfig == null) {
  991. this.__contentConfig = new utils.Dictionary();
  992. }
  993. return this.__contentConfig;
  994. }
  995. },
  996. /**
  997. * 设置所有配置项,用于初始化默认的值
  998. *
  999. * 如果是第一组添加的话,那么它默认就是设置菜单打开的配置
  1000. * @param configList 配置项
  1001. */
  1002. addContentConfig(configList) {
  1003. if (!Array.isArray(configList)) {
  1004. configList = [configList];
  1005. }
  1006. let index = this.$data.contentConfig.keys().length;
  1007. this.$data.contentConfig.set(index, configList);
  1008. },
  1009. /**
  1010. * 获取所有的配置内容,用于初始化默认的值
  1011. */
  1012. getAllContentConfig() {
  1013. return this.$data.contentConfig.values().flat();
  1014. },
  1015. /**
  1016. * 获取配置内容
  1017. * @param index 配置索引
  1018. */
  1019. getConfig(index = 0) {
  1020. return this.$data.contentConfig.get(index) ?? [];
  1021. },
  1022. /**
  1023. * 获取默认左侧底部的配置项
  1024. */
  1025. getDefaultBottomContentConfig() {
  1026. return [
  1027. {
  1028. id: "script-version",
  1029. title: `版本:${_GM_info?.script?.version || "未知"}`,
  1030. isBottom: true,
  1031. forms: [],
  1032. clickFirstCallback(event, rightHeaderElement, rightContainerElement) {
  1033. let supportURL = _GM_info?.script?.supportURL || _GM_info?.script?.namespace;
  1034. if (typeof supportURL === "string" && utils.isNotNull(supportURL)) {
  1035. window.open(supportURL, "_blank");
  1036. }
  1037. return false;
  1038. }
  1039. }
  1040. ];
  1041. }
  1042. };
  1043. let applyObjectThis = (obj) => {
  1044. if (typeof obj === "object" && obj != null || typeof obj === "function") {
  1045. Object.keys(obj).forEach((key) => {
  1046. if (typeof obj[key] === "function") {
  1047. obj[key] = obj[key].bind(obj);
  1048. }
  1049. });
  1050. }
  1051. };
  1052. const __GM_cookie__ = _GM_cookie;
  1053. applyObjectThis(__GM_cookie__);
  1054. applyObjectThis(cookieManager);
  1055. const CookieManager = {
  1056. get cookieManagerApiName() {
  1057. let managerApi = Panel.getValue(
  1058. "cookie-manager-api",
  1059. "document.cookie"
  1060. );
  1061. return managerApi;
  1062. },
  1063. get cookieManager() {
  1064. if (this.cookieManagerApiName === "GM_cookie") {
  1065. return {
  1066. list(options, callback) {
  1067. __GM_cookie__.list(options, (result) => {
  1068. callback(result);
  1069. });
  1070. },
  1071. set(cookieInfo, callback) {
  1072. __GM_cookie__.set(
  1073. cookieInfo,
  1074. (result) => {
  1075. callback(result);
  1076. }
  1077. );
  1078. },
  1079. delete(cookieInfo, callback) {
  1080. __GM_cookie__.delete(cookieInfo, (result) => {
  1081. callback(result);
  1082. });
  1083. }
  1084. };
  1085. } else if (this.cookieManagerApiName === "GM.cookie") {
  1086. return {
  1087. list(options, callback) {
  1088. _GM.cookie.list().then((result) => {
  1089. callback(result);
  1090. });
  1091. },
  1092. set(cookieInfo, callback) {
  1093. _GM.cookie.set(
  1094. cookieInfo
  1095. ).then((result) => {
  1096. callback(result ?? null);
  1097. }).catch((reason) => {
  1098. callback(reason);
  1099. });
  1100. },
  1101. delete(cookieInfo, callback) {
  1102. _GM.cookie.delete(cookieInfo).then((result) => {
  1103. callback(result ?? null);
  1104. }).catch((reason) => {
  1105. callback(reason);
  1106. });
  1107. }
  1108. };
  1109. } else if (this.cookieManagerApiName === "cookieStore") {
  1110. let cookieStore = _unsafeWindow.cookieStore;
  1111. return {
  1112. list(options, callback) {
  1113. cookieStore.getAll().then((result) => {
  1114. callback(result);
  1115. }).catch((reason) => {
  1116. log.error(reason);
  1117. Qmsg.error(reason.toString());
  1118. });
  1119. },
  1120. set(cookieInfo, callback) {
  1121. cookieStore.set(cookieInfo).then(() => {
  1122. callback();
  1123. }).catch((reason) => {
  1124. callback(reason);
  1125. });
  1126. },
  1127. delete(cookieInfo, callback) {
  1128. cookieStore.delete(cookieInfo).then((result) => {
  1129. callback();
  1130. }).catch((reason) => {
  1131. callback(reason);
  1132. });
  1133. }
  1134. };
  1135. } else {
  1136. return cookieManager;
  1137. }
  1138. },
  1139. /**
  1140. * 查询所有Cookie
  1141. */
  1142. queryAllCookie() {
  1143. return new Promise(
  1144. (resolve, reject) => {
  1145. try {
  1146. this.cookieManager.list({}, (cookieListResult) => {
  1147. let __cookieListResult__ = cookieListResult || [];
  1148. __cookieListResult__ = __cookieListResult__.sort(
  1149. (a, b) => a.name.localeCompare(b.name)
  1150. );
  1151. resolve(__cookieListResult__);
  1152. });
  1153. } catch (error) {
  1154. log.error(error);
  1155. Qmsg.error(error.toString());
  1156. reject(error);
  1157. }
  1158. }
  1159. );
  1160. },
  1161. /**
  1162. * 清除所有Cookie
  1163. */
  1164. deleteAllCookie() {
  1165. return new Promise((resolve, reject) => {
  1166. try {
  1167. this.cookieManager.list({}, async (cookieListResult) => {
  1168. const __cookieListResult__ = cookieListResult || [];
  1169. const result = {
  1170. success: 0,
  1171. error: 0
  1172. };
  1173. for (let index = 0; index < __cookieListResult__.length; index++) {
  1174. const cookieListItem = __cookieListResult__[index];
  1175. let deleteError = await new Promise((deleteResolve) => {
  1176. this.deleteCookie(cookieListItem).then((deleteResult) => {
  1177. deleteResolve(deleteResult);
  1178. });
  1179. });
  1180. if (deleteError) {
  1181. result.error++;
  1182. } else {
  1183. result.success++;
  1184. }
  1185. }
  1186. resolve(result);
  1187. });
  1188. } catch (error) {
  1189. log.error(error);
  1190. Qmsg.error(error.toString());
  1191. reject(error);
  1192. }
  1193. });
  1194. },
  1195. /**
  1196. * 添加Cookie
  1197. */
  1198. addCookie(cookieInfo) {
  1199. return new Promise((resolve, reject) => {
  1200. try {
  1201. Reflect.deleteProperty(cookieInfo, "hostOnly");
  1202. CookieManager.cookieManager.set(
  1203. cookieInfo,
  1204. (error) => {
  1205. if (false) ;
  1206. resolve(error);
  1207. }
  1208. );
  1209. } catch (error) {
  1210. log.error(error);
  1211. Qmsg.error(error.toString());
  1212. reject(error);
  1213. }
  1214. });
  1215. },
  1216. /**
  1217. * 删除Cookie
  1218. */
  1219. deleteCookie(cookieInfo) {
  1220. return new Promise((resolve, reject) => {
  1221. try {
  1222. CookieManager.cookieManager.delete(
  1223. cookieInfo,
  1224. (error) => {
  1225. if (false) ;
  1226. resolve(error);
  1227. }
  1228. );
  1229. } catch (error) {
  1230. log.error(error);
  1231. Qmsg.error(error.toString());
  1232. reject(error);
  1233. }
  1234. });
  1235. },
  1236. /**
  1237. * 更新Cookie
  1238. */
  1239. updateCookie(cookieInfo) {
  1240. return new Promise(
  1241. async (resolve, reject) => {
  1242. let result;
  1243. try {
  1244. let deleteError = await CookieManager.deleteCookie(cookieInfo);
  1245. if (deleteError) {
  1246. throw new TypeError(deleteError.toString());
  1247. }
  1248. let addError = await CookieManager.addCookie(cookieInfo);
  1249. if (addError) {
  1250. throw new TypeError(addError.toString());
  1251. }
  1252. } catch (error) {
  1253. result = error;
  1254. } finally {
  1255. resolve(result);
  1256. }
  1257. }
  1258. );
  1259. }
  1260. };
  1261. const PanelComponents = {
  1262. $data: {
  1263. __storeApiFn: null,
  1264. get storeApiValue() {
  1265. if (!this.__storeApiFn) {
  1266. this.__storeApiFn = new Utils.Dictionary();
  1267. }
  1268. return this.__storeApiFn;
  1269. }
  1270. },
  1271. /**
  1272. * 获取自定义的存储接口
  1273. * @param type 组件类型
  1274. */
  1275. getStorageApi(type) {
  1276. if (!this.hasStorageApi(type)) {
  1277. return;
  1278. }
  1279. return this.$data.storeApiValue.get(type);
  1280. },
  1281. /**
  1282. * 判断是否存在自定义的存储接口
  1283. * @param type 组件类型
  1284. */
  1285. hasStorageApi(type) {
  1286. return this.$data.storeApiValue.has(type);
  1287. },
  1288. /**
  1289. * 设置自定义的存储接口
  1290. * @param type 组件类型
  1291. * @param storageApiValue 存储接口
  1292. */
  1293. setStorageApi(type, storageApiValue) {
  1294. this.$data.storeApiValue.set(type, storageApiValue);
  1295. },
  1296. /**
  1297. * 初始化组件的存储接口属性
  1298. *
  1299. * @param type 组件类型
  1300. * @param config 组件配置,必须包含prop属性
  1301. * @param storageApiValue 存储接口
  1302. */
  1303. initComponentsStorageApi(type, config, storageApiValue) {
  1304. let propsStorageApi;
  1305. if (this.hasStorageApi(type)) {
  1306. propsStorageApi = this.getStorageApi(type);
  1307. } else {
  1308. propsStorageApi = storageApiValue;
  1309. }
  1310. this.setComponentsStorageApiProperty(config, propsStorageApi);
  1311. },
  1312. /**
  1313. * 设置组件的存储接口属性
  1314. * @param config 组件配置,必须包含prop属性
  1315. * @param storageApiValue 存储接口
  1316. */
  1317. setComponentsStorageApiProperty(config, storageApiValue) {
  1318. Reflect.set(config.props, PROPS_STORAGE_API, storageApiValue);
  1319. }
  1320. };
  1321. const UISwitch = function(text, key, defaultValue, clickCallback, description, afterAddToUListCallBack) {
  1322. let result = {
  1323. text,
  1324. type: "switch",
  1325. description,
  1326. attributes: {},
  1327. props: {},
  1328. getValue() {
  1329. let storageApiValue = this.props[PROPS_STORAGE_API];
  1330. return Boolean(storageApiValue.get(key, defaultValue));
  1331. },
  1332. callback(event, __value) {
  1333. let value = Boolean(__value);
  1334. log.success(`${value ? "开启" : "关闭"} ${text}`);
  1335. if (typeof clickCallback === "function") {
  1336. let result2 = clickCallback(event, value);
  1337. if (result2) {
  1338. return;
  1339. }
  1340. }
  1341. let storageApiValue = this.props[PROPS_STORAGE_API];
  1342. storageApiValue.set(key, value);
  1343. },
  1344. afterAddToUListCallBack
  1345. };
  1346. Reflect.set(result.attributes, ATTRIBUTE_KEY, key);
  1347. Reflect.set(result.attributes, ATTRIBUTE_DEFAULT_VALUE, defaultValue);
  1348. PanelComponents.initComponentsStorageApi(
  1349. "switch",
  1350. result,
  1351. {
  1352. get(key2, defaultValue2) {
  1353. return Panel.getValue(key2, defaultValue2);
  1354. },
  1355. set(key2, value) {
  1356. Panel.setValue(key2, value);
  1357. }
  1358. }
  1359. );
  1360. return result;
  1361. };
  1362. const CookieInfoTransform = {
  1363. /**
  1364. * 对编辑前的cookie信息进行值转换
  1365. */
  1366. beforeEdit(cookieInfo) {
  1367. const cookieManagerApiName = CookieManager.cookieManagerApiName;
  1368. if (cookieManagerApiName === "cookieStore") {
  1369. if (typeof cookieInfo.expires === "number") {
  1370. cookieInfo.expirationDate = cookieInfo.expires;
  1371. }
  1372. } else if (cookieManagerApiName === "GM_cookie" || cookieManagerApiName === "GM.cookie") {
  1373. if (typeof cookieInfo.expirationDate === "number") {
  1374. cookieInfo.expirationDate = cookieInfo.expirationDate * 1e3;
  1375. }
  1376. }
  1377. return cookieInfo;
  1378. },
  1379. /**
  1380. * 对编辑后的cookie信息进行值转换
  1381. */
  1382. afterEdit(cookieInfo) {
  1383. const cookieManagerApiName = CookieManager.cookieManagerApiName;
  1384. if (cookieManagerApiName === "document.cookie") {
  1385. cookieInfo.domain = "";
  1386. } else if (cookieManagerApiName === "cookieStore") {
  1387. if (typeof cookieInfo.expirationDate === "number") {
  1388. cookieInfo.expires = cookieInfo.expirationDate;
  1389. }
  1390. } else if (cookieManagerApiName === "GM_cookie" || cookieManagerApiName === "GM.cookie") {
  1391. if (typeof cookieInfo.expirationDate === "number") {
  1392. cookieInfo.expirationDate = Math.floor(
  1393. cookieInfo.expirationDate / 1e3
  1394. );
  1395. }
  1396. }
  1397. return cookieInfo;
  1398. }
  1399. };
  1400. let edit_ui_input = (text, getValue, setValue, disabled) => {
  1401. let config = {
  1402. text,
  1403. type: "input",
  1404. isNumber: false,
  1405. isPassword: false,
  1406. props: {},
  1407. attributes: {},
  1408. description: "",
  1409. getValue() {
  1410. return getValue();
  1411. },
  1412. callback(event, value) {
  1413. setValue(value);
  1414. },
  1415. placeholder: "",
  1416. disabled: Boolean(disabled)
  1417. };
  1418. return config;
  1419. };
  1420. let edit_ui_select = (text, data, getValue, setValue, disabled) => {
  1421. let config = {
  1422. text,
  1423. type: "select",
  1424. description: "",
  1425. attributes: {},
  1426. props: {},
  1427. getValue() {
  1428. return getValue();
  1429. },
  1430. callback(event, isSelectedValue, isSelectedText) {
  1431. let value = isSelectedValue;
  1432. setValue(value);
  1433. },
  1434. data: typeof data === "function" ? data() : data,
  1435. disabled: Boolean(disabled)
  1436. };
  1437. return config;
  1438. };
  1439. const CookieManagerEditView = {
  1440. init() {
  1441. },
  1442. /**
  1443. * 显示视图
  1444. * @param cookieInfo 需要编辑的cookie
  1445. * @param dialogCloseCallBack 弹窗关闭的回调
  1446. */
  1447. showView(__cookieInfo__, dialogCloseCallBack) {
  1448. let isEdit = !!__cookieInfo__;
  1449. let cookieInfo = utils.assign(
  1450. {
  1451. name: "",
  1452. value: "",
  1453. domain: window.location.hostname,
  1454. path: "/",
  1455. secure: false,
  1456. hostOnly: false,
  1457. httpOnly: false,
  1458. sameSite: "lax",
  1459. expirationDate: Date.now() + 60 * 60 * 24 * 30 * 1e3
  1460. },
  1461. __cookieInfo__,
  1462. true
  1463. );
  1464. cookieInfo = CookieInfoTransform.beforeEdit(cookieInfo);
  1465. let $dialog = __pops.confirm({
  1466. title: {
  1467. text: isEdit ? "编辑Cookie" : "添加Cookie",
  1468. position: "center"
  1469. },
  1470. content: {
  1471. text: "",
  1472. html: true
  1473. },
  1474. drag: true,
  1475. btn: {
  1476. position: "center",
  1477. ok: {
  1478. text: isEdit ? "编辑" : "添加",
  1479. async callback(eventDetails, event) {
  1480. let valid = CookieManagerEditView.validCookieInfo(cookieInfo);
  1481. if (!valid) {
  1482. return;
  1483. }
  1484. cookieInfo.value = encodeURIComponent(cookieInfo.value);
  1485. cookieInfo = CookieInfoTransform.afterEdit(cookieInfo);
  1486. if (isEdit) {
  1487. let result = await CookieManager.updateCookie(cookieInfo);
  1488. if (result) {
  1489. Qmsg.error(result.toString());
  1490. } else {
  1491. Qmsg.success("修改成功");
  1492. eventDetails.close();
  1493. }
  1494. } else {
  1495. let result = await CookieManager.addCookie(cookieInfo);
  1496. if (result) {
  1497. Qmsg.error(result.toString());
  1498. } else {
  1499. Qmsg.success("添加成功");
  1500. eventDetails.close();
  1501. }
  1502. }
  1503. if (typeof dialogCloseCallBack === "function") {
  1504. dialogCloseCallBack(cookieInfo);
  1505. }
  1506. }
  1507. },
  1508. cancel: {
  1509. text: "取消"
  1510. }
  1511. },
  1512. mask: {
  1513. enable: true
  1514. },
  1515. width: window.innerWidth > 350 ? "350px" : "80vw",
  1516. height: PanelUISize.setting.height,
  1517. style: (
  1518. /*css*/
  1519. `
  1520. ${__pops.config.cssText.panelCSS}
  1521.  
  1522. .pops-panel-input input:disabled{
  1523. color: #b4b4b4;
  1524. }
  1525. .pops-confirm-content{
  1526. padding: 10px;
  1527. }
  1528. .pops-confirm-content li{
  1529. display: flex;
  1530. flex-direction: column;
  1531. }
  1532. .pops-panel-item-left-text{
  1533. margin-bottom: 5px;
  1534. }
  1535. .pops-panel-input.pops-input-disabled{
  1536. border: 1px solid #dcdfe6;
  1537. }
  1538. #cookie-item-property-expires{
  1539. border: 1px solid rgb(184, 184, 184, var(--pops-bd-opacity));
  1540. border-radius: 4px;
  1541. background-color: #ffffff;
  1542. width: 100%;
  1543. height: 32px;
  1544. padding: 0px 8px;
  1545. }
  1546. #cookie-item-property-expires:hover{
  1547. box-shadow: 0 0 0 1px #c0c4cc inset;
  1548. }
  1549. #cookie-item-property-expires:focus,
  1550. #cookie-item-property-expires:focus-within{
  1551. outline: 0;
  1552. border: 1px solid #409eff;
  1553. border-radius: 4px;
  1554. box-shadow: none;
  1555. }
  1556. `
  1557. )
  1558. });
  1559. let $editContent = $dialog.$shadowRoot.querySelector(
  1560. ".pops-confirm-content"
  1561. );
  1562. let panelHandlerComponents = __pops.config.PanelHandlerComponents();
  1563. let $name = panelHandlerComponents.createSectionContainerItem_input(
  1564. edit_ui_input(
  1565. "name",
  1566. () => cookieInfo.name,
  1567. (value) => cookieInfo.name = value,
  1568. isEdit
  1569. )
  1570. );
  1571. let $value = panelHandlerComponents.createSectionContainerItem_input(
  1572. edit_ui_input(
  1573. "value",
  1574. () => cookieInfo.value,
  1575. (value) => cookieInfo.value = value
  1576. )
  1577. );
  1578. let $domain = panelHandlerComponents.createSectionContainerItem_input(
  1579. edit_ui_input(
  1580. "domain",
  1581. () => cookieInfo.domain,
  1582. (value) => cookieInfo.domain = value
  1583. )
  1584. );
  1585. let $path = panelHandlerComponents.createSectionContainerItem_input(
  1586. edit_ui_input(
  1587. "path",
  1588. () => cookieInfo.path,
  1589. (value) => cookieInfo.path = value
  1590. )
  1591. );
  1592. let $expires;
  1593. if (cookieInfo.session) {
  1594. $expires = panelHandlerComponents.createSectionContainerItem_input(
  1595. edit_ui_input(
  1596. "expires",
  1597. () => "会话",
  1598. (value) => {
  1599. },
  1600. true
  1601. )
  1602. );
  1603. } else {
  1604. $expires = panelHandlerComponents.createSectionContainerItem_own({
  1605. type: "own",
  1606. getLiElementCallBack: function(liElement) {
  1607. let $li = domUtils.createElement("li", {
  1608. innerHTML: (
  1609. /*html*/
  1610. `
  1611. <div class="pops-panel-item-left-text">
  1612. <p class="pops-panel-item-left-main-text">expires</p>
  1613. </div>
  1614. <div class="pops-panel-item-right-wrapper">
  1615. <input type="datetime-local" id="cookie-item-property-expires">
  1616. </div>
  1617. `
  1618. )
  1619. });
  1620. let $dateTime = $li.querySelector(
  1621. "#cookie-item-property-expires"
  1622. );
  1623. $dateTime.valueAsNumber = cookieInfo.expirationDate;
  1624. domUtils.on(
  1625. $dateTime,
  1626. ["change", "input", "propertychange"],
  1627. (event) => {
  1628. utils.preventEvent(event);
  1629. cookieInfo.expirationDate = $dateTime.valueAsNumber;
  1630. }
  1631. );
  1632. return $li;
  1633. }
  1634. });
  1635. }
  1636. let $httpOnly = panelHandlerComponents.createSectionContainerItem_select(
  1637. edit_ui_select(
  1638. "httpOnly",
  1639. [
  1640. {
  1641. text: "true",
  1642. value: true
  1643. },
  1644. {
  1645. text: "false",
  1646. value: false
  1647. }
  1648. ],
  1649. () => cookieInfo.httpOnly,
  1650. (value) => cookieInfo.httpOnly = value
  1651. )
  1652. );
  1653. let $secure = panelHandlerComponents.createSectionContainerItem_select(
  1654. edit_ui_select(
  1655. "secure",
  1656. [
  1657. {
  1658. text: "true",
  1659. value: true
  1660. },
  1661. {
  1662. text: "false",
  1663. value: false
  1664. }
  1665. ],
  1666. () => cookieInfo.secure,
  1667. (value) => cookieInfo.secure = value
  1668. )
  1669. );
  1670. let sameSiteData = [
  1671. {
  1672. text: "no_restriction",
  1673. value: "no_restriction"
  1674. },
  1675. {
  1676. text: "lax",
  1677. value: "lax"
  1678. },
  1679. {
  1680. text: "strict",
  1681. value: "strict"
  1682. },
  1683. {
  1684. text: "unspecified",
  1685. value: "unspecified"
  1686. }
  1687. ];
  1688. if (CookieManager.cookieManagerApiName === "cookieStore") {
  1689. sameSiteData = [
  1690. {
  1691. text: "lax",
  1692. value: "lax"
  1693. },
  1694. {
  1695. text: "strict",
  1696. value: "strict"
  1697. },
  1698. {
  1699. text: "none",
  1700. value: "none"
  1701. }
  1702. ];
  1703. }
  1704. let $sameSite = panelHandlerComponents.createSectionContainerItem_select(
  1705. edit_ui_select(
  1706. "sameSite",
  1707. sameSiteData,
  1708. () => cookieInfo.sameSite,
  1709. (value) => cookieInfo.sameSite = value
  1710. )
  1711. );
  1712. domUtils.append($editContent, [$name, $value]);
  1713. if (CookieManager.cookieManagerApiName === "GM_cookie" || CookieManager.cookieManagerApiName === "GM.cookie") {
  1714. domUtils.append($editContent, [
  1715. $domain,
  1716. $path,
  1717. $expires,
  1718. $httpOnly,
  1719. $secure,
  1720. $sameSite
  1721. ]);
  1722. } else if (CookieManager.cookieManagerApiName === "cookieStore") {
  1723. domUtils.append($editContent, [$domain, $path, $expires, $sameSite]);
  1724. }
  1725. },
  1726. /**
  1727. * Cookie信息校验
  1728. */
  1729. validCookieInfo(cookieInfo) {
  1730. if (cookieInfo.name == null || cookieInfo.name == "") {
  1731. Qmsg.error("name不能为空");
  1732. return false;
  1733. }
  1734. if (cookieInfo.domain == null || cookieInfo.domain == "") {
  1735. Qmsg.error("domain不能为空");
  1736. return false;
  1737. }
  1738. if (cookieInfo.path == null || cookieInfo.path == "") {
  1739. Qmsg.error("path不能为空");
  1740. return false;
  1741. }
  1742. return true;
  1743. }
  1744. };
  1745. const UISelect = function(text, key, defaultValue, data, changeCallback, description) {
  1746. let selectData = [];
  1747. if (typeof data === "function") {
  1748. selectData = data();
  1749. } else {
  1750. selectData = data;
  1751. }
  1752. let result = {
  1753. text,
  1754. type: "select",
  1755. description,
  1756. attributes: {},
  1757. props: {},
  1758. getValue() {
  1759. let storageApiValue = this.props[PROPS_STORAGE_API];
  1760. return storageApiValue.get(key, defaultValue);
  1761. },
  1762. callback(event, isSelectedValue, isSelectedText) {
  1763. let value = isSelectedValue;
  1764. log.info(`选择:${isSelectedText}`);
  1765. if (typeof changeCallback === "function") {
  1766. let result2 = changeCallback(event, value, isSelectedText);
  1767. if (result2) {
  1768. return;
  1769. }
  1770. }
  1771. let storageApiValue = this.props[PROPS_STORAGE_API];
  1772. storageApiValue.set(key, value);
  1773. },
  1774. data: selectData
  1775. };
  1776. Reflect.set(result.attributes, ATTRIBUTE_KEY, key);
  1777. Reflect.set(result.attributes, ATTRIBUTE_DEFAULT_VALUE, defaultValue);
  1778. PanelComponents.initComponentsStorageApi(
  1779. "select",
  1780. result,
  1781. {
  1782. get(key2, defaultValue2) {
  1783. return Panel.getValue(key2, defaultValue2);
  1784. },
  1785. set(key2, value) {
  1786. Panel.setValue(key2, value);
  1787. }
  1788. }
  1789. );
  1790. return result;
  1791. };
  1792. const UIInput = function(text, key, defaultValue, description, changeCallback, placeholder = "", isNumber, isPassword, afterAddToUListCallBack) {
  1793. let result = {
  1794. text,
  1795. type: "input",
  1796. isNumber: Boolean(isNumber),
  1797. isPassword: Boolean(isPassword),
  1798. attributes: {},
  1799. props: {},
  1800. description,
  1801. afterAddToUListCallBack,
  1802. getValue() {
  1803. let storageApiValue = this.props[PROPS_STORAGE_API];
  1804. return storageApiValue.get(key, defaultValue);
  1805. },
  1806. callback(event, value, valueAsNumber) {
  1807. let storageApiValue = this.props[PROPS_STORAGE_API];
  1808. storageApiValue.set(key, value);
  1809. },
  1810. placeholder
  1811. };
  1812. Reflect.set(result.attributes, ATTRIBUTE_KEY, key);
  1813. Reflect.set(result.attributes, ATTRIBUTE_DEFAULT_VALUE, defaultValue);
  1814. PanelComponents.initComponentsStorageApi(
  1815. "input",
  1816. result,
  1817. {
  1818. get(key2, defaultValue2) {
  1819. return Panel.getValue(key2, defaultValue2);
  1820. },
  1821. set(key2, value) {
  1822. Panel.setValue(key2, value);
  1823. }
  1824. }
  1825. );
  1826. return result;
  1827. };
  1828. const UITextArea = function(text, key, defaultValue, description, changeCallback, placeholder = "", disabled) {
  1829. let result = {
  1830. text,
  1831. type: "textarea",
  1832. attributes: {},
  1833. props: {},
  1834. description,
  1835. placeholder,
  1836. disabled,
  1837. getValue() {
  1838. let storageApiValue = this.props[PROPS_STORAGE_API];
  1839. let value = storageApiValue.get(key, defaultValue);
  1840. if (Array.isArray(value)) {
  1841. return value.join("\n");
  1842. }
  1843. return value;
  1844. },
  1845. callback(event, value) {
  1846. let storageApiValue = this.props[PROPS_STORAGE_API];
  1847. storageApiValue.set(key, value);
  1848. }
  1849. };
  1850. Reflect.set(result.attributes, ATTRIBUTE_KEY, key);
  1851. Reflect.set(result.attributes, ATTRIBUTE_DEFAULT_VALUE, defaultValue);
  1852. PanelComponents.initComponentsStorageApi(
  1853. "switch",
  1854. result,
  1855. {
  1856. get(key2, defaultValue2) {
  1857. return Panel.getValue(key2, defaultValue2);
  1858. },
  1859. set(key2, value) {
  1860. Panel.setValue(key2, value);
  1861. }
  1862. }
  1863. );
  1864. return result;
  1865. };
  1866. class RuleEditView {
  1867. option;
  1868. constructor(option) {
  1869. this.option = option;
  1870. }
  1871. /**
  1872. * 显示视图
  1873. */
  1874. async showView() {
  1875. let $dialog = __pops.confirm({
  1876. title: {
  1877. text: this.option.title,
  1878. position: "center"
  1879. },
  1880. content: {
  1881. text: (
  1882. /*html*/
  1883. `
  1884. <form class="rule-form-container" onsubmit="return false">
  1885. <ul class="rule-form-ulist"></ul>
  1886. <input type="submit" style="display: none;" />
  1887. </form>
  1888. `
  1889. ),
  1890. html: true
  1891. },
  1892. btn: utils.assign(
  1893. {
  1894. ok: {
  1895. callback: async () => {
  1896. await submitSaveOption();
  1897. }
  1898. }
  1899. },
  1900. this.option.btn || {},
  1901. true
  1902. ),
  1903. drag: true,
  1904. mask: {
  1905. enable: true
  1906. },
  1907. style: (
  1908. /*css*/
  1909. `
  1910. ${__pops.config.cssText.panelCSS}
  1911. .rule-form-container {
  1912. }
  1913. .rule-form-container li{
  1914. display: flex;
  1915. align-items: center;
  1916. justify-content: space-between;
  1917. padding: 5px 20px;
  1918. gap: 10px;
  1919. }
  1920. .rule-form-ulist-dynamic{
  1921. --button-margin-top: 0px;
  1922. --button-margin-right: 0px;
  1923. --button-margin-bottom: 0px;
  1924. --button-margin-left: 0px;
  1925. display: flex;
  1926. flex-direction: column;
  1927. align-items: flex-start;
  1928. padding: 5px 0px 5px 20px;
  1929. }
  1930. .rule-form-ulist-dynamic__inner{
  1931. width: 100%;
  1932. }
  1933. .rule-form-ulist-dynamic__inner-container{
  1934. display: flex;
  1935. align-items: center;
  1936. }
  1937. .dynamic-forms{
  1938. width: 100%;
  1939. }
  1940. .pops-panel-item-left-main-text{
  1941. max-width: 150px;
  1942. }
  1943. .pops-panel-item-right-text{
  1944. padding-left: 30px;
  1945. }
  1946. .pops-panel-item-right-text,
  1947. .pops-panel-item-right-main-text{
  1948. text-overflow: ellipsis;
  1949. overflow: hidden;
  1950. white-space: nowrap;
  1951. }
  1952. .pops-panel-item-left-desc-text{
  1953. line-height: normal;
  1954. margin-top: 6px;
  1955. font-size: 0.8em;
  1956. color: rgb(108, 108, 108);
  1957. }
  1958.  
  1959. ${this.option?.style ?? ""}
  1960. `
  1961. ),
  1962. width: typeof this.option.width === "function" ? this.option.width() : window.innerWidth > 500 ? "500px" : "88vw",
  1963. height: typeof this.option.height === "function" ? this.option.height() : window.innerHeight > 500 ? "500px" : "80vh"
  1964. });
  1965. let $form = $dialog.$shadowRoot.querySelector(
  1966. ".rule-form-container"
  1967. );
  1968. $dialog.$shadowRoot.querySelector(
  1969. "input[type=submit]"
  1970. );
  1971. let $ulist = $dialog.$shadowRoot.querySelector(".rule-form-ulist");
  1972. let view = await this.option.getView(await this.option.data());
  1973. $ulist.appendChild(view);
  1974. const submitSaveOption = async () => {
  1975. let result = await this.option.onsubmit($form, await this.option.data());
  1976. if (!result.success) {
  1977. return;
  1978. }
  1979. $dialog.close();
  1980. await this.option.dialogCloseCallBack(true);
  1981. };
  1982. }
  1983. }
  1984. class RuleFilterView {
  1985. option;
  1986. constructor(option) {
  1987. this.option = option;
  1988. }
  1989. showView() {
  1990. let $alert = __pops.alert({
  1991. title: {
  1992. text: this.option.title,
  1993. position: "center"
  1994. },
  1995. content: {
  1996. text: (
  1997. /*html*/
  1998. `
  1999. <div class="filter-container"></div>
  2000. `
  2001. )
  2002. },
  2003. btn: {
  2004. ok: {
  2005. text: "关闭",
  2006. type: "default"
  2007. }
  2008. },
  2009. drag: true,
  2010. mask: {
  2011. enable: true
  2012. },
  2013. width: window.innerWidth > 500 ? "350px" : "80vw",
  2014. height: window.innerHeight > 500 ? "300px" : "70vh",
  2015. style: (
  2016. /*css*/
  2017. `
  2018. .filter-container{
  2019. height: 100%;
  2020. display: flex;
  2021. flex-direction: column;
  2022. gap: 20px;
  2023. }
  2024. .filter-container button{
  2025. text-wrap: wrap;
  2026. padding: 8px;
  2027. height: auto;
  2028. text-align: left;
  2029. }
  2030. `
  2031. )
  2032. });
  2033. let $filterContainer = $alert.$shadowRoot.querySelector(".filter-container");
  2034. let $fragment = document.createDocumentFragment();
  2035. this.option.filterOption.forEach((filterOption) => {
  2036. let $button = document.createElement("button");
  2037. $button.innerText = filterOption.name;
  2038. let execFilterAndCloseDialog = async () => {
  2039. let allRuleInfo = await this.option.getAllRuleInfo();
  2040. allRuleInfo.forEach(async (ruleInfo) => {
  2041. let filterResult = await filterOption.filterCallBack(ruleInfo.data);
  2042. if (!filterResult) {
  2043. domUtils.hide(ruleInfo.$el, false);
  2044. } else {
  2045. domUtils.show(ruleInfo.$el, false);
  2046. }
  2047. });
  2048. if (typeof this.option.execFilterCallBack === "function") {
  2049. await this.option.execFilterCallBack();
  2050. }
  2051. $alert.close();
  2052. };
  2053. domUtils.on($button, "click", async (event) => {
  2054. utils.preventEvent(event);
  2055. if (typeof filterOption.callback === "function") {
  2056. let result = await filterOption.callback(
  2057. event,
  2058. execFilterAndCloseDialog
  2059. );
  2060. if (!result) {
  2061. return;
  2062. }
  2063. }
  2064. await execFilterAndCloseDialog();
  2065. });
  2066. $fragment.appendChild($button);
  2067. });
  2068. $filterContainer.appendChild($fragment);
  2069. }
  2070. }
  2071. class RuleView {
  2072. option;
  2073. constructor(option) {
  2074. this.option = option;
  2075. }
  2076. /**
  2077. * 显示视图
  2078. * @param filterCallBack 返回值为false隐藏,true则不隐藏(不处理)
  2079. */
  2080. async showView(filterCallBack) {
  2081. let $popsConfirm = __pops.confirm({
  2082. title: {
  2083. text: this.option.title,
  2084. position: "center"
  2085. },
  2086. content: {
  2087. text: (
  2088. /*html*/
  2089. `
  2090. <div class="rule-view-container">
  2091. </div>
  2092. `
  2093. ),
  2094. html: true
  2095. },
  2096. btn: {
  2097. merge: true,
  2098. reverse: false,
  2099. position: "space-between",
  2100. ok: {
  2101. enable: this.option?.bottomControls?.add?.enable || true,
  2102. type: "primary",
  2103. text: "添加",
  2104. callback: async (event) => {
  2105. this.showEditView(
  2106. false,
  2107. await this.option.getAddData(),
  2108. $popsConfirm.$shadowRoot
  2109. );
  2110. }
  2111. },
  2112. close: {
  2113. enable: true,
  2114. callback(event) {
  2115. $popsConfirm.close();
  2116. }
  2117. },
  2118. cancel: {
  2119. enable: this.option?.bottomControls?.filter?.enable || false,
  2120. type: "default",
  2121. text: "过滤",
  2122. callback: (details, event) => {
  2123. if (typeof this.option?.bottomControls?.filter?.callback === "function") {
  2124. this.option.bottomControls.filter.callback();
  2125. }
  2126. let getAllRuleElement = () => {
  2127. return Array.from(
  2128. $popsConfirm.$shadowRoot.querySelectorAll(
  2129. ".rule-view-container .rule-item"
  2130. )
  2131. );
  2132. };
  2133. let $button = event.target.closest(".pops-confirm-btn").querySelector(".pops-confirm-btn-cancel span");
  2134. if (domUtils.text($button).includes("取消")) {
  2135. getAllRuleElement().forEach(($el) => {
  2136. domUtils.show($el, false);
  2137. });
  2138. domUtils.text($button, "过滤");
  2139. } else {
  2140. let ruleFilterView = new RuleFilterView({
  2141. title: this.option.bottomControls?.filter?.title ?? "过滤规则",
  2142. filterOption: this.option.bottomControls?.filter?.option || [],
  2143. execFilterCallBack() {
  2144. domUtils.text($button, "取消过滤");
  2145. },
  2146. getAllRuleInfo: () => {
  2147. return getAllRuleElement().map(($el) => {
  2148. return {
  2149. data: this.parseRuleItemElement($el).data,
  2150. $el
  2151. };
  2152. });
  2153. }
  2154. });
  2155. ruleFilterView.showView();
  2156. }
  2157. }
  2158. },
  2159. other: {
  2160. enable: this.option?.bottomControls?.clear?.enable || true,
  2161. type: "xiaomi-primary",
  2162. text: `清空所有(${(await this.option.data()).length})`,
  2163. callback: (event) => {
  2164. let $askDialog = __pops.confirm({
  2165. title: {
  2166. text: "提示",
  2167. position: "center"
  2168. },
  2169. content: {
  2170. text: "确定清空所有的数据?",
  2171. html: false
  2172. },
  2173. btn: {
  2174. ok: {
  2175. enable: true,
  2176. callback: async (popsEvent) => {
  2177. log.success("清空所有");
  2178. if (typeof this.option?.bottomControls?.clear?.callback === "function") {
  2179. this.option.bottomControls.clear.callback();
  2180. }
  2181. let data = await this.option.data();
  2182. if (data.length) {
  2183. Qmsg.error("清理失败");
  2184. return;
  2185. } else {
  2186. Qmsg.success("清理成功");
  2187. }
  2188. await this.updateDeleteAllBtnText($popsConfirm.$shadowRoot);
  2189. this.clearContent($popsConfirm.$shadowRoot);
  2190. $askDialog.close();
  2191. }
  2192. },
  2193. cancel: {
  2194. text: "取消",
  2195. enable: true
  2196. }
  2197. },
  2198. mask: { enable: true },
  2199. width: "300px",
  2200. height: "200px"
  2201. });
  2202. }
  2203. }
  2204. },
  2205. mask: {
  2206. enable: true
  2207. },
  2208. width: window.innerWidth > 500 ? "500px" : "88vw",
  2209. height: window.innerHeight > 500 ? "500px" : "80vh",
  2210. style: (
  2211. /*css*/
  2212. `
  2213. ${__pops.config.cssText.panelCSS}
  2214. .rule-item{
  2215. display: flex;
  2216. align-items: center;
  2217. line-height: normal;
  2218. font-size: 16px;
  2219. padding: 4px 8px;
  2220. gap: 8px;
  2221. }
  2222. .rule-name{
  2223. flex: 1;
  2224. white-space: nowrap;
  2225. text-overflow: ellipsis;
  2226. overflow: hidden;
  2227. }
  2228. .rule-controls{
  2229. display: flex;
  2230. align-items: center;
  2231. text-overflow: ellipsis;
  2232. overflow: hidden;
  2233. white-space: nowrap;
  2234. gap: 8px;
  2235. padding: 0px;
  2236. }
  2237. .rule-controls-enable{
  2238. }
  2239. .rule-controls-edit{
  2240. }
  2241. .rule-controls-delete{
  2242. }
  2243. .rule-controls-edit,
  2244. .rule-controls-delete{
  2245. width: 16px;
  2246. height: 16px;
  2247. cursor: pointer;
  2248. }
  2249. `
  2250. )
  2251. });
  2252. let allData = await this.option.data();
  2253. let changeButtonText = false;
  2254. for (let index = 0; index < allData.length; index++) {
  2255. let item = allData[index];
  2256. let $ruleItemList = await this.appendRuleItemElement(
  2257. $popsConfirm.$shadowRoot,
  2258. item
  2259. );
  2260. let flag = typeof filterCallBack === "function" ? filterCallBack(item) : true;
  2261. if (!flag) {
  2262. changeButtonText = true;
  2263. $ruleItemList.forEach(($el) => {
  2264. domUtils.hide($el, false);
  2265. });
  2266. }
  2267. }
  2268. if (changeButtonText) {
  2269. let $button = $popsConfirm.$shadowRoot.querySelector(
  2270. ".pops-confirm-btn-cancel span"
  2271. );
  2272. domUtils.text($button, "取消过滤");
  2273. }
  2274. }
  2275. /**
  2276. * 显示编辑视图
  2277. * @param isEdit 是否是编辑状态
  2278. * @param editData 编辑的数据
  2279. * @param $parentShadowRoot (可选)关闭弹窗后对ShadowRoot进行操作
  2280. * @param $editRuleItemElement (可选)关闭弹窗后对规则行进行更新数据
  2281. * @param updateDataCallBack (可选)关闭添加/编辑弹窗的回调(不更新数据)
  2282. * @param submitCallBack (可选)添加/修改提交的回调
  2283. */
  2284. showEditView(isEdit, editData, $parentShadowRoot, $editRuleItemElement, updateDataCallBack, submitCallBack) {
  2285. let dialogCloseCallBack = async (isSubmit) => {
  2286. if (isSubmit) {
  2287. if (typeof submitCallBack === "function") {
  2288. let newData = await this.option.getData(editData);
  2289. submitCallBack(newData);
  2290. }
  2291. } else {
  2292. if (!isEdit) {
  2293. await this.option.deleteData(editData);
  2294. }
  2295. if (typeof updateDataCallBack === "function") {
  2296. let newData = await this.option.getData(editData);
  2297. updateDataCallBack(newData);
  2298. }
  2299. }
  2300. };
  2301. let editView = new RuleEditView({
  2302. title: isEdit ? "编辑" : "添加",
  2303. data: () => {
  2304. return editData;
  2305. },
  2306. dialogCloseCallBack,
  2307. getView: async (data) => {
  2308. return await this.option.itemControls.edit.getView(data, isEdit);
  2309. },
  2310. btn: {
  2311. ok: {
  2312. enable: true,
  2313. text: isEdit ? "修改" : "添加"
  2314. },
  2315. cancel: {
  2316. callback: async (detail, event) => {
  2317. detail.close();
  2318. await dialogCloseCallBack(false);
  2319. }
  2320. },
  2321. close: {
  2322. callback: async (detail, event) => {
  2323. detail.close();
  2324. await dialogCloseCallBack(false);
  2325. }
  2326. }
  2327. },
  2328. onsubmit: async ($form, data) => {
  2329. let result = await this.option.itemControls.edit.onsubmit(
  2330. $form,
  2331. isEdit,
  2332. data
  2333. );
  2334. if (result.success) {
  2335. if (isEdit) {
  2336. Qmsg.success("修改成功");
  2337. $parentShadowRoot && await this.updateRuleItemElement(
  2338. result.data,
  2339. $editRuleItemElement,
  2340. $parentShadowRoot
  2341. );
  2342. } else {
  2343. $parentShadowRoot && await this.appendRuleItemElement(
  2344. $parentShadowRoot,
  2345. result.data
  2346. );
  2347. }
  2348. } else {
  2349. if (isEdit) {
  2350. log.error("修改失败");
  2351. }
  2352. }
  2353. return result;
  2354. },
  2355. style: this.option.itemControls.edit.style,
  2356. width: this.option.itemControls.edit.width,
  2357. height: this.option.itemControls.edit.height
  2358. });
  2359. editView.showView();
  2360. }
  2361. /**
  2362. * 解析弹窗内的各个元素
  2363. */
  2364. parseViewElement($shadowRoot) {
  2365. let $container = $shadowRoot.querySelector(
  2366. ".rule-view-container"
  2367. );
  2368. let $deleteBtn = $shadowRoot.querySelector(
  2369. ".pops-confirm-btn button.pops-confirm-btn-other"
  2370. );
  2371. return {
  2372. /** 容器 */
  2373. $container,
  2374. /** 左下角的清空按钮 */
  2375. $deleteBtn
  2376. };
  2377. }
  2378. /**
  2379. * 解析每一项的元素
  2380. */
  2381. parseRuleItemElement($ruleElement) {
  2382. let $enable = $ruleElement.querySelector(
  2383. ".rule-controls-enable"
  2384. );
  2385. let $enableSwitch = $enable.querySelector(".pops-panel-switch");
  2386. let $enableSwitchInput = $enable.querySelector(
  2387. ".pops-panel-switch__input"
  2388. );
  2389. let $enableSwitchCore = $enable.querySelector(
  2390. ".pops-panel-switch__core"
  2391. );
  2392. let $edit = $ruleElement.querySelector(".rule-controls-edit");
  2393. let $delete = $ruleElement.querySelector(
  2394. ".rule-controls-delete"
  2395. );
  2396. return {
  2397. /** 启用开关 */
  2398. $enable,
  2399. /** 启用开关的container */
  2400. $enableSwitch,
  2401. /** 启用开关的input */
  2402. $enableSwitchInput,
  2403. /** 启用开关的core */
  2404. $enableSwitchCore,
  2405. /** 编辑按钮 */
  2406. $edit,
  2407. /** 删除按钮 */
  2408. $delete,
  2409. /** 存储在元素上的数据 */
  2410. data: Reflect.get($ruleElement, "data-rule")
  2411. };
  2412. }
  2413. /**
  2414. * 创建一条规则元素
  2415. */
  2416. async createRuleItemElement(data, $shadowRoot) {
  2417. let name = await this.option.getDataItemName(data);
  2418. let $ruleItem = domUtils.createElement("div", {
  2419. className: "rule-item",
  2420. innerHTML: (
  2421. /*html*/
  2422. `
  2423. <div class="rule-name">${name}</div>
  2424. <div class="rule-controls">
  2425. <div class="rule-controls-enable">
  2426. <div class="pops-panel-switch">
  2427. <input class="pops-panel-switch__input" type="checkbox">
  2428. <span class="pops-panel-switch__core">
  2429. <div class="pops-panel-switch__action">
  2430. </div>
  2431. </span>
  2432. </div>
  2433. </div>
  2434. <div class="rule-controls-edit">
  2435. ${__pops.config.iconSVG.edit}
  2436. </div>
  2437. <div class="rule-controls-delete">
  2438. ${__pops.config.iconSVG.delete}
  2439. </div>
  2440. </div>
  2441. `
  2442. )
  2443. });
  2444. Reflect.set($ruleItem, "data-rule", data);
  2445. let switchCheckedClassName = "pops-panel-switch-is-checked";
  2446. const {
  2447. $enable,
  2448. $enableSwitch,
  2449. $enableSwitchCore,
  2450. $enableSwitchInput,
  2451. $delete,
  2452. $edit
  2453. } = this.parseRuleItemElement($ruleItem);
  2454. if (this.option.itemControls.enable.enable) {
  2455. domUtils.on($enableSwitchCore, "click", async (event) => {
  2456. let isChecked = false;
  2457. if ($enableSwitch.classList.contains(switchCheckedClassName)) {
  2458. $enableSwitch.classList.remove(switchCheckedClassName);
  2459. isChecked = false;
  2460. } else {
  2461. $enableSwitch.classList.add(switchCheckedClassName);
  2462. isChecked = true;
  2463. }
  2464. $enableSwitchInput.checked = isChecked;
  2465. await this.option.itemControls.enable.callback(data, isChecked);
  2466. });
  2467. if (await this.option.itemControls.enable.getEnable(data)) {
  2468. $enableSwitch.classList.add(switchCheckedClassName);
  2469. }
  2470. } else {
  2471. $enable.remove();
  2472. }
  2473. if (this.option.itemControls.edit.enable) {
  2474. domUtils.on($edit, "click", (event) => {
  2475. utils.preventEvent(event);
  2476. this.showEditView(true, data, $shadowRoot, $ruleItem, (newData) => {
  2477. data = null;
  2478. data = newData;
  2479. });
  2480. });
  2481. } else {
  2482. $edit.remove();
  2483. }
  2484. if (this.option.itemControls.delete.enable) {
  2485. domUtils.on($delete, "click", (event) => {
  2486. utils.preventEvent(event);
  2487. let $askDialog = __pops.confirm({
  2488. title: {
  2489. text: "提示",
  2490. position: "center"
  2491. },
  2492. content: {
  2493. text: "确定删除该条数据?",
  2494. html: false
  2495. },
  2496. btn: {
  2497. ok: {
  2498. enable: true,
  2499. callback: async (popsEvent) => {
  2500. log.success("删除数据");
  2501. let flag = await this.option.itemControls.delete.deleteCallBack(
  2502. data
  2503. );
  2504. if (flag) {
  2505. Qmsg.success("成功删除该数据");
  2506. $ruleItem.remove();
  2507. await this.updateDeleteAllBtnText($shadowRoot);
  2508. $askDialog.close();
  2509. } else {
  2510. Qmsg.error("删除该数据失败");
  2511. }
  2512. }
  2513. },
  2514. cancel: {
  2515. text: "取消",
  2516. enable: true
  2517. }
  2518. },
  2519. mask: {
  2520. enable: true
  2521. },
  2522. width: "300px",
  2523. height: "200px"
  2524. });
  2525. });
  2526. } else {
  2527. $delete.remove();
  2528. }
  2529. return $ruleItem;
  2530. }
  2531. /**
  2532. * 添加一个规则元素
  2533. */
  2534. async appendRuleItemElement($shadowRoot, data) {
  2535. let { $container } = this.parseViewElement($shadowRoot);
  2536. let $ruleItem = [];
  2537. let iteratorData = Array.isArray(data) ? data : [data];
  2538. for (let index = 0; index < iteratorData.length; index++) {
  2539. let item = iteratorData[index];
  2540. let $item = await this.createRuleItemElement(item, $shadowRoot);
  2541. $container.appendChild($item);
  2542. $ruleItem.push($item);
  2543. }
  2544. await this.updateDeleteAllBtnText($shadowRoot);
  2545. return $ruleItem;
  2546. }
  2547. /**
  2548. * 更新弹窗内容的元素
  2549. */
  2550. async updateRuleContaienrElement($shadowRoot) {
  2551. this.clearContent($shadowRoot);
  2552. const { $container } = this.parseViewElement($shadowRoot);
  2553. let data = await this.option.data();
  2554. await this.appendRuleItemElement($shadowRoot, data);
  2555. await this.updateDeleteAllBtnText($shadowRoot);
  2556. }
  2557. /**
  2558. * 更新规则元素
  2559. */
  2560. async updateRuleItemElement(data, $oldRuleItem, $shadowRoot) {
  2561. let $newRuleItem = await this.createRuleItemElement(data, $shadowRoot);
  2562. $oldRuleItem.after($newRuleItem);
  2563. $oldRuleItem.remove();
  2564. }
  2565. /**
  2566. * 清空内容
  2567. */
  2568. clearContent($shadowRoot) {
  2569. const { $container } = this.parseViewElement($shadowRoot);
  2570. domUtils.html($container, "");
  2571. }
  2572. /**
  2573. * 设置删除按钮的文字
  2574. */
  2575. setDeleteBtnText($shadowRoot, text, isHTML = false) {
  2576. const { $deleteBtn } = this.parseViewElement($shadowRoot);
  2577. if (isHTML) {
  2578. domUtils.html($deleteBtn, text);
  2579. } else {
  2580. domUtils.text($deleteBtn, text);
  2581. }
  2582. }
  2583. /**
  2584. * 更新【清空所有】的按钮的文字
  2585. * @param $shadowRoot
  2586. */
  2587. async updateDeleteAllBtnText($shadowRoot) {
  2588. let data = await this.option.data();
  2589. this.setDeleteBtnText($shadowRoot, `清空所有(${data.length})`);
  2590. }
  2591. }
  2592. const CookieRule = {
  2593. $key: {
  2594. STORAGE_KEY: "cookie-rule"
  2595. },
  2596. $data: {
  2597. /** 规则数据 */
  2598. ruleData: []
  2599. },
  2600. /** 初始化数据 */
  2601. init() {
  2602. this.$data.ruleData = [];
  2603. let allData = this.getData();
  2604. allData.forEach((data) => {
  2605. if (!data.enable) {
  2606. return;
  2607. }
  2608. let url = window.location.href;
  2609. let ruleUrl = data.data.url;
  2610. let enableRegExpToMatchUrl = data.data.enableRegExpToMatchUrl;
  2611. if (enableRegExpToMatchUrl) {
  2612. let regExpUrl = new RegExp(ruleUrl, "i");
  2613. if (!regExpUrl.test(url)) {
  2614. return;
  2615. }
  2616. } else {
  2617. if (!url.includes(ruleUrl)) {
  2618. return;
  2619. }
  2620. }
  2621. this.$data.ruleData.push(data);
  2622. });
  2623. },
  2624. /**
  2625. * 显示视图
  2626. */
  2627. showView() {
  2628. let panelHandlerComponents = __pops.config.PanelHandlerComponents();
  2629. function generateStorageApi(data, handler) {
  2630. return {
  2631. get(key, defaultValue) {
  2632. return Reflect.get(data, key) ?? defaultValue;
  2633. },
  2634. set(key, value) {
  2635. Reflect.set(data, key, value);
  2636. }
  2637. };
  2638. }
  2639. let ruleView = new RuleView({
  2640. title: "Cookie规则",
  2641. data: () => {
  2642. return this.getData();
  2643. },
  2644. getAddData: () => {
  2645. return this.getTemplateData();
  2646. },
  2647. getDataItemName: (data) => {
  2648. return data["name"];
  2649. },
  2650. updateData: (data) => {
  2651. return this.updateData(data);
  2652. },
  2653. deleteData: (data) => {
  2654. return this.deleteData(data);
  2655. },
  2656. getData: (data) => {
  2657. let allData = this.getData();
  2658. let findValue = allData.find((item) => item.uuid === data.uuid);
  2659. return findValue ?? data;
  2660. },
  2661. itemControls: {
  2662. enable: {
  2663. enable: true,
  2664. getEnable(data) {
  2665. return data.enable;
  2666. },
  2667. callback: (data, enable) => {
  2668. data.enable = enable;
  2669. this.updateData(data);
  2670. }
  2671. },
  2672. edit: {
  2673. enable: true,
  2674. getView: (data, isEdit) => {
  2675. let $fragment = document.createDocumentFragment();
  2676. let templateData = this.getTemplateData();
  2677. if (!isEdit) {
  2678. data = templateData;
  2679. }
  2680. let enable_template = UISwitch(
  2681. "启用",
  2682. "enable",
  2683. templateData.enable
  2684. );
  2685. Reflect.set(
  2686. enable_template.props,
  2687. PROPS_STORAGE_API,
  2688. generateStorageApi(data)
  2689. );
  2690. let $enable = panelHandlerComponents.createSectionContainerItem_switch(
  2691. enable_template
  2692. );
  2693. let name_template = UIInput(
  2694. "规则名称",
  2695. "name",
  2696. "",
  2697. templateData.name,
  2698. void 0,
  2699. "必填"
  2700. );
  2701. Reflect.set(
  2702. name_template.props,
  2703. PROPS_STORAGE_API,
  2704. generateStorageApi(data)
  2705. );
  2706. let $name = panelHandlerComponents.createSectionContainerItem_input(
  2707. name_template
  2708. );
  2709. let url_template = UIInput(
  2710. "网址",
  2711. "url",
  2712. templateData.data.url,
  2713. "用于执行该规则的网址",
  2714. void 0,
  2715. "必填"
  2716. );
  2717. Reflect.set(
  2718. url_template.props,
  2719. PROPS_STORAGE_API,
  2720. generateStorageApi(data.data)
  2721. );
  2722. let $url = panelHandlerComponents.createSectionContainerItem_input(
  2723. url_template
  2724. );
  2725. let enableRegExpToMatchUrl_template = UISwitch(
  2726. "启用正则匹配网址",
  2727. "enableRegExpToMatchUrl",
  2728. templateData.data.enableRegExpToMatchUrl
  2729. );
  2730. Reflect.set(
  2731. enableRegExpToMatchUrl_template.props,
  2732. PROPS_STORAGE_API,
  2733. generateStorageApi(data.data)
  2734. );
  2735. let $enableRegExpToMatchUrl = panelHandlerComponents.createSectionContainerItem_switch(
  2736. enableRegExpToMatchUrl_template
  2737. );
  2738. let cookieName_template = UIInput(
  2739. "Cookie名称",
  2740. "cookieName",
  2741. templateData.data.cookieName,
  2742. "用于匹配执行操作的Cookie名",
  2743. void 0,
  2744. "必填"
  2745. );
  2746. Reflect.set(
  2747. cookieName_template.props,
  2748. PROPS_STORAGE_API,
  2749. generateStorageApi(data.data)
  2750. );
  2751. let $cookieName = panelHandlerComponents.createSectionContainerItem_input(
  2752. cookieName_template
  2753. );
  2754. let enableRegExpToMatchCookieName_template = UISwitch(
  2755. "启用正则匹配Cookie名称",
  2756. "enableRegExpToMatchCookieName",
  2757. templateData.data.enableRegExpToMatchCookieName
  2758. );
  2759. Reflect.set(
  2760. enableRegExpToMatchCookieName_template.props,
  2761. PROPS_STORAGE_API,
  2762. generateStorageApi(data.data)
  2763. );
  2764. let $enableRegExpToMatchCookieName = panelHandlerComponents.createSectionContainerItem_switch(
  2765. enableRegExpToMatchCookieName_template
  2766. );
  2767. let operationMode_template = UISelect(
  2768. "操作模式",
  2769. "operationMode",
  2770. templateData.data.operationMode,
  2771. [
  2772. {
  2773. value: "delete",
  2774. text: "删除Cookie"
  2775. },
  2776. {
  2777. value: "extended",
  2778. text: "自动延长Cookie有效期30天"
  2779. },
  2780. {
  2781. value: "extended-90",
  2782. text: "自动延长Cookie有效期90天"
  2783. },
  2784. {
  2785. value: "extended-180",
  2786. text: "自动延长Cookie有效期180天"
  2787. },
  2788. {
  2789. value: "extended-360",
  2790. text: "自动延长Cookie有效期360天"
  2791. }
  2792. ]
  2793. );
  2794. Reflect.set(
  2795. operationMode_template.props,
  2796. PROPS_STORAGE_API,
  2797. generateStorageApi(data.data)
  2798. );
  2799. let $operationMode = panelHandlerComponents.createSectionContainerItem_select(
  2800. operationMode_template
  2801. );
  2802. let remark_template = UITextArea(
  2803. "备注",
  2804. "remark",
  2805. templateData.data.remark
  2806. );
  2807. Reflect.set(
  2808. remark_template.props,
  2809. PROPS_STORAGE_API,
  2810. generateStorageApi(data.data)
  2811. );
  2812. let $remark = panelHandlerComponents.createSectionContainerItem_textarea(
  2813. remark_template
  2814. );
  2815. $fragment.append(
  2816. $enable,
  2817. $name,
  2818. $url,
  2819. $enableRegExpToMatchUrl,
  2820. $cookieName,
  2821. $enableRegExpToMatchCookieName,
  2822. $operationMode,
  2823. $remark
  2824. );
  2825. return $fragment;
  2826. },
  2827. onsubmit: ($form, isEdit, editData) => {
  2828. let $ulist_li = $form.querySelectorAll(
  2829. ".rule-form-ulist > li"
  2830. );
  2831. let data = this.getTemplateData();
  2832. if (isEdit) {
  2833. data.uuid = editData.uuid;
  2834. }
  2835. try {
  2836. $ulist_li.forEach(($li) => {
  2837. let formConfig = Reflect.get($li, "__formConfig__");
  2838. let attrs = Reflect.get(formConfig, "attributes");
  2839. let storageApi = Reflect.get($li, PROPS_STORAGE_API);
  2840. let key = Reflect.get(attrs, ATTRIBUTE_KEY);
  2841. let defaultValue = Reflect.get(attrs, ATTRIBUTE_DEFAULT_VALUE);
  2842. let value = storageApi.get(key, defaultValue);
  2843. if (Reflect.has(data, key)) {
  2844. Reflect.set(data, key, value);
  2845. } else if (Reflect.has(data.data, key)) {
  2846. Reflect.set(data.data, key, value);
  2847. } else {
  2848. log.error(`${key}不在数据中`);
  2849. }
  2850. });
  2851. if (data.name.trim() === "") {
  2852. Qmsg.error("规则名称不能为空");
  2853. return {
  2854. success: false,
  2855. data
  2856. };
  2857. }
  2858. if (data.data.url.trim() === "") {
  2859. Qmsg.error("网址不能为空");
  2860. return {
  2861. success: false,
  2862. data
  2863. };
  2864. }
  2865. if (data.data.cookieName.trim() === "") {
  2866. Qmsg.error("Cookie名称不能为空");
  2867. return {
  2868. success: false,
  2869. data
  2870. };
  2871. }
  2872. if (isEdit) {
  2873. return {
  2874. success: this.updateData(data),
  2875. data
  2876. };
  2877. } else {
  2878. return {
  2879. success: this.addData(data),
  2880. data
  2881. };
  2882. }
  2883. } catch (error) {
  2884. log.error(error);
  2885. return {
  2886. success: false,
  2887. data
  2888. };
  2889. } finally {
  2890. this.init();
  2891. }
  2892. },
  2893. style: (
  2894. /*css*/
  2895. `
  2896. .pops-panel-textarea textarea{
  2897. height: 150px;
  2898. }
  2899. .pops-panel-item-left-desc-text{
  2900. line-height: normal;
  2901. margin-top: 6px;
  2902. font-size: 0.8em;
  2903. color: rgb(108, 108, 108);
  2904. max-width: 100px;
  2905. }
  2906. `
  2907. )
  2908. },
  2909. delete: {
  2910. enable: true,
  2911. deleteCallBack: (data) => {
  2912. return this.deleteData(data);
  2913. }
  2914. }
  2915. }
  2916. });
  2917. ruleView.showView();
  2918. },
  2919. /**
  2920. * 获取模板数据
  2921. */
  2922. getTemplateData() {
  2923. return {
  2924. uuid: utils.generateUUID(),
  2925. enable: true,
  2926. name: "",
  2927. data: {
  2928. url: "",
  2929. enableRegExpToMatchUrl: false,
  2930. cookieName: "",
  2931. enableRegExpToMatchCookieName: false,
  2932. operationMode: "delete",
  2933. remark: ""
  2934. }
  2935. };
  2936. },
  2937. /**
  2938. * 获取数据
  2939. */
  2940. getData() {
  2941. return _GM_getValue(this.$key.STORAGE_KEY, []);
  2942. },
  2943. /**
  2944. * 设置数据
  2945. * @param data
  2946. */
  2947. setData(data) {
  2948. _GM_setValue(this.$key.STORAGE_KEY, data);
  2949. },
  2950. /**
  2951. * 添加数据
  2952. * @param data
  2953. */
  2954. addData(data) {
  2955. let localData = this.getData();
  2956. let findIndex = localData.findIndex((item) => item.uuid == data.uuid);
  2957. if (findIndex === -1) {
  2958. localData.push(data);
  2959. _GM_setValue(this.$key.STORAGE_KEY, localData);
  2960. return true;
  2961. } else {
  2962. return false;
  2963. }
  2964. },
  2965. /**
  2966. * 更新数据
  2967. * @param data
  2968. */
  2969. updateData(data) {
  2970. let localData = this.getData();
  2971. let index = localData.findIndex((item) => item.uuid == data.uuid);
  2972. let updateFlag = false;
  2973. if (index !== -1) {
  2974. updateFlag = true;
  2975. localData[index] = data;
  2976. }
  2977. this.setData(localData);
  2978. return updateFlag;
  2979. },
  2980. /**
  2981. * 删除数据
  2982. * @param data
  2983. */
  2984. deleteData(data) {
  2985. let localData = this.getData();
  2986. let index = localData.findIndex((item) => item.uuid == data.uuid);
  2987. let deleteFlag = false;
  2988. if (index !== -1) {
  2989. deleteFlag = true;
  2990. localData.splice(index, 1);
  2991. }
  2992. this.setData(localData);
  2993. return deleteFlag;
  2994. },
  2995. /**
  2996. * 清空数据
  2997. */
  2998. clearData() {
  2999. _GM_deleteValue(this.$key.STORAGE_KEY);
  3000. },
  3001. /**
  3002. * 导出规则
  3003. */
  3004. exportRule(fileName = "rule.json") {
  3005. let allRule = this.getData();
  3006. let blob = new Blob([JSON.stringify(allRule, null, 4)]);
  3007. let blobUrl = window.URL.createObjectURL(blob);
  3008. let $a = domUtils.createElement("a");
  3009. $a.href = blobUrl;
  3010. $a.download = fileName;
  3011. $a.click();
  3012. setTimeout(() => {
  3013. window.URL.revokeObjectURL(blobUrl);
  3014. }, 1500);
  3015. },
  3016. /**
  3017. * 导入规则
  3018. */
  3019. importRule() {
  3020. let $alert = __pops.alert({
  3021. title: {
  3022. text: "请选择导入方式",
  3023. position: "center"
  3024. },
  3025. content: {
  3026. text: (
  3027. /*html*/
  3028. `
  3029. <div class="import-mode" data-mode="local">本地导入</div>
  3030. <div class="import-mode" data-mode="network">网络导入</div>
  3031. `
  3032. ),
  3033. html: true
  3034. },
  3035. width: PanelUISize.info.width,
  3036. height: PanelUISize.info.height,
  3037. style: (
  3038. /*css*/
  3039. `
  3040. .import-mode{
  3041. display: inline-block;
  3042. margin: 10px;
  3043. padding: 10px;
  3044. border: 1px solid #ccc;
  3045. border-radius: 5px;
  3046. cursor: pointer;
  3047. }
  3048. `
  3049. )
  3050. });
  3051. let $local = $alert.$shadowRoot.querySelector(
  3052. ".import-mode[data-mode='local']"
  3053. );
  3054. let $network = $alert.$shadowRoot.querySelector(
  3055. ".import-mode[data-mode='network']"
  3056. );
  3057. domUtils.on($local, "click", (event) => {
  3058. utils.preventEvent(event);
  3059. $alert.close();
  3060. let $input = domUtils.createElement("input", {
  3061. type: "file",
  3062. accept: ".json"
  3063. });
  3064. domUtils.on($input, ["propertychange", "input"], (event2) => {
  3065. if (!$input.files?.length) {
  3066. return;
  3067. }
  3068. let uploadFile = $input.files[0];
  3069. let fileReader = new FileReader();
  3070. fileReader.onload = () => {
  3071. let data = utils.toJSON(fileReader.result);
  3072. if (!Array.isArray(data)) {
  3073. log.error("不是正确的规则文件", data);
  3074. Qmsg.error("不是正确的规则文件");
  3075. return;
  3076. }
  3077. this.setData(data);
  3078. Qmsg.success(`成功导入 ${data.length}条规则`);
  3079. };
  3080. fileReader.readAsText(uploadFile, "UTF-8");
  3081. });
  3082. $input.click();
  3083. });
  3084. domUtils.on($network, "click", (event) => {
  3085. utils.preventEvent(event);
  3086. $alert.close();
  3087. __pops.prompt({
  3088. title: {
  3089. text: "网络导入",
  3090. position: "center"
  3091. },
  3092. content: {
  3093. text: "",
  3094. placeholder: "url",
  3095. focus: true
  3096. },
  3097. btn: {
  3098. ok: {
  3099. callback: async (eventDetails, event2) => {
  3100. let url = eventDetails.text;
  3101. if (utils.isNull(url)) {
  3102. Qmsg.error("请填入完整的url");
  3103. return;
  3104. }
  3105. let response = await httpx.get(url);
  3106. if (!response.status) {
  3107. return;
  3108. }
  3109. let data = utils.toJSON(response.data.responseText);
  3110. if (!Array.isArray(data)) {
  3111. log.error("不是正确的规则文件", response, data);
  3112. Qmsg.error("不是正确的规则文件");
  3113. return;
  3114. }
  3115. this.setData(data);
  3116. eventDetails.close();
  3117. Qmsg.success(`成功导入 ${data.length}条规则`);
  3118. }
  3119. }
  3120. },
  3121. width: PanelUISize.info.width,
  3122. height: "auto"
  3123. });
  3124. });
  3125. }
  3126. };
  3127. const CookieManagerView = {
  3128. init() {
  3129. this.registerMenu();
  3130. },
  3131. /**
  3132. * 显示视图
  3133. */
  3134. async showView() {
  3135. const $alert = __pops.alert({
  3136. title: {
  3137. text: "Cookie编辑器",
  3138. html: false,
  3139. position: "center"
  3140. },
  3141. content: {
  3142. text: (
  3143. /*html*/
  3144. `
  3145. <div class="cookie-wrapper">
  3146. <div class="cookie-search-wrapper">
  3147. <div class="cookie-search-inner">
  3148. <input type="text" placeholder="搜索Cookie名称">
  3149. </div>
  3150. <div class="cookie-search-setting">
  3151. <svg class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4368" width="28" height="28">
  3152. <path fill="#2c2c2c" d="M439.264 208a16 16 0 0 0-16 16v67.968a239.744 239.744 0 0 0-46.496 26.896l-58.912-34a16 16 0 0 0-21.856 5.856l-80 138.56a16 16 0 0 0 5.856 21.856l58.896 34a242.624 242.624 0 0 0 0 53.728l-58.88 34a16 16 0 0 0-6.72 20.176l0.848 1.68 80 138.56a16 16 0 0 0 21.856 5.856l58.912-34a239.744 239.744 0 0 0 46.496 26.88V800a16 16 0 0 0 16 16h160a16 16 0 0 0 16-16v-67.968a239.744 239.744 0 0 0 46.512-26.896l58.912 34a16 16 0 0 0 21.856-5.856l80-138.56a16 16 0 0 0-4.288-20.832l-1.568-1.024-58.896-34a242.624 242.624 0 0 0 0-53.728l58.88-34a16 16 0 0 0 6.72-20.176l-0.848-1.68-80-138.56a16 16 0 0 0-21.856-5.856l-58.912 34a239.744 239.744 0 0 0-46.496-26.88V224a16 16 0 0 0-16-16h-160z m32 48h96v67.376l28.8 12.576c13.152 5.76 25.632 12.976 37.184 21.52l25.28 18.688 58.448-33.728 48 83.136-58.368 33.68 3.472 31.2a194.624 194.624 0 0 1 0 43.104l-3.472 31.2 58.368 33.68-48 83.136-58.432-33.728-25.296 18.688c-11.552 8.544-24.032 15.76-37.184 21.52l-28.8 12.576V768h-96v-67.376l-28.784-12.576c-13.152-5.76-25.632-12.976-37.184-21.52l-25.28-18.688-58.448 33.728-48-83.136 58.368-33.68-3.472-31.2a194.624 194.624 0 0 1 0-43.104l3.472-31.2-58.368-33.68 48-83.136 58.432 33.728 25.296-18.688a191.744 191.744 0 0 1 37.184-21.52l28.8-12.576V256z m47.28 144a112 112 0 1 0 0 224 112 112 0 0 0 0-224z m0 48a64 64 0 1 1 0 128 64 64 0 0 1 0-128z"></path>
  3153. </svg>
  3154. </div>
  3155. </div>
  3156. <div class="cookie-control-wrapper">
  3157. <button class="cookie-control-refresh" type="default">刷新</button>
  3158. <button class="cookie-control-add" type="default">添加</button>
  3159. <button class="cookie-control-copy-all" type="default">复制全部</button>
  3160. <button class="cookie-control-clear-all" type="default">清除全部</button>
  3161. <button class="cookie-control-rule-manager" type="default">规则管理</button>
  3162. <div class="cookie-setting">
  3163. <svg class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4368" width="28" height="28">
  3164. <path fill="#2c2c2c" d="M439.264 208a16 16 0 0 0-16 16v67.968a239.744 239.744 0 0 0-46.496 26.896l-58.912-34a16 16 0 0 0-21.856 5.856l-80 138.56a16 16 0 0 0 5.856 21.856l58.896 34a242.624 242.624 0 0 0 0 53.728l-58.88 34a16 16 0 0 0-6.72 20.176l0.848 1.68 80 138.56a16 16 0 0 0 21.856 5.856l58.912-34a239.744 239.744 0 0 0 46.496 26.88V800a16 16 0 0 0 16 16h160a16 16 0 0 0 16-16v-67.968a239.744 239.744 0 0 0 46.512-26.896l58.912 34a16 16 0 0 0 21.856-5.856l80-138.56a16 16 0 0 0-4.288-20.832l-1.568-1.024-58.896-34a242.624 242.624 0 0 0 0-53.728l58.88-34a16 16 0 0 0 6.72-20.176l-0.848-1.68-80-138.56a16 16 0 0 0-21.856-5.856l-58.912 34a239.744 239.744 0 0 0-46.496-26.88V224a16 16 0 0 0-16-16h-160z m32 48h96v67.376l28.8 12.576c13.152 5.76 25.632 12.976 37.184 21.52l25.28 18.688 58.448-33.728 48 83.136-58.368 33.68 3.472 31.2a194.624 194.624 0 0 1 0 43.104l-3.472 31.2 58.368 33.68-48 83.136-58.432-33.728-25.296 18.688c-11.552 8.544-24.032 15.76-37.184 21.52l-28.8 12.576V768h-96v-67.376l-28.784-12.576c-13.152-5.76-25.632-12.976-37.184-21.52l-25.28-18.688-58.448 33.728-48-83.136 58.368-33.68-3.472-31.2a194.624 194.624 0 0 1 0-43.104l3.472-31.2-58.368-33.68 48-83.136 58.432 33.728 25.296-18.688a191.744 191.744 0 0 1 37.184-21.52l28.8-12.576V256z m47.28 144a112 112 0 1 0 0 224 112 112 0 0 0 0-224z m0 48a64 64 0 1 1 0 128 64 64 0 0 1 0-128z"></path>
  3165. </svg>
  3166. </div>
  3167. </div>
  3168. <div class="cookie-list-wrapper">
  3169. </div>
  3170. </div>
  3171. `
  3172. ),
  3173. html: true
  3174. },
  3175. btn: {
  3176. ok: {
  3177. enable: false
  3178. }
  3179. },
  3180. mask: {
  3181. enable: true
  3182. },
  3183. drag: true,
  3184. width: PanelUISize.setting.width,
  3185. height: PanelUISize.setting.height,
  3186. style: (
  3187. /*css*/
  3188. `
  3189. ${__pops.config.cssText.panelCSS}
  3190. .cookie-wrapper{
  3191. display: flex;
  3192. flex-direction: column;
  3193. padding: 10px;
  3194. gap: 10px;
  3195. }
  3196. .cookie-control-wrapper{
  3197. display: flex;
  3198. flex-wrap: wrap;
  3199. padding: 0px 10px;
  3200. gap: 5px;
  3201. --button-margin-left: 0px;
  3202. }
  3203. .cookie-search-wrapper{
  3204. display: flex;
  3205. align-items: center;
  3206. }
  3207. .cookie-search-inner{
  3208. width: 100%;
  3209. padding: 0px 10px;
  3210. }
  3211. .cookie-search-inner input{
  3212. height: 30px;
  3213. padding: 5px 8px;
  3214. width: 100%;
  3215. border-radius: 6px;
  3216. }
  3217. .cookie-search-inner input::placeholder{
  3218. display: flex;
  3219. align-items: baseline;
  3220. }
  3221. .cookie-search-inner input:focus-visible{
  3222. outline: none;
  3223. }
  3224. .cookie-setting,
  3225. .cookie-search-setting{
  3226. display: flex;
  3227. align-items: center;
  3228. }
  3229. .cookie-setting svg,
  3230. .cookie-search-setting svg{
  3231. cursor: pointer;
  3232. }
  3233. .cookie-list-wrapper{
  3234. display: flex;
  3235. flex-wrap: wrap;
  3236. gap: 10px;
  3237. }
  3238. .cookie-item{
  3239. display: flex;
  3240. flex-direction: column;
  3241. padding: 10px 10px;
  3242. margin: 0px 10px;
  3243. background: #f1efef;
  3244. border-radius: 10px;
  3245. gap: 5px;
  3246. box-sizing: border-box;
  3247. width: 100%;
  3248. }
  3249. .cookie-item-group{
  3250. display: flex;
  3251. align-items: center;
  3252. }
  3253. .cookie-item-group-left{
  3254. width: 100px;
  3255. min-width: 100px;
  3256. max-width: 100px;
  3257. text-transform: capitalize
  3258. }
  3259. .cookie-item-group-control .cookie-item-group-right{
  3260. display: flex;
  3261. align-items: center;
  3262. gap: 10px;
  3263. }
  3264. .cookie-item-group-control .cookie-item-group-control-copy,
  3265. .cookie-item-group-control .cookie-item-group-control-edit,
  3266. .cookie-item-group-control .cookie-item-group-control-delete{
  3267. display: flex;
  3268. align-items: center;
  3269. }
  3270. .cookie-item-group-control .cookie-item-group-control-delete svg{
  3271. width: 16px;
  3272. height: 16px;
  3273. }
  3274. .cookie-item-group-control svg{
  3275. cursor: pointer;
  3276. }
  3277. `
  3278. )
  3279. });
  3280. const $search = $alert.$shadowRoot.querySelector(
  3281. ".cookie-search-inner input"
  3282. );
  3283. const $searchSetting = $alert.$shadowRoot.querySelector(
  3284. ".cookie-search-setting"
  3285. );
  3286. const $refresh = $alert.$shadowRoot.querySelector(
  3287. ".cookie-control-refresh"
  3288. );
  3289. const $add = $alert.$shadowRoot.querySelector(
  3290. ".cookie-control-add"
  3291. );
  3292. const $copyAll = $alert.$shadowRoot.querySelector(
  3293. ".cookie-control-copy-all"
  3294. );
  3295. const $clearAll = $alert.$shadowRoot.querySelector(
  3296. ".cookie-control-clear-all"
  3297. );
  3298. const $ruleManager = $alert.$shadowRoot.querySelector(
  3299. ".cookie-control-rule-manager"
  3300. );
  3301. const $setting = $alert.$shadowRoot.querySelector(".cookie-setting");
  3302. const $cookieListWrapper = $alert.$shadowRoot.querySelector(
  3303. ".cookie-list-wrapper"
  3304. );
  3305. let createCookieItemElement = (cookieInfo) => {
  3306. const $cookieItem = domUtils.createElement("div", {
  3307. className: "cookie-item",
  3308. innerHTML: (
  3309. /*html*/
  3310. `
  3311. `
  3312. ),
  3313. "data-cookie-info": cookieInfo
  3314. });
  3315. const cookieProperty = [
  3316. {
  3317. leftText: "name",
  3318. rightText: cookieInfo.name
  3319. },
  3320. {
  3321. leftText: "value",
  3322. // 解码值
  3323. rightText: Panel.getValue("decode-cookie-value") ? decodeURIComponent(cookieInfo.value) : encodeURIComponent(cookieInfo.value)
  3324. }
  3325. ];
  3326. if (CookieManager.cookieManagerApiName === "GM_cookie" || CookieManager.cookieManagerApiName === "GM.cookie") {
  3327. cookieInfo = cookieInfo;
  3328. cookieProperty.push(
  3329. {
  3330. leftText: "domain",
  3331. rightText: cookieInfo.domain
  3332. },
  3333. {
  3334. leftText: "path",
  3335. rightText: cookieInfo.path
  3336. },
  3337. {
  3338. leftText: "session",
  3339. rightText: JSON.stringify(cookieInfo.session)
  3340. },
  3341. {
  3342. leftText: "expires",
  3343. rightText: cookieInfo.session ? "会话" : cookieInfo.expirationDate ? new Date(cookieInfo.expirationDate * 1e3).toISOString() : "未知"
  3344. },
  3345. {
  3346. leftText: "httpOnly",
  3347. rightText: JSON.stringify(cookieInfo.httpOnly)
  3348. },
  3349. {
  3350. leftText: "hostOnly",
  3351. rightText: JSON.stringify(cookieInfo.hostOnly)
  3352. },
  3353. {
  3354. leftText: "secure",
  3355. rightText: JSON.stringify(cookieInfo.secure)
  3356. },
  3357. {
  3358. leftText: "sameSite",
  3359. rightText: cookieInfo.sameSite
  3360. }
  3361. );
  3362. } else if (CookieManager.cookieManagerApiName === "cookieStore") {
  3363. cookieInfo = cookieInfo;
  3364. cookieProperty.push(
  3365. {
  3366. leftText: "domain",
  3367. rightText: cookieInfo.domain
  3368. },
  3369. {
  3370. leftText: "path",
  3371. rightText: cookieInfo.path
  3372. },
  3373. {
  3374. leftText: "expires",
  3375. rightText: cookieInfo.expires ? new Date(cookieInfo.expires).toISOString() : "会话"
  3376. },
  3377. {
  3378. leftText: "secure",
  3379. rightText: JSON.stringify(cookieInfo.secure)
  3380. },
  3381. {
  3382. leftText: "sameSite",
  3383. rightText: cookieInfo.sameSite
  3384. }
  3385. );
  3386. }
  3387. cookieProperty.forEach((it) => {
  3388. const $cookieItemGroup = domUtils.createElement("div", {
  3389. className: "cookie-item-group",
  3390. innerHTML: (
  3391. /*html*/
  3392. `
  3393. <div class="cookie-item-group-left">
  3394. <p>${it.leftText}</p>
  3395. </div>
  3396. <div class="cookie-item-group-right">
  3397. <p>${it.rightText}</p>
  3398. </div>
  3399. `
  3400. )
  3401. });
  3402. domUtils.append($cookieItem, $cookieItemGroup);
  3403. });
  3404. let $cookieItemGroupControl = domUtils.createElement("div", {
  3405. className: "cookie-item-group cookie-item-group-control",
  3406. innerHTML: (
  3407. /*html*/
  3408. `
  3409. <div class="cookie-item-group-left">操作</div>
  3410. <div class="cookie-item-group-right">
  3411. <div class="cookie-item-group-control-copy">
  3412. <svg t="1742795616339" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16">
  3413. <path d="M880 247.008l-162.016-166.016Q700.992 64 677.984 64h-316.992q-26.016 0-46.016 18.016-16.992 15.008-23.008 36.992H231.968q-43.008 0-73.504 31.008t-30.496 76v627.008q0 44 30.496 75.488T231.968 960h508q43.008 0 73.504-31.488t30.496-75.488v-63.008q23.008-6.016 37.504-25.504t14.496-44.512V287.008q0-24-16-40z m-168-160.992l-3.008-3.008z m98.016 177.984L744 196z m-126.016-116.992l108 110.016h-108V147.008zM676.992 128zM204.992 948q4 0.992 4.992 2.016-2.016-0.992-4.992-2.016z m27.008 4q-6.016 0-12-0.992 4.992 0.992 12 0.992z m543.008-99.008q0 15.008-10.016 25.504t-24.992 10.496H232q-14.016 0-24.512-10.496t-10.496-25.504V225.984q0-15.008 10.496-25.504t24.512-10.496h58.016v531.008q0 30.016 20.992 51.008t50.016 20.992H775.04v60z m52-132.992q0 2.016-2.016 2.016h-464q-2.016 0-2.016-2.016V136.992q0-2.016 2.016-2.016h251.008v156.992q0 15.008 10.016 24.992t24 10.016h180.992v392.992z m9.984 64q4-0.992 8.992-2.016-4.992 0.992-8.992 2.016z m-244-168.992h-107.008q-15.008 0-24.992 10.496t-10.016 24.992 10.016 24.992 24.992 10.496h107.008q14.016 0 24.512-10.496t10.496-24.992-10.496-24.992-24.512-10.496z m107.008-111.008h-214.016q-14.016 0-24.512 10.496t-10.496 24.992 10.496 24.992 24.512 10.496h214.016q14.016 0 24-10.496t10.016-24.992-10.016-24.992-24-10.496z m-240.992 36q0 4 0.992 8-0.992-4-0.992-8zM700 512z m12 52l4-2.016z m-260.992-135.488q0 14.496 10.496 24.992t24.512 10.496h214.016q14.016 0 24-10.496t10.016-24.992-10.016-24.992-24-10.496h-214.016q-14.016 0-24.512 10.496t-10.496 24.992z m8 1.504z"></path>
  3414. </svg>
  3415. </div>
  3416. <div class="cookie-item-group-control-edit">
  3417. <svg t="1742795710451" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16">
  3418. <path d="M800 960 224 960c-52.928 0-96-43.072-96-96L128 224c0-52.928 43.072-96 96-96l448 0c17.696 0 32 14.336 32 32s-14.304 32-32 32L224 192C206.368 192 192 206.368 192 224l0 640c0 17.664 14.368 32 32 32l576 0c17.664 0 32-14.336 32-32L832 352c0-17.664 14.304-32 32-32s32 14.336 32 32l0 512C896 916.928 852.928 960 800 960zM612 448c-8.192 0-16.384-3.136-22.624-9.376-12.512-12.512-12.512-32.736 0-45.248l318.016-318.016c12.512-12.512 32.736-12.512 45.248 0s12.512 32.736 0 45.248l-318.016 318.016C628.384 444.896 620.192 448 612 448zM480 448 288 448c-17.664 0-32-14.336-32-32s14.336-32 32-32l192 0c17.664 0 32 14.336 32 32S497.664 448 480 448zM672 640 288 640c-17.664 0-32-14.304-32-32s14.336-32 32-32l384 0c17.696 0 32 14.304 32 32S689.696 640 672 640z"></path>
  3419. </svg>
  3420. </div>
  3421. <div class="cookie-item-group-control-delete">
  3422. ${__pops.config.iconSVG.delete}
  3423. </div>
  3424. </div>
  3425. `
  3426. )
  3427. });
  3428. let $cookieItemCopy = $cookieItemGroupControl.querySelector(
  3429. ".cookie-item-group-control-copy"
  3430. );
  3431. let $cookieItemEdit = $cookieItemGroupControl.querySelector(
  3432. ".cookie-item-group-control-edit"
  3433. );
  3434. let $cookieItemDelete = $cookieItemGroupControl.querySelector(
  3435. ".cookie-item-group-control-delete"
  3436. );
  3437. domUtils.on($cookieItemCopy, "click", (event) => {
  3438. utils.preventEvent(event);
  3439. let cookieText = cookieInfo.value;
  3440. utils.setClip(cookieText).then((status) => {
  3441. if (status) {
  3442. Qmsg.success("复制成功");
  3443. } else {
  3444. Qmsg.error("复制失败");
  3445. }
  3446. });
  3447. });
  3448. domUtils.on($cookieItemEdit, "click", (event) => {
  3449. utils.preventEvent(event);
  3450. CookieManagerEditView.showView(cookieInfo, (__cookieInfo__) => {
  3451. let $newCookieItem = createCookieItemElement(__cookieInfo__);
  3452. domUtils.after($cookieItem, $newCookieItem);
  3453. $cookieItem.parentElement?.removeChild($cookieItem);
  3454. });
  3455. });
  3456. domUtils.on($cookieItemDelete, "click", (event) => {
  3457. utils.preventEvent(event);
  3458. let result = confirm("确定删除该Cookie?");
  3459. if (!result) {
  3460. return;
  3461. }
  3462. CookieManager.deleteCookie(cookieInfo).then((status) => {
  3463. if (!status) {
  3464. Qmsg.success("删除成功");
  3465. $cookieItem.parentElement?.removeChild($cookieItem);
  3466. } else {
  3467. log.error(status);
  3468. Qmsg.error("删除失败");
  3469. }
  3470. });
  3471. });
  3472. domUtils.append($cookieItem, [$cookieItemGroupControl]);
  3473. return $cookieItem;
  3474. };
  3475. let updateCookieListGroup = async (filterCallBack) => {
  3476. let cookieList = await CookieManager.queryAllCookie();
  3477. if (typeof filterCallBack === "function") {
  3478. cookieList = cookieList.filter(filterCallBack);
  3479. }
  3480. domUtils.empty($cookieListWrapper);
  3481. let $fragment = document.createDocumentFragment();
  3482. cookieList.forEach((cookieItem) => {
  3483. if (Panel.getValue("exclude-session-cookie")) {
  3484. if (cookieItem.session) {
  3485. return;
  3486. }
  3487. if (CookieManager.cookieManagerApiName === "cookieStore" && cookieItem.expires == null) {
  3488. return;
  3489. }
  3490. }
  3491. const $cookieItem = createCookieItemElement(cookieItem);
  3492. $fragment.appendChild($cookieItem);
  3493. });
  3494. $cookieListWrapper.appendChild($fragment);
  3495. };
  3496. updateCookieListGroup();
  3497. domUtils.on(
  3498. $search,
  3499. ["input", "propertychange"],
  3500. utils.debounce((event) => {
  3501. updateCookieListGroup((cookieItem) => {
  3502. let searchText = domUtils.val($search);
  3503. let enableRegExp = Panel.getValue(
  3504. "search-config-use-regexp"
  3505. );
  3506. return enableRegExp ? Boolean(cookieItem.name.match(new RegExp(searchText))) : cookieItem.name.includes(searchText);
  3507. });
  3508. })
  3509. );
  3510. domUtils.listenKeyboard(
  3511. $search,
  3512. "keypress",
  3513. (keyName, keyValue, otherCodeList) => {
  3514. if (keyName === "Enter" && otherCodeList.length === 0) {
  3515. utils.dispatchEvent($search, "input");
  3516. }
  3517. }
  3518. );
  3519. domUtils.on($searchSetting, "click", (event) => {
  3520. utils.preventEvent(event);
  3521. let $settingAlert = __pops.alert({
  3522. title: {
  3523. text: "搜索配置",
  3524. position: "center"
  3525. },
  3526. content: {
  3527. text: "",
  3528. html: true
  3529. },
  3530. btn: {
  3531. ok: {
  3532. enable: false
  3533. }
  3534. },
  3535. drag: true,
  3536. mask: {
  3537. clickEvent: {
  3538. toClose: true
  3539. }
  3540. },
  3541. width: PanelUISize.info.width,
  3542. height: PanelUISize.info.height,
  3543. style: (
  3544. /*css*/
  3545. `
  3546. ${__pops.config.cssText.panelCSS}
  3547.  
  3548. .pops-alert-content li{
  3549. display: flex;
  3550. justify-content: space-between;
  3551. align-items: center;
  3552. padding: 10px;
  3553. }
  3554. .pops-panel-item-left-desc-text{
  3555. line-height: normal;
  3556. margin-top: 6px;
  3557. font-size: 0.8em;
  3558. color: rgb(108, 108, 108);
  3559. }
  3560. `
  3561. )
  3562. });
  3563. let $content = $settingAlert.$shadowRoot.querySelector(
  3564. ".pops-alert-content"
  3565. );
  3566. let panelHandlerComponents = __pops.config.PanelHandlerComponents();
  3567. let $useRegExp = panelHandlerComponents.createSectionContainerItem_switch(
  3568. UISwitch(
  3569. "启用正则表达式",
  3570. "search-config-use-regexp",
  3571. false,
  3572. void 0,
  3573. "使用正则表达式搜索Cookie名称"
  3574. )
  3575. );
  3576. domUtils.append($content, $useRegExp);
  3577. });
  3578. domUtils.on($refresh, "click", (event) => {
  3579. utils.preventEvent(event);
  3580. let searchText = domUtils.val($search);
  3581. if (searchText == "") {
  3582. updateCookieListGroup();
  3583. } else {
  3584. utils.dispatchEvent($search, "input");
  3585. }
  3586. });
  3587. domUtils.on($add, "click", (event) => {
  3588. utils.preventEvent(event);
  3589. CookieManagerEditView.showView(void 0, (__cookieInfo__) => {
  3590. updateCookieListGroup();
  3591. });
  3592. });
  3593. domUtils.on($copyAll, "click", (event) => {
  3594. utils.preventEvent(event);
  3595. CookieManager.queryAllCookie().then((cookieList) => {
  3596. cookieList = cookieList.filter((it) => {
  3597. return !(it.session && Panel.getValue("exclude-session-cookie"));
  3598. });
  3599. if (cookieList.length === 0) {
  3600. Qmsg.warning("没有Cookie可以复制");
  3601. return;
  3602. }
  3603. let cookieText = cookieList.map((it) => {
  3604. let cookieItemValueText = it.value;
  3605. return `${it.name}=${cookieItemValueText}; `;
  3606. }).join("");
  3607. utils.setClip(cookieText).then((status) => {
  3608. if (status) {
  3609. Qmsg.success("复制成功");
  3610. } else {
  3611. Qmsg.error("复制失败");
  3612. }
  3613. });
  3614. });
  3615. });
  3616. domUtils.on($clearAll, "click", (event) => {
  3617. utils.preventEvent(event);
  3618. let result = window.confirm("确定清除全部Cookie?");
  3619. if (!result) {
  3620. return;
  3621. }
  3622. CookieManager.deleteAllCookie().then((deleteInfo) => {
  3623. if (deleteInfo.error) {
  3624. Qmsg.warning(
  3625. `清除成功:${deleteInfo.success} 失败:${deleteInfo.error}`
  3626. );
  3627. } else {
  3628. Qmsg.success("清除成功");
  3629. }
  3630. updateCookieListGroup();
  3631. });
  3632. });
  3633. domUtils.on($ruleManager, "click", (event) => {
  3634. utils.preventEvent(event);
  3635. CookieRule.showView();
  3636. });
  3637. domUtils.on($setting, "click", (event) => {
  3638. utils.preventEvent(event);
  3639. let $settingAlert = __pops.alert({
  3640. title: {
  3641. text: "设置",
  3642. position: "center"
  3643. },
  3644. content: {
  3645. text: "",
  3646. html: true
  3647. },
  3648. btn: {
  3649. ok: {
  3650. enable: false
  3651. }
  3652. },
  3653. drag: true,
  3654. mask: {
  3655. clickEvent: {
  3656. toClose: true
  3657. }
  3658. },
  3659. width: PanelUISize.info.width,
  3660. height: PanelUISize.info.height,
  3661. style: (
  3662. /*css*/
  3663. `
  3664. ${__pops.config.cssText.panelCSS}
  3665.  
  3666. .pops-alert-content li{
  3667. display: flex;
  3668. justify-content: space-between;
  3669. align-items: center;
  3670. padding: 10px;
  3671. }
  3672. .pops-panel-item-left-desc-text{
  3673. line-height: normal;
  3674. margin-top: 6px;
  3675. font-size: 0.8em;
  3676. color: rgb(108, 108, 108);
  3677. }
  3678. `
  3679. )
  3680. });
  3681. let $content = $settingAlert.$shadowRoot.querySelector(
  3682. ".pops-alert-content"
  3683. );
  3684. let panelHandlerComponents = __pops.config.PanelHandlerComponents();
  3685. let $useGM_cookie = panelHandlerComponents.createSectionContainerItem_select(
  3686. UISelect(
  3687. "CookieManager Api",
  3688. "cookie-manager-api",
  3689. "document.cookie",
  3690. [
  3691. {
  3692. text: "document.cookie",
  3693. value: "document.cookie"
  3694. },
  3695. {
  3696. text: "cookieStore",
  3697. value: "cookieStore"
  3698. },
  3699. {
  3700. text: "GM_cookie",
  3701. value: "GM_cookie"
  3702. },
  3703. {
  3704. text: "GM.cookie",
  3705. value: "GM.cookie"
  3706. }
  3707. ],
  3708. () => {
  3709. updateCookieListGroup();
  3710. },
  3711. "操作Cookie的Api函数"
  3712. )
  3713. );
  3714. let $decodeValue = panelHandlerComponents.createSectionContainerItem_switch(
  3715. UISwitch(
  3716. "解码Cookie值",
  3717. "decode-cookie-value",
  3718. false,
  3719. () => {
  3720. updateCookieListGroup();
  3721. },
  3722. "对Cookie值进行解码"
  3723. )
  3724. );
  3725. let $excludeSessionCookie = panelHandlerComponents.createSectionContainerItem_switch(
  3726. UISwitch(
  3727. "排除Session Cookie",
  3728. "exclude-session-cookie",
  3729. false,
  3730. () => {
  3731. updateCookieListGroup();
  3732. },
  3733. "过滤掉浏览器会话Cookie"
  3734. )
  3735. );
  3736. domUtils.append($content, [
  3737. $useGM_cookie,
  3738. $decodeValue,
  3739. $excludeSessionCookie
  3740. ]);
  3741. });
  3742. },
  3743. /**
  3744. * 注册(不可用)脚本菜单
  3745. */
  3746. registerMenu() {
  3747. const that = this;
  3748. GM_Menu.add({
  3749. key: "cookie_manager_view",
  3750. text: "⚙ Cookie管理",
  3751. autoReload: false,
  3752. isStoreValue: false,
  3753. showText(text, enable) {
  3754. return text;
  3755. },
  3756. callback(data) {
  3757. that.showView();
  3758. }
  3759. });
  3760. }
  3761. };
  3762. const CookieRuleController = {
  3763. init() {
  3764. this.execController();
  3765. domUtils.ready(() => {
  3766. this.execController();
  3767. });
  3768. },
  3769. /**
  3770. * 执行操作
  3771. */
  3772. execController() {
  3773. for (let index = 0; index < CookieRule.$data.ruleData.length; index++) {
  3774. const rule = CookieRule.$data.ruleData[index];
  3775. CookieManager.queryAllCookie().then(async (cookieListResult) => {
  3776. for (let cookieInfoIndex = 0; cookieInfoIndex < cookieListResult.length; cookieInfoIndex++) {
  3777. let cookieInfo = cookieListResult[cookieInfoIndex];
  3778. const cookieName = cookieInfo.name;
  3779. const ruleCookieName = rule.data.cookieName;
  3780. let flag = false;
  3781. if (rule.data.enableRegExpToMatchCookieName) {
  3782. let regExpCookieName = new RegExp(ruleCookieName, "i");
  3783. if (regExpCookieName.test(cookieName)) {
  3784. flag = true;
  3785. }
  3786. } else {
  3787. if (cookieName.includes(ruleCookieName)) {
  3788. flag = true;
  3789. }
  3790. }
  3791. if (flag) {
  3792. let operationMode = rule.data.operationMode;
  3793. if (operationMode === "delete") {
  3794. CookieManager.deleteCookie(cookieInfo);
  3795. } else if (operationMode === "extended" || operationMode === "extended-90" || operationMode === "extended-180" || operationMode === "extended-360") {
  3796. let currentTime = Date.now();
  3797. let oneMonth = 30 * 24 * 60 * 60 * 1e3;
  3798. let threeMonth = oneMonth * 3;
  3799. let halfAYear = oneMonth * 6;
  3800. let oneYear = oneMonth * 12;
  3801. let checkTime = oneMonth;
  3802. if (operationMode === "extended-90") {
  3803. checkTime = threeMonth;
  3804. } else if (operationMode === "extended-180") {
  3805. checkTime = halfAYear;
  3806. } else if (operationMode === "extended-360") {
  3807. checkTime = oneYear;
  3808. }
  3809. let updateFlag = false;
  3810. if (CookieManager.cookieManagerApiName === "document.cookie") {
  3811. cookieInfo.expirationDate = currentTime + checkTime;
  3812. updateFlag = true;
  3813. } else if (CookieManager.cookieManagerApiName === "cookieStore") {
  3814. let expireTime = cookieInfo.expires;
  3815. if (typeof expireTime === "number" && expireTime - currentTime < checkTime) {
  3816. cookieInfo.expires = expireTime + checkTime;
  3817. updateFlag = true;
  3818. }
  3819. } else if (CookieManager.cookieManagerApiName === "GM_cookie" || CookieManager.cookieManagerApiName === "GM.cookie") {
  3820. let expireTime = cookieInfo.expirationDate;
  3821. if (typeof expireTime === "number" && expireTime * 1e3 - currentTime < checkTime) {
  3822. cookieInfo.expirationDate = expireTime + checkTime / 1e3;
  3823. updateFlag = true;
  3824. }
  3825. } else {
  3826. log.error(
  3827. "未知的cookieManagerApiName",
  3828. CookieManager.cookieManagerApiName
  3829. );
  3830. }
  3831. if (updateFlag) {
  3832. await CookieManager.updateCookie(cookieInfo);
  3833. }
  3834. }
  3835. }
  3836. }
  3837. });
  3838. }
  3839. }
  3840. };
  3841. const UIButton = function(text, description, buttonText, buttonIcon, buttonIsRightIcon, buttonIconIsLoading, buttonType, clickCallBack, afterAddToUListCallBack, disable) {
  3842. let result = {
  3843. text,
  3844. type: "button",
  3845. attributes: {},
  3846. props: {},
  3847. description,
  3848. buttonIcon,
  3849. buttonIsRightIcon,
  3850. buttonIconIsLoading,
  3851. buttonType,
  3852. buttonText,
  3853. callback(event) {
  3854. if (typeof clickCallBack === "function") {
  3855. clickCallBack(event);
  3856. }
  3857. },
  3858. afterAddToUListCallBack
  3859. };
  3860. Reflect.set(result.attributes, ATTRIBUTE_INIT, () => {
  3861. result.disable = Boolean(
  3862. disable
  3863. );
  3864. });
  3865. return result;
  3866. };
  3867. const Component_Rule = {
  3868. id: "view-rule",
  3869. title: "规则",
  3870. headerTitle: "Cookie操作规则",
  3871. forms: [
  3872. {
  3873. type: "forms",
  3874. text: "",
  3875. forms: [
  3876. UIButton(
  3877. "自定义规则",
  3878. "操作Cookie的规则",
  3879. "管理",
  3880. void 0,
  3881. false,
  3882. false,
  3883. "default",
  3884. () => {
  3885. CookieRule.showView();
  3886. }
  3887. )
  3888. ]
  3889. },
  3890. {
  3891. type: "forms",
  3892. text: "",
  3893. forms: [
  3894. UIButton(
  3895. "数据导入",
  3896. "导入自定义规则数据",
  3897. "导入",
  3898. void 0,
  3899. false,
  3900. false,
  3901. "primary",
  3902. () => {
  3903. CookieRule.importRule();
  3904. }
  3905. ),
  3906. UIButton(
  3907. "数据导出",
  3908. "导出自定义规则数据",
  3909. "导出",
  3910. void 0,
  3911. false,
  3912. false,
  3913. "primary",
  3914. () => {
  3915. CookieRule.exportRule("CookieManagerRule.json");
  3916. }
  3917. )
  3918. ]
  3919. }
  3920. ]
  3921. };
  3922. const Component_Common = {
  3923. id: "view-general",
  3924. title: "通用",
  3925. forms: [
  3926. {
  3927. text: "Toast配置",
  3928. type: "forms",
  3929. forms: [
  3930. UISelect(
  3931. "Toast位置",
  3932. PanelSettingConfig.qmsg_config_position.key,
  3933. PanelSettingConfig.qmsg_config_position.defaultValue,
  3934. [
  3935. {
  3936. value: "topleft",
  3937. text: "左上角"
  3938. },
  3939. {
  3940. value: "top",
  3941. text: "顶部"
  3942. },
  3943. {
  3944. value: "topright",
  3945. text: "右上角"
  3946. },
  3947. {
  3948. value: "left",
  3949. text: "左边"
  3950. },
  3951. {
  3952. value: "center",
  3953. text: "中间"
  3954. },
  3955. {
  3956. value: "right",
  3957. text: "右边"
  3958. },
  3959. {
  3960. value: "bottomleft",
  3961. text: "左下角"
  3962. },
  3963. {
  3964. value: "bottom",
  3965. text: "底部"
  3966. },
  3967. {
  3968. value: "bottomright",
  3969. text: "右下角"
  3970. }
  3971. ],
  3972. (event, isSelectValue, isSelectText) => {
  3973. log.info("设置当前Qmsg弹出位置" + isSelectText);
  3974. },
  3975. "Toast显示在页面九宫格的位置"
  3976. ),
  3977. UISelect(
  3978. "最多显示的数量",
  3979. PanelSettingConfig.qmsg_config_maxnums.key,
  3980. PanelSettingConfig.qmsg_config_maxnums.defaultValue,
  3981. [
  3982. {
  3983. value: 1,
  3984. text: "1"
  3985. },
  3986. {
  3987. value: 2,
  3988. text: "2"
  3989. },
  3990. {
  3991. value: 3,
  3992. text: "3"
  3993. },
  3994. {
  3995. value: 4,
  3996. text: "4"
  3997. },
  3998. {
  3999. value: 5,
  4000. text: "5"
  4001. }
  4002. ],
  4003. void 0,
  4004. "限制Toast显示的数量"
  4005. ),
  4006. UISwitch(
  4007. "逆序弹出",
  4008. PanelSettingConfig.qmsg_config_showreverse.key,
  4009. PanelSettingConfig.qmsg_config_showreverse.defaultValue,
  4010. void 0,
  4011. "修改Toast弹出的顺序"
  4012. )
  4013. ]
  4014. }
  4015. ]
  4016. };
  4017. PanelContent.addContentConfig([Component_Common, Component_Rule]);
  4018. Panel.init();
  4019. CookieRule.init();
  4020. CookieRuleController.init();
  4021. CookieManagerView.init();
  4022.  
  4023. })(Qmsg, DOMUtils, Utils, pops);

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址