diff --git a/resource/i18n/en.json b/resource/i18n/en.json index 52f017af6..59f179108 100644 --- a/resource/i18n/en.json +++ b/resource/i18n/en.json @@ -34,7 +34,9 @@ "export": "Export", "import": "Import", "share": "Share", - "actionConfirm": "Are you sure you want to do this?" + "actionConfirm": "Are you sure you want to do this?", + "importFailed": "Import failed", + "importSuccess": "Import success" }, "topbar": { "title": "@:(app.name)", @@ -534,7 +536,9 @@ "pages": "Applicable page", "enable": "Enable", "action": "Action" - } + }, + "importNameDuplicate": "The name [{name}] already exists. Please re-enter the new name:", + "invalidPlugin": "Invalid plugin" } }, "sites": { diff --git a/resource/i18n/zh-CN.json b/resource/i18n/zh-CN.json index 816eef69d..e62a07479 100644 --- a/resource/i18n/zh-CN.json +++ b/resource/i18n/zh-CN.json @@ -34,7 +34,9 @@ "export": "导出", "import": "导入", "share": "分享", - "actionConfirm": "确认要进行此操作吗?" + "actionConfirm": "确认要进行此操作吗?", + "importFailed": "导入失败", + "importSuccess": "已成功导入" }, "topbar": { "title": "@:(app.name)", @@ -534,7 +536,9 @@ "pages": "适用页面", "enable": "启用", "action": "操作" - } + }, + "importNameDuplicate": "该名称【{name}】已存在,请重新输入新的名称:", + "invalidPlugin": "无效的插件" } }, "sites": { diff --git a/src/options/views/settings/SitePlugins/Index.vue b/src/options/views/settings/SitePlugins/Index.vue index 4a520260d..eb55ca452 100644 --- a/src/options/views/settings/SitePlugins/Index.vue +++ b/src/options/views/settings/SitePlugins/Index.vue @@ -14,6 +14,23 @@ remove {{$t('common.remove')}} + + + + + + folder_open + {{$t('settings.sites.index.importConfig')}} + + + + + + {{ errorMsg }} + {{ successMsg }} @@ -119,7 +139,9 @@ import AddItem from "./Add.vue"; import EditItem from "./Edit.vue"; import { filters } from "@/service/filters"; -import { PPF } from "../../../../service/public"; +import { PPF } from "@/service/public"; +import FileSaver from "file-saver"; + export default Vue.extend({ components: { AddItem, @@ -145,7 +167,12 @@ export default Vue.extend({ readonly: false } as any, dialogRemoveConfirm: false, - plugins: [] as any + plugins: [] as any, + fileImport: null as any, + errorMsg: "", + haveError: false, + haveSuccess: false, + successMsg: "" }; }, methods: { @@ -244,8 +271,104 @@ export default Vue.extend({ this.plugins = plugins; } }, + + clearMessage() { + this.successMsg = ""; + this.errorMsg = ""; + }, + + /** + * 导出插件 + */ share(item: Plugin) { - console.log(item); + let fileName = + (this.site.host || this.site.name) + "-plugin-" + item.name + ".json"; + + const blob = new Blob([JSON.stringify(item)], { + type: "text/plain" + }); + FileSaver.saveAs(blob, fileName); + }, + /** + * 导入配置文件 + */ + importConfig() { + this.fileImport.click(); + }, + + importConfigFile(event: Event) { + this.clearMessage(); + let inputDOM: any = event.srcElement; + if (inputDOM.files.length > 0 && inputDOM.files[0].name.length > 0) { + for (let index = 0; index < inputDOM.files.length; index++) { + const file = inputDOM.files[index]; + const r = new FileReader(); + r.onload = (e: any) => { + try { + const result = JSON.parse(e.target.result); + this.importPlugin(result); + } catch (error) { + console.log(error); + this.errorMsg = this.$t("common.importFailed").toString(); + } + }; + r.onerror = () => { + this.errorMsg = this.$t("settings.backup.loadError").toString(); + }; + r.readAsText(file); + } + + inputDOM.value = ""; + } + }, + + /** + * 导入插件信息 + */ + importPlugin(source: Plugin) { + if ( + !( + source.name && + source.id && + source.isCustom && + source.pages && + source.pages.length > 0 + ) + ) { + this.errorMsg = this.$t( + "settings.sitePlugins.index.invalidPlugin" + ).toString(); + return; + } + const plugin = this.getPlugin(source); + if (plugin) { + const newName = window.prompt( + this.$t("settings.sitePlugins.index.importNameDuplicate", { + name: plugin.name + }).toString() + ); + + if (newName) { + source.name = newName; + this.importPlugin(source); + return; + } else { + return; + } + } + this.addItem(source); + + this.successMsg = this.$t("common.importSuccess").toString(); + }, + + getPlugin(source: Plugin) { + const plugins = this.site.plugins; + if (plugins && plugins.length > 0) { + return plugins.find((item: Plugin) => { + return item.name === source.name; + }); + } + return null; } }, created() { @@ -255,6 +378,13 @@ export default Vue.extend({ this.reloadPlugins(host); } }, + mounted() { + this.fileImport = this.$refs.fileImport; + this.fileImport.addEventListener("change", this.importConfigFile); + }, + beforeDestroy() { + this.fileImport.removeEventListener("change", this.importConfigFile); + }, computed: { headers(): Array { return [ @@ -280,6 +410,14 @@ export default Vue.extend({ } ]; } + }, + watch: { + successMsg() { + this.haveSuccess = this.successMsg != ""; + }, + errorMsg() { + this.haveError = this.errorMsg != ""; + } } }); diff --git a/src/options/views/settings/Sites/Index.vue b/src/options/views/settings/Sites/Index.vue index 9bb9237fc..d1b46ea83 100644 --- a/src/options/views/settings/Sites/Index.vue +++ b/src/options/views/settings/Sites/Index.vue @@ -16,7 +16,13 @@ - + folder_open @@ -466,8 +472,13 @@ export default Vue.extend({ const file = restoreFile.files[index]; const r = new FileReader(); r.onload = (e: any) => { - const result = JSON.parse(e.target.result); - this.importSite(result); + try { + const result = JSON.parse(e.target.result); + this.importSite(result); + } catch (error) { + console.log(error); + this.errorMsg = this.$t("common.importFailed").toString(); + } }; r.onerror = () => { this.errorMsg = this.$t("settings.backup.loadError").toString();