import { DOMUtils, httpx, log, pops, SCRIPT_NAME, utils } from "@/env"; import { UIButton } from "@components/setting/components/ui-button"; import { UIInput } from "@components/setting/components/ui-input"; import { UISwitch } from "@components/setting/components/ui-switch"; import { Panel } from "@components/setting/panel"; import { ATTRIBUTE_DEFAULT_VALUE, ATTRIBUTE_KEY, PROPS_STORAGE_API } from "@components/setting/panel-config"; import { PanelContent } from "@components/setting/panel-content"; import { PanelUISize } from "@components/setting/panel-ui-size"; import { type RulePanelContentOption, type RuleSubscribeOption } from "@components/utils/RulePanelView"; import { StorageUtils } from "@components/utils/StorageUtils"; import type { PopsPanelContainerConfig } from "@whitesev/pops/dist/types/src/components/panel/types/components-container.js"; import type { PopsPanelContentConfig } from "@whitesev/pops/dist/types/src/components/panel/types/index.js"; import Qmsg from "qmsg"; import { NetDiskRuleDataKEY, WebsiteRuleDataKey } from "../data/NetDiskRuleDataKey"; import { NetDiskPops } from "../pops/NetDiskPops"; import { NetDiskRule } from "../rule/NetDiskRule"; import { NetDiskView } from "../view/NetDiskView"; import panelIndexCSS from "./../view/setting/index.css?raw"; import panelSettingCSS from "./css/index.css?raw"; import { WebsiteSubscribeRule } from "./WebsiteSubscribeRule"; import { CommonUtil } from "@components/utils/CommonUtil"; /** 深拷贝 */ function deepCopy(obj: T): T { if (obj === null || typeof obj !== "object") { return obj; } let copy = Array.isArray(obj) ? [] : {}; for (let key in obj) { if (obj.hasOwnProperty(key)) { // @ts-expect-error copy[key] = deepCopy(obj[key]); } } // @ts-expect-error return copy; } /** 网站规则的存储操作Api */ const WebsiteRuleStorageApi = new StorageUtils("websiteRule"); /** 网站规则 */ export const WebsiteRule = { $data: { STORAGE_KEY: "rule", EXPORT_CONFIG_KEY: "rule-export-config", /** 是否正在显示编辑视图 */ isShowEditView: false, }, init() {}, /** * 获取默认数据 */ getTemplateData(): WebsiteRuleOption { return { uuid: utils.generateUUID(), subscribeUUID: null, enable: true, name: "", url: "", data: {}, }; }, /** * 获取规则面板视图的配置 * @param quickAddData 用于快速添加数据 */ getRulePanelViewOption(quickAddData?: WebsiteRuleOption) { const that = this; const panelHandlerComponents = pops.fn.PanelHandlerComponents(); const addData = () => { return quickAddData ?? this.getTemplateData(); }; /** * 自定义存储api的配置 * @param uuid */ const generateStorageApi = function (data: any) { return { get(key: string, defaultValue: any) { return data[key] ?? defaultValue; }, set(key: string, value: any) { data[key] = value; }, }; }; const ruleEditHandler = (data: WebsiteRuleOption, isEdit: boolean, subscribeUUID?: string) => { this.$data.isShowEditView = true; if (!isEdit) { data = addData(); } /** * 自定义存储api的配置 * @param uuid */ const generatePanelStorageApi = (uuid: string) => { return { get(key: string, defaultValue: any) { if (subscribeUUID) { // 订阅的 const currentRule = WebsiteSubscribeRule.getSubscribeRule(subscribeUUID, uuid)!; return Reflect.get(currentRule.data, key) ?? defaultValue; } else { // 本地的 const currentRule = that.getRule(uuid) ?? addData(); const panelValue = Panel.getValue(key, defaultValue); return (currentRule && Reflect.get(currentRule.data, key)) ?? panelValue; } }, set(key: string, value: any) { if (subscribeUUID) { // 订阅的 const currentRule = WebsiteSubscribeRule.getSubscribeRule(subscribeUUID, uuid)!; Reflect.set(currentRule.data, key, value); WebsiteSubscribeRule.updateSubscribeRule(subscribeUUID, currentRule); } else { // 本地的 const currentRule = that.getRule(uuid) ?? addData(); Reflect.set(currentRule.data, key, value); that.updateRule(currentRule); } }, setAll(data: any) { if (subscribeUUID) { // 订阅的 const currentRule = WebsiteSubscribeRule.getSubscribeRule(subscribeUUID, uuid)!; currentRule.data = data; return WebsiteSubscribeRule.updateSubscribeRule(subscribeUUID, currentRule); } else { // 本地的 const currentRule = that.getRule(uuid) ?? addData(); currentRule.data = data; return that.updateRule(currentRule); } }, }; }; const $fragment = document.createDocumentFragment(); // 启用 const enable_template = UISwitch("启用", "enable", true); Reflect.set(enable_template.props!, PROPS_STORAGE_API, generateStorageApi(data)); const $enable = panelHandlerComponents.createSectionContainerItem_switch(enable_template).$el; // 规则名称 const name_template = UIInput("规则名称", "name", "", "", void 0, "必填"); Reflect.set(name_template.props!, PROPS_STORAGE_API, generateStorageApi(data)); const $name = panelHandlerComponents.createSectionContainerItem_input(name_template).$el; // 匹配网址 const url_template = UIInput("匹配网址", "url", "", "", void 0, "必填,可正则"); Reflect.set(url_template.props!, PROPS_STORAGE_API, generateStorageApi(data)); const $data_url = panelHandlerComponents.createSectionContainerItem_input(url_template).$el; // 覆盖设置 const coverSetting_template = UIButton( "覆盖设置", "", "自定义", void 0, false, false, "primary", (event) => { DOMUtils.preventEvent(event); // 先获取总设置和所有规则的content配置 const originPanelContentConfig = [...PanelContent.getConfig(0), ...NetDiskRule.getRulePanelContent()]; // 新配置,原始直接覆盖是浅复制 // let newPanelContentConfig = utils.assign( // [], // originPanelContentConfig, // true // ) as PopsPanelContentConfig[]; const newPanelContentConfig = deepCopy(originPanelContentConfig); // console.log(newPanelContentConfig); // 迭代遍历form配置,进行updateStorageApi /** 迭代遍历 */ const iterativeTraversal = function (configList: PopsPanelContentConfig["views"]) { configList.forEach((configItem) => { if (typeof configItem?.props === "object" && Reflect.has(configItem.props, PROPS_STORAGE_API)) { // 替换存储配置 const panelStorageApi = generatePanelStorageApi(data.uuid); Reflect.set(configItem.props, PROPS_STORAGE_API, panelStorageApi); } const childViews = (configItem).views; if (childViews && Array.isArray(childViews)) { // 存在子配置forms iterativeTraversal(childViews); } }); }; for (let index = 0; index < newPanelContentConfig.length; index++) { const leftContentConfigItem = newPanelContentConfig[index]; if (!leftContentConfigItem.views) { // 不存在forms continue; } if ( typeof leftContentConfigItem.afterRender === "function" && leftContentConfigItem?.id.toString().startsWith("netdisk-panel-config-") ) { // 覆盖左侧的afterRender leftContentConfigItem.afterRender = (__data) => { const ruleKey = Reflect.get(__data.asideConfig.attributes!, "data-key"); const enableKey = NetDiskRuleDataKEY.function.enable(ruleKey); if (subscribeUUID) { const subscribeRule = WebsiteSubscribeRule.getSubscribeRule(subscribeUUID, data.uuid)!; __data.$asideLiElement.setAttribute("data-function-enable", subscribeRule.data[enableKey] ?? true); } else { __data.$asideLiElement.setAttribute( "data-function-enable", isEdit ? WebsiteRule.getRuleDataValue(data.uuid, enableKey, true) : (data.data[enableKey] ?? true) ); } }; } if ( typeof leftContentConfigItem.attributes === "object" && leftContentConfigItem.views != null && ATTRIBUTE_KEY in leftContentConfigItem.attributes ) { /** 规则键 */ const ruleKey = leftContentConfigItem.attributes[ATTRIBUTE_KEY]; const custom_accessCode_enable_template = UISwitch( "启用", WebsiteRuleDataKey.features.customAccessCodeEnable(ruleKey), false, void 0, "启用后将允许执行下面的功能", void 0 ); // 覆盖存储api Reflect.set( custom_accessCode_enable_template.props!, PROPS_STORAGE_API, generatePanelStorageApi(data.uuid) ); const custom_accessCode_template = UIInput( "自定义访问码", WebsiteRuleDataKey.features.customAccessCode(ruleKey), "", "让获取的到的链接的访问码都为自定义的访问码", void 0, "请输入自定义访问码" ); // 覆盖存储api Reflect.set(custom_accessCode_template.props!, PROPS_STORAGE_API, generatePanelStorageApi(data.uuid)); const custom_accessCode_container: PopsPanelContainerConfig = { text: "额外功能", type: "container", views: [custom_accessCode_enable_template, custom_accessCode_template], }; if (leftContentConfigItem.views.length) { // 添加到第一个后面 leftContentConfigItem.views.splice(1, 0, custom_accessCode_container); } else { leftContentConfigItem.views.push(custom_accessCode_container); } } // 循环左侧容器内存储的右侧配置项 const rightContentConfigList = leftContentConfigItem.views; if (rightContentConfigList && Array.isArray(rightContentConfigList)) { iterativeTraversal(rightContentConfigList); } } // 然后显示出来 NetDiskPops.panel( { title: { text: `覆盖设置`, position: "center", }, content: newPanelContentConfig, btn: { close: { enable: true, callback(evtConfig) { evtConfig.close(); }, }, }, mask: { clickCallBack(continueExec) { continueExec(); }, }, only: false, class: "whitesevPopSetting", style: /*css*/ ` ${panelIndexCSS} ${panelSettingCSS} // 隐藏顶部的图标 .netdisk-custom-rule-edit, .netdisk-custom-rule-delete, // 隐藏快捷键设置菜单,因为这个是全局唯一的 .netdisk-panel-forms-shortcut-keys-deepMenu{ display: none !important; }`, }, NetDiskView.$config.viewSizeConfig.settingView ); }, void 0 ); const $coverSetting_template = panelHandlerComponents.createSectionContainerItem_button(coverSetting_template).$el; // 数据 const storeData_template = UIButton("存储的数据", "", "查看/编辑", void 0, false, false, "primary", () => { const $alert = NetDiskPops.alert( { title: { text: storeData_template.text, position: "center", }, content: { text: /*html*/ ` `, html: true, }, btn: { ok: { text: "保存", callback(evtConfig) { const dataText = DOMUtils.val($textarea); try { const __data__ = JSON.parse(dataText); data.data = __data__; const panelStorageApi = generatePanelStorageApi(data.uuid); const flag = panelStorageApi.setAll(__data__); if (flag) { Qmsg.success("保存成功"); evtConfig.close(); } else { Qmsg.error("保存失败"); } } catch (error: any) { Qmsg.error(error.message); } }, }, }, mask: { clickEvent: { toClose: false, toHide: false, }, }, height: "auto", style: /*css*/ ` .pops-content textarea { --textarea-bd-color: #dcdfe6; display: inline-block; resize: vertical; padding: 5px 15px; margin: 0; line-height: normal; box-sizing: border-box; border: 0; border-radius: 0; outline: none; -webkit-appearance: none; -moz-appearance: none; appearance: none; background: none; width: 100%; height: 100%; appearance: none; resize: none; } .pops-content textarea{ height: 500px; } .pops-content textarea:focus { --textarea-bd-color: #3677f0; } .pops-content textarea:hover { --textarea-bd-color: #c0c4cc; } `, }, { Mobile: PanelUISize.setting, PC: PanelUISize.setting, } ); const $textarea = $alert.$shadowRoot.querySelector("textarea")!; DOMUtils.val($textarea, CommonUtil.toStr(data.data)); }); const $storeData = panelHandlerComponents.createSectionContainerItem_button(storeData_template).$el; $fragment.append($enable, $name, $data_url, $coverSetting_template, $storeData); return $fragment; }; const ruleEditSubmitHandler = ($form: HTMLFormElement, isEdit: boolean, editData?: WebsiteRuleOption) => { // 提交表单 const $ulist_li = $form.querySelectorAll(".rule-form-ulist > li"); const data: WebsiteRuleOption = addData(); if (isEdit) { data.uuid = editData!.uuid; const allData = this.getAllRule(); const findValue = allData.find((item) => item.uuid === data.uuid); if (findValue) { data.data = findValue.data; } } const $ulist_li_list = Array.from($ulist_li); for (let i = 0; i < $ulist_li_list.length; i++) { const $li = $ulist_li_list[i]; const viewConfig = Reflect.get($li, panelHandlerComponents.$data.nodeStoreConfigKey); const attrs = Reflect.get(viewConfig, "attributes"); const storageApi = Reflect.get($li, PROPS_STORAGE_API); const key = Reflect.get(attrs, ATTRIBUTE_KEY); if (key == null) { continue; } const defaultValue = Reflect.get(attrs, ATTRIBUTE_DEFAULT_VALUE); const value = storageApi.get(key, defaultValue); if (Reflect.has(data, key)) { Reflect.set(data, key, value); } else if (Reflect.has(data.data, key)) { Reflect.set(data.data, key, value); } else { log.error(`${key}不在数据中`); } } if (data.name == null || data.name.trim() === "") { Qmsg.error("规则名称不能为空"); return { success: false, data: data, }; } if (data.url.trim() === "") { Qmsg.error("匹配网址不能为空"); return { success: false, data: data, }; } if (isEdit) { return { success: this.updateRule(data), data: data, }; } else { return { success: this.addRule(data), data: data, }; } }; const rulePanelViewOption: RulePanelContentOption = { id: "website-rule", title: "网站规则", ruleOption: { btnControls: { add: { enable: true, }, filter: { enable: true, option: [ { name: "全部", value: "", filterCallBack() { return true; }, }, { name: "已启用", value: "enable", filterCallBack(data) { return data.enable; }, }, { name: "未启用", value: "notEnable", filterCallBack(data) { return !data.enable; }, }, { name: "在当前网址生效", value: "workInCurrentUrl", filterCallBack: (data) => { return this.checkRuleMatch(data); }, }, ], inputOption: [ { name: "规则名", value: "name", filterCallBack(data, searchText) { const name = data.name; if (typeof name === "string") { return Boolean(name.match(searchText)); } else { return false; } }, }, { name: "网址", value: "url", filterCallBack(data, searchText) { return Boolean(data.url.match(searchText)); }, }, ], }, clearAll: { enable: true, callback: () => { this.deleteAllRule(); }, }, import: { enable: true, callback: (updateView) => { this.importRule(() => { updateView(); }); }, }, export: { enable: true, callback: () => { this.exportRule(SCRIPT_NAME + "-网站规则.json", SCRIPT_NAME + "-网站规则-订阅模式.json"); }, }, ruleEnable: { enable: true, getEnable(data) { return data.enable; }, callback: (data, enable) => { data.enable = enable; this.updateRule(data); }, }, ruleEdit: { enable: true, getView: ruleEditHandler, onsubmit: ruleEditSubmitHandler, }, ruleDelete: { enable: true, deleteCallBack: (data) => { return this.deleteRule(data.uuid); }, }, }, data: () => { return this.getAllRule(); }, getAddData: () => { return addData(); }, getData: (data) => { let allData = this.getAllRule(); let findValue = allData.find((item) => item.uuid === data.uuid); return findValue ?? data; }, getDataItemName: (data) => { return data["name"] ?? data.url; }, updateData: (data) => { return this.updateRule(data); }, deleteData: (data) => { this.$data.isShowEditView = false; return this.deleteRule(data.uuid); }, }, subscribe: { enable: true, data() { return WebsiteSubscribeRule.getAllSubscribe(); }, getData: (data) => { let findValue = WebsiteSubscribeRule.getSubscribe(data.uuid); return findValue ?? data; }, getDataItemName(subscribeOption) { return /*html*/ ` `; }, addData: (data) => { return WebsiteSubscribeRule.addSubscribe(data); }, updateData: (data) => { return WebsiteSubscribeRule.updateSubscribe(data); }, deleteData: (data) => { return WebsiteSubscribeRule.deleteSubscribe(data); }, btnControls: { add: { enable: true, }, filter: { enable: true, option: [ { name: "全部", value: "", filterCallBack() { return true; }, }, { name: "已启用", value: "enable", filterCallBack(data) { return data.data.enable; }, }, { name: "未启用", value: "notEnable", filterCallBack(data) { return !data.data.enable; }, }, ], inputOption: [ { name: "标题", value: "name", filterCallBack(data, searchText) { let flag = false; if (typeof data.data.title === "string") { flag = Boolean(data.data.title.match(searchText)); } if (!flag && typeof data.subscribeData.title === "string") { flag = Boolean(data.subscribeData.title.match(searchText)); } return flag; }, }, { name: "订阅地址", value: "url", filterCallBack(data, searchText) { return Boolean(data.data.url.match(searchText)); }, }, ], }, clearAll: { enable: true, callback: () => { WebsiteSubscribeRule.deleteAllSubscribe(); }, }, ruleEnable: { enable: true, getEnable(data) { return data.data.enable; }, async callback(data, enable) { data.data.enable = enable; WebsiteSubscribeRule.updateSubscribe(data); }, }, ruleEdit: { enable: true, callback: (option) => { let subscribeUUID = option.ruleData.uuid; option.enterDeepMenu({ headerTitle: // 自己重新命名的 option.ruleData.data.title || // 订阅的规则自带的 option.ruleData.subscribeData.title || // 订阅的链接 option.ruleData.data.url, data() { let currentData = WebsiteSubscribeRule.getSubscribe(subscribeUUID); return currentData?.subscribeData?.ruleData ?? option.ruleData.subscribeData.ruleData; }, getData(data) { let currentData = WebsiteSubscribeRule.getSubscribeRule(subscribeUUID, data.uuid); return currentData ?? data; }, getDataItemName(data) { return data.name ?? data.url; }, addData() { // TODO return true; }, updateData(data) { return WebsiteSubscribeRule.updateSubscribeRule(subscribeUUID, data); }, deleteData(data) { return WebsiteSubscribeRule.deleteSubscribeRule(subscribeUUID, data); }, btnControls: { filter: { enable: true, option: [ { name: "全部", value: "", filterCallBack() { return true; }, }, { name: "已启用", value: "enable", filterCallBack(data) { return data.enable; }, }, { name: "未启用", value: "notEnable", filterCallBack(data) { return !data.enable; }, }, ], inputOption: [ { name: "规则名", value: "name", filterCallBack(data, searchText) { const name = data.name; if (typeof name === "string") { return Boolean(name.match(searchText)); } else { return false; } }, }, { name: "网址", value: "url", filterCallBack(data, searchText) { return Boolean(data.url.match(searchText)); }, }, ], }, clearAll: { enable: true, callback: () => { WebsiteSubscribeRule.clearSubscribe(subscribeUUID); }, }, ruleEnable: { enable: true, getEnable(data) { return data.enable; }, callback(data, enable) { data.enable = enable; WebsiteSubscribeRule.updateSubscribeRule(subscribeUUID, data); }, }, ruleEdit: { enable: true, getView: (data, isEdit) => { return ruleEditHandler(data, isEdit, subscribeUUID); }, onsubmit: ruleEditSubmitHandler, }, ruleDelete: { enable: true, deleteCallBack(data) { return WebsiteSubscribeRule.deleteSubscribeRule(subscribeUUID, data); }, }, }, }); return false; }, }, ruleDelete: { enable: true, deleteCallBack: (data) => { return WebsiteSubscribeRule.deleteSubscribe(data); }, }, import: { enable: true, callback(updateView) { WebsiteSubscribeRule.importSubscribe(() => { updateView(); }); }, }, export: { enable: true, callback() { WebsiteSubscribeRule.exportSubscribe(SCRIPT_NAME + "-网站规则-订阅.json"); }, }, }, getSubscribeInfo: WebsiteSubscribeRule.getSubscribeInfo.bind(WebsiteSubscribeRule), }, }; return rulePanelViewOption; }, /** * 添加单个规则 */ addRule(rule: WebsiteRuleOption) { const allRule = this.getAllRule(); allRule.push(rule); WebsiteRuleStorageApi.set(this.$data.STORAGE_KEY, allRule); return true; }, /** * 根据uuid获取单个规则的数据 * @param uuid */ getRule(uuid: string) { const findValue = this.getAllRule().find((rule) => rule.uuid === uuid); if (findValue) { return findValue; } // 未找到符合的 // 看看是否是来自订阅的规则 const findSubscribeRule = WebsiteSubscribeRule.getAllSubscribeRule().find((rule) => { return rule.uuid === uuid; }); return findSubscribeRule; }, /** * 根据uuid获取单个规则的存储数据 * @param uuid */ getRuleData(uuid: string | WebsiteRuleOption) { if (typeof uuid === "string") { return this.getRule(uuid)!.data; } else { return uuid.data; } }, /** * 根据uuid获取单个规则的存储数据的值 * @param uuid * @param key 键 * @param defaultValue 默认值 */ getRuleDataValue(uuid: string, key: string, defaultValue: T) { const ruleData = this.getRuleData(uuid); return (ruleData && Reflect.get(ruleData, key)) ?? defaultValue; }, /** * 更新单个规则 * @param rule */ updateRule(rule: WebsiteRuleOption) { const allRule = this.getAllRule(); let flag = false; for (let index = 0; index < allRule.length; index++) { const localRule = allRule[index]; if (localRule.uuid === rule.uuid) { // uuid相同,确定为同一个规则 allRule[index] = rule; flag = true; break; } } if (flag) { WebsiteRuleStorageApi.set(this.$data.STORAGE_KEY, allRule); } else { // 未找到符合的 // 看看是否是来自订阅的 const findSubscribeRule = WebsiteSubscribeRule.getAllSubscribeRule().find((it) => { return it.uuid === rule.uuid; }); if (findSubscribeRule) { flag = WebsiteSubscribeRule.updateSubscribeRule(rule.subscribeUUID!, rule); } } return flag; }, /** * 删除单个规则 * @param uuid 整个规则或者规则的uuid */ deleteRule(uuid: string | WebsiteRuleOption) { const allRule = this.getAllRule(); let flag = false; const needDeleteRuleUUID = typeof uuid === "string" ? uuid : uuid.uuid; for (let index = 0; index < allRule.length; index++) { const localRule = allRule[index]; if (localRule.uuid === needDeleteRuleUUID) { allRule.splice(index, 1); flag = true; break; } } if (flag) { WebsiteRuleStorageApi.set(this.$data.STORAGE_KEY, allRule); } else { const findSubscribeRule = WebsiteSubscribeRule.getAllSubscribeRule().find((it) => { return it.uuid === needDeleteRuleUUID; }); if (findSubscribeRule) { flag = WebsiteSubscribeRule.deleteSubscribeRule(findSubscribeRule.subscribeUUID!, findSubscribeRule); } } return flag; }, /** * 清空所有规则 */ deleteAllRule() { WebsiteRuleStorageApi.delete(this.$data.STORAGE_KEY); }, /** * 获取所有规则 */ getAllRule(): WebsiteRuleOption[] { const allRule = WebsiteRuleStorageApi.get(this.$data.STORAGE_KEY, []); return allRule; }, /** * 校验规则是否在对应的url中执行 * @returns * + true 匹配 * + false 未匹配 */ checkRuleMatch(rule: WebsiteRuleOption, url = window.location.href) { const matchRegExp = new RegExp(rule.url, "gi"); return Boolean(url.match(matchRegExp)); }, /** * 根据url获取匹配的规则 * @param [filterUnEnable=true] (默认true)是否去除未启用的规则 * @param [url=window.location.href] (默认当前url)需要匹配的url */ getUrlMatchedRule(filterUnEnable = true, url: string = window.location.href) { let allRule = this.getAllRule(); const allSubscribeRule = WebsiteSubscribeRule.getAllSubscribeRule(true); allRule = allRule.concat(allSubscribeRule); const matchedRule = allRule.filter((rule) => { if (filterUnEnable && !rule.enable) { return false; } return this.checkRuleMatch(rule, url); }); return matchedRule; }, /** * 导出规则 */ exportRule(fileName = "rule.json", subscribeFileName = "rule-subscribe.json") { const $alert = NetDiskPops.alert({ title: { text: "请选择导出方式", position: "center", }, content: { text: /*html*/ `
导出规则
导出订阅规则
`, html: true, }, btn: { ok: { enable: false }, close: { enable: true, callback(details) { details.close(); }, }, }, mask: { enable: true }, drag: true, width: PanelUISize.info.width, height: PanelUISize.info.height, style: /*css*/ ` .btn-control{ display: inline-block; margin: 10px; padding: 10px; border: 1px solid #ccc; border-radius: 5px; cursor: pointer; } .btn-control:hover{ color: #409eff; border-color: #c6e2ff; background-color: #ecf5ff; } `, }); /** 仅导出规则 */ let $onlyExportRuleList = $alert.$shadowRoot.querySelector( ".btn-control[data-mode='only-export-rule-list']" )!; /** 导出为订阅规则 */ let $exportToSubscribe = $alert.$shadowRoot.querySelector( ".btn-control[data-mode='export-to-subscribe']" )!; /** * 导出文件 */ let exportFile = (__fileName__: string, __data__: any) => { let blob = new Blob([JSON.stringify(__data__, null, 4)]); let blobUrl = window.URL.createObjectURL(blob); let $a = document.createElement("a"); $a.href = blobUrl; $a.download = __fileName__; $a.click(); setTimeout(() => { window.URL.revokeObjectURL(blobUrl); }, 1500); }; // 仅导出规则 DOMUtils.on($onlyExportRuleList, "click", (event) => { DOMUtils.preventEvent(event); try { let allRule = this.getAllRule(); if (allRule.length === 0) { Qmsg.warning("规则为空,无需导出"); return; } exportFile(fileName, allRule); $alert.close(); } catch (error: any) { Qmsg.error(error.toString(), { consoleLogContent: true }); } }); // 导出为订阅规则 DOMUtils.on($exportToSubscribe, "click", (event) => { DOMUtils.preventEvent(event); const that = this; $alert.close(); try { let allRule = this.getAllRule(); if (allRule.length === 0) { Qmsg.warning("规则为空,无需导出"); return; } let panelHandlerComponents = pops.fn.PanelHandlerComponents(); /** * 自定义存储api的配置 * @param uuid */ let generateStorageApi = function (data: any) { return { get(key: string, defaultValue: any) { return data[key] ?? defaultValue; }, set(key: string, value: any) { data[key] = value; WebsiteRuleStorageApi.set(that.$data.EXPORT_CONFIG_KEY, data); }, }; }; /** * 按下导出的按钮的回调 */ let exportCallBack = () => { let configData = WebsiteRuleStorageApi.get["subscribeData"]>>( this.$data.EXPORT_CONFIG_KEY, {} ); if (configData?.title === "" || configData.title == null) { Qmsg.error("订阅标题不能为空"); return; } if (configData.version == null) { Qmsg.error("版本号不能为空"); return; } else { configData.version = Number(configData.version); } if (configData.homePage == null) { configData.homePage = void 0; } configData.lastModified = Date.now(); configData.ruleData = this.getAllRule(); exportFile(subscribeFileName, configData); $exportSubscribeDialog.close(); }; let $exportSubscribeDialog = NetDiskPops.alert({ title: { text: "请填写导出配置", position: "center", }, content: { text: /*html*/ ` `, html: true, }, btn: { ok: { enable: true, text: "导出", callback() { exportCallBack(); }, }, close: { enable: true, callback(details) { details.close(); }, }, }, mask: { enable: true, }, drag: true, width: PanelUISize.info.width, height: PanelUISize.info.height, style: /*css*/ ` ${pops.config.cssText.panelCSS} .pops-alert-content li{ list-style-type: none; display: flex; align-items: center; justify-content: space-between; margin: 10px; } `, }); let $content = $exportSubscribeDialog.$shadowRoot.querySelector(".pops-alert-content")!; let configData = WebsiteRuleStorageApi.get["subscribeData"]>>( this.$data.EXPORT_CONFIG_KEY, {} ); // 订阅名称 let title_template = UIInput("订阅标题", "title", ""); Reflect.set(title_template.props!, PROPS_STORAGE_API, generateStorageApi(configData)); let $title = panelHandlerComponents.createSectionContainerItem_input(title_template).$el; // 版本号 let version_template = UIInput("版本号", "version", ""); Reflect.set(version_template.props!, PROPS_STORAGE_API, generateStorageApi(configData)); let $version = panelHandlerComponents.createSectionContainerItem_input(version_template).$el; // 主页地址 let homePage_template = UIInput("主页地址", "homePage", "", "", void 0, "选填"); Reflect.set(homePage_template.props!, PROPS_STORAGE_API, generateStorageApi(configData)); let $homePage = panelHandlerComponents.createSectionContainerItem_input(homePage_template).$el; DOMUtils.append($content, $title); DOMUtils.append($content, $version); DOMUtils.append($content, $homePage); } catch (error: any) { Qmsg.error(error.toString(), { consoleLogContent: true }); } }); }, /** * 导入规则 * @param importEndCallBack 导入完毕后的回调 */ importRule(importEndCallBack?: () => void) { const $alert = NetDiskPops.alert({ title: { text: "请选择导入方式", position: "center", }, content: { text: /*html*/ `
本地导入
网络导入
剪贴板导入
`, html: true, }, btn: { ok: { enable: false }, close: { enable: true, callback(details) { details.close(); }, }, }, mask: { enable: true }, drag: true, width: PanelUISize.info.width, height: PanelUISize.info.height, style: /*css*/ ` .btn-control{ display: inline-block; margin: 10px; padding: 10px; border: 1px solid #ccc; border-radius: 5px; cursor: pointer; } .btn-control:hover{ color: #409eff; border-color: #c6e2ff; background-color: #ecf5ff; }`, }); /** 本地导入 */ const $local = $alert.$shadowRoot.querySelector(".btn-control[data-mode='local']")!; /** 网络导入 */ const $network = $alert.$shadowRoot.querySelector(".btn-control[data-mode='network']")!; /** 剪贴板导入 */ const $clipboard = $alert.$shadowRoot.querySelector(".btn-control[data-mode='clipboard']")!; /** * 将获取到的规则更新至存储 */ const updateRuleToStorage = (data: any[]) => { let allData = this.getAllRule(); let addNewData: typeof allData = []; for (let index = 0; index < data.length; index++) { const dataItem = data[index]; let findIndex = allData.findIndex((it) => it.uuid === dataItem.uuid); if (findIndex !== -1) { // 存在相同的uuid的规则 // 不做处理 } else { // 追加 addNewData.push(dataItem); } } allData = allData.concat(addNewData); WebsiteRuleStorageApi.set(this.$data.STORAGE_KEY, allData); Qmsg.success(`共 ${data.length} 条规则,新增 ${addNewData.length} 条`); importEndCallBack?.(); }; /** * @param subscribeText 订阅文件文本 */ const importFile = (subscribeText: string) => { return new Promise((resolve) => { const data = utils.toJSON(subscribeText); if (!Array.isArray(data)) { log.error(data); Qmsg.error("导入失败,格式不符合(不是数组)", { consoleLogContent: true, }); resolve(false); return; } if (!data.length) { Qmsg.error("导入失败,解析出的数据为空", { consoleLogContent: true, }); resolve(false); return; } updateRuleToStorage(data); resolve(true); }); }; // 本地导入 DOMUtils.on($local, "click", (event) => { DOMUtils.preventEvent(event); $alert.close(); const $input = DOMUtils.createElement("input", { type: "file", accept: ".json", }); DOMUtils.on($input, ["propertychange", "input"], () => { if (!$input.files?.length) { return; } const uploadFile = $input.files![0]; const fileReader = new FileReader(); fileReader.onload = () => { importFile(fileReader.result as string); }; fileReader.readAsText(uploadFile, "UTF-8"); }); $input.click(); }); // 网络导入 DOMUtils.on($network, "click", (event) => { DOMUtils.preventEvent(event); $alert.close(); const $prompt = NetDiskPops.prompt({ title: { text: "网络导入", position: "center", }, content: { text: "", placeholder: "请填写URL", focus: true, }, btn: { close: { enable: true, callback(details) { details.close(); }, }, ok: { text: "导入", callback: async (eventDetails) => { const url = eventDetails.text; if (utils.isNull(url)) { Qmsg.error("请填入完整的url"); return; } const $loading = Qmsg.loading("正在获取配置..."); const response = await httpx.get(url, { allowInterceptConfig: false, }); $loading.close(); if (!response.status) { log.error(response); Qmsg.error("获取配置失败", { consoleLogContent: true }); return; } const flag = await importFile(response.data.responseText); if (!flag) { return; } eventDetails.close(); }, }, cancel: { enable: false, }, }, mask: { enable: true }, drag: true, width: PanelUISize.info.width, height: "auto", }); const $promptInput = $prompt.$shadowRoot.querySelector("input")!; const $promptOk = $prompt.$shadowRoot.querySelector(".pops-prompt-btn-ok")!; DOMUtils.on($promptInput, ["input", "propertychange"], () => { const value = DOMUtils.val($promptInput); if (value === "") { DOMUtils.attr($promptOk, "disabled", "true"); } else { DOMUtils.removeAttr($promptOk, "disabled"); } }); DOMUtils.onKeyboard($promptInput, "keydown", (keyName, keyValue, otherCodeList) => { if (keyName === "Enter" && otherCodeList.length === 0) { const value = DOMUtils.val($promptInput); if (value !== "") { DOMUtils.emit($promptOk, "click"); } } }); DOMUtils.emit($promptInput, "input"); }); // 剪贴板导入 DOMUtils.on($clipboard, "click", async (event) => { DOMUtils.preventEvent(event); $alert.close(); const clipboardInfo = await utils.getClipboardInfo(); if (clipboardInfo.error != null) { Qmsg.error(clipboardInfo.error.toString()); return; } if (clipboardInfo.content.trim() === "") { Qmsg.warning("获取到的剪贴板内容为空"); return; } const flag = await importFile(clipboardInfo.content); if (!flag) { return; } }); }, };