diff --git a/plugin/auto_number.js b/plugin/auto_number.js
index f53b96f5..aae32e94 100644
--- a/plugin/auto_number.js
+++ b/plugin/auto_number.js
@@ -1,7 +1,6 @@
-(() => {
- const config = global._pluginUtils.getPluginSetting("auto_number");
-
- const base_css = `
+class autoNumberPlugin extends global._basePlugin {
+ beforeProcess = () => {
+ this.base_css = `
#write { counter-reset: write-h2 Figures Tables Fences; }
h1 { counter-reset: write-h2 Figures Tables Fences; }
h2 { counter-reset: write-h3 Figures Tables Fences; }
@@ -24,7 +23,7 @@
}
}
`
- const content_css = `
+ this.content_css = `
#write h2:before {
counter-increment: write-h2;
content: counter(write-h2) ". ";
@@ -77,7 +76,7 @@
line-height: inherit;
}`
- const side_bar_css = `
+ this.side_bar_css = `
.outline-content { counter-reset: outline-h2; }
.outline-h1 { counter-reset: outline-h2; }
.outline-h2 { counter-reset: outline-h3; }
@@ -110,7 +109,7 @@
content: counter(outline-h2) "." counter(outline-h3) "." counter(outline-h4) "." counter(outline-h5) "." counter(outline-h6) " ";
}`
- const toc_css = `
+ this.toc_css = `
.md-toc-content { counter-reset: toc-h2; }
.md-toc-h1 { counter-reset: toc-h2; }
.md-toc-h2 { counter-reset: toc-h3; }
@@ -143,33 +142,33 @@
content: counter(toc-h2) "." counter(toc-h3) "." counter(toc-h4) "." counter(toc-h5) "." counter(toc-h6) " ";
}`
- const image_css = `
+ this.image_css = `
#write p span.md-image.md-img-loaded::after {
counter-increment: Figures;
- content: "${config.NAME.image} " counter(write-h2) "-" counter(Figures);
+ content: "${this.config.NAMES.image} " counter(write-h2) "-" counter(Figures);
font-family: monospace;
display: block;
text-align: center;
margin: 4px 0;
}`
- const table_css = `
+ this.table_css = `
#write figure.table-figure::after {
counter-increment: Tables;
- content: "${config.NAME.table} " counter(write-h2) "-" counter(Tables);
+ content: "${this.config.NAMES.table} " counter(write-h2) "-" counter(Tables);
font-family: monospace;
display: block;
text-align: center;
margin: 4px 0;
}`
- const fence_css = `
+ this.fence_css = `
#write .md-fences {
margin-bottom: 2.4em;
}
#write .md-fences::after {
counter-increment: Fences;
- content: "${config.NAME.fence} " counter(write-h2) "-" counter(Fences);
+ content: "${this.config.NAMES.fence} " counter(write-h2) "-" counter(Fences);
position: absolute;
width: 100%;
text-align: center;
@@ -178,43 +177,21 @@
font-size: 1.1em;
z-index: 9;
}`
-
- const removeStyle = () => {
- const ele = document.getElementById(config.ID);
- ele && ele.parentElement && ele.parentElement.removeChild(ele);
- }
-
- const getStyleString = () => {
- return [
- base_css,
- (config.ENABLE_CONTENT) ? content_css : "",
- (config.ENABLE_SIDE_BAR) ? side_bar_css : "",
- (config.ENABLE_TOC) ? toc_css : "",
- (config.ENABLE_IMAGE) ? image_css : "",
- (config.ENABLE_TABLE) ? table_css : "",
- (config.ENABLE_FENCE) ? fence_css : "",
- ].join("\n")
}
- const insertStyle = toggle => {
- if (toggle) {
- config[toggle] = !config[toggle];
- removeStyle();
- }
-
- const css = getStyleString();
- global._pluginUtils.insertStyle(config.ID, css);
+ style = () => {
+ const textID = this.config.ID;
+ const text = this.getResultStyle();
+ return {textID, text}
}
- insertStyle();
-
- if (config.ENABLE_WHEN_EXPORT) {
- const decoMixin = {
+ init = () => {
+ this.decoMixin = {
inExport: false,
beforeExport: (...args) => {
this.inExport = true;
- args[0].extraCss = `body {font-variant-ligatures: no-common-ligatures;} ` + getStyleString();
+ args[0].extraCss = `body {font-variant-ligatures: no-common-ligatures;} ` + this.getStyleString();
},
afterGetHeaderMatrix: headers => {
@@ -261,84 +238,114 @@
}
}
- global._pluginUtils.decorate(
- () => (File && File.editor && File.editor.export && File.editor.export.exportToHTML),
- File.editor.export,
- "exportToHTML",
- decoMixin.beforeExport,
- null
- );
- global._pluginUtils.decorate(
- () => (File && File.editor && File.editor.library && File.editor.library.outline
- && File.editor.library.outline.getHeaderMatrix),
- File.editor.library.outline,
- "getHeaderMatrix",
- null,
- decoMixin.afterGetHeaderMatrix
- );
+ this.callArgs = [
+ {
+ arg_name: "禁用/启用大纲自动编号",
+ arg_value: "set_outline"
+ },
+ {
+ arg_name: "禁用/启用正文自动编号",
+ arg_value: "set_content"
+ },
+ {
+ arg_name: "禁用/启用TOC自动编号",
+ arg_value: "set_toc"
+ },
+ {
+ arg_name: "禁用/启用表格自动编号",
+ arg_value: "set_table"
+ },
+ {
+ arg_name: "禁用/启用图片自动编号",
+ arg_value: "set_image"
+ },
+ {
+ arg_name: "禁用/启用代码块自动编号",
+ arg_value: "set_fence"
+ },
+ ];
+
+ this.callMap = {
+ disable: this.removeStyle,
+ enable: this.insertStyle,
+ set_outline: () => this.insertStyle("ENABLE_SIDE_BAR"),
+ set_content: () => this.insertStyle("ENABLE_CONTENT"),
+ set_toc: () => this.insertStyle("ENABLE_TOC"),
+ set_table: () => this.insertStyle("ENABLE_TABLE"),
+ set_image: () => this.insertStyle("ENABLE_IMAGE"),
+ set_fence: () => this.insertStyle("ENABLE_FENCE"),
+ }
}
- //////////////////////// 以下是声明式插件系统代码 ////////////////////////
- const callArgs = [
- {
- arg_name: "禁用/启用大纲自动编号",
- arg_value: "set_outline"
- },
- {
- arg_name: "禁用/启用正文自动编号",
- arg_value: "set_content"
- },
- {
- arg_name: "禁用/启用TOC自动编号",
- arg_value: "set_toc"
- },
- {
- arg_name: "禁用/启用表格自动编号",
- arg_value: "set_table"
- },
- {
- arg_name: "禁用/启用图片自动编号",
- arg_value: "set_image"
- },
- {
- arg_name: "禁用/启用代码块自动编号",
- arg_value: "set_fence"
- },
- ];
+ process = () => {
+ this.init();
- const dynamicCallArgsGenerator = () => {
+ if (this.config.ENABLE_WHEN_EXPORT) {
+ this.utils.decorate(
+ () => (File && File.editor && File.editor.export && File.editor.export.exportToHTML),
+ File.editor.export,
+ "exportToHTML",
+ this.decoMixin.beforeExport,
+ null
+ );
+ this.utils.decorate(
+ () => (File && File.editor && File.editor.library && File.editor.library.outline
+ && File.editor.library.outline.getHeaderMatrix),
+ File.editor.library.outline,
+ "getHeaderMatrix",
+ null,
+ this.decoMixin.afterGetHeaderMatrix
+ );
+ }
+ }
+
+ removeStyle = () => {
+ const ele = document.getElementById(this.config.ID);
+ ele && ele.parentElement && ele.parentElement.removeChild(ele);
+ }
+
+ getStyleString = () => {
+ return [
+ this.base_css,
+ (this.config.ENABLE_CONTENT) ? this.content_css : "",
+ (this.config.ENABLE_SIDE_BAR) ? this.side_bar_css : "",
+ (this.config.ENABLE_TOC) ? this.toc_css : "",
+ (this.config.ENABLE_IMAGE) ? this.image_css : "",
+ (this.config.ENABLE_TABLE) ? this.table_css : "",
+ (this.config.ENABLE_FENCE) ? this.fence_css : "",
+ ].join("\n")
+ }
+
+ getResultStyle = toggle => {
+ if (toggle) {
+ this.config[toggle] = !this.config[toggle];
+ this.removeStyle();
+ }
+
+ return this.getStyleString()
+ }
+
+ insertStyle = toggle => {
+ const css = this.getResultStyle(toggle);
+ this.utils.insertStyle(this.config.ID, css);
+ }
+
+ dynamicCallArgsGenerator = () => {
let arg_name = "启用";
let arg_value = "enable";
- if (!!document.getElementById(config.ID)) {
+ if (!!document.getElementById(this.config.ID)) {
arg_name = "禁用";
arg_value = "disable";
}
return [{arg_name, arg_value}]
}
- const callMap = {
- disable: removeStyle,
- enable: insertStyle,
- set_outline: () => insertStyle("ENABLE_SIDE_BAR"),
- set_content: () => insertStyle("ENABLE_CONTENT"),
- set_toc: () => insertStyle("ENABLE_TOC"),
- set_table: () => insertStyle("ENABLE_TABLE"),
- set_image: () => insertStyle("ENABLE_IMAGE"),
- set_fence: () => insertStyle("ENABLE_FENCE"),
- }
-
- const call = type => {
- const func = callMap[type];
+ call = type => {
+ const func = this.callMap[type];
func && func();
}
- module.exports = {
- call,
- callArgs,
- dynamicCallArgsGenerator,
- meta: {
- call
- }
- };
+}
- console.log("auto_number.js had been injected");
-})()
\ No newline at end of file
+module.exports = {
+ plugin: autoNumberPlugin
+};
\ No newline at end of file
diff --git a/plugin/collapse_paragraph.js b/plugin/collapse_paragraph.js
index 9b60a32a..b4d645d6 100644
--- a/plugin/collapse_paragraph.js
+++ b/plugin/collapse_paragraph.js
@@ -1,9 +1,8 @@
-(() => {
- const config = global._pluginUtils.getPluginSetting("collapse_paragraph");
-
- (() => {
- const css = `
- #write .${config.CLASS_NAME}::after {
+class collapseParagraphPlugin extends global._basePlugin {
+ style = () => {
+ const textID = "plugin-collapse-paragraph-style"
+ const text = `
+ #write .${this.config.CLASS_NAME}::after {
display: initial;
content: "{\\2026}" !important;
margin: 0 0.6rem;
@@ -11,29 +10,47 @@
color: white;
opacity: 0.6;
background-color: gray;
- }
- `;
- global._pluginUtils.insertStyle("plugin-collapse-paragraph-style", css);
- })()
+ }`;
+ return {textID, text}
+ }
- const callbackOtherPlugin = () => {
- const outlinePlugin = global._pluginUtils.getPlugin("outline");
- outlinePlugin && outlinePlugin.meta.refresh();
+ init = () => {
+ this.paragraphList = ["H1", "H2", "H3", "H4", "H5", "H6"];
+ this.dynamicUtil = {target: null}
}
- const paragraphList = ["H1", "H2", "H3", "H4", "H5", "H6"];
+ process = () => {
+ this.init();
- const toggle = (paragraph, display) => {
- const idx = paragraphList.indexOf(paragraph.tagName);
- const stop = paragraphList.slice(0, idx + 1);
+ document.getElementById("write").addEventListener("click", ev => {
+ if (!this.utils.metaKeyPressed(ev)) return;
+ const paragraph = ev.target.closest("h1, h2, h3, h4, h5, h6");
+ if (!paragraph) return;
+
+ document.activeElement.blur();
+ const collapsed = paragraph.classList.contains(this.config.CLASS_NAME);
+ const list = ev.altKey ? (ev.shiftKey ? this.findAllSiblings(paragraph) : this.findSiblings(paragraph)) : [paragraph];
+ list.forEach(ele => this.trigger(ele, collapsed));
+ this.callbackOtherPlugin();
+ })
+ }
+
+ callbackOtherPlugin = () => {
+ const outlinePlugin = this.utils.getPlugin("outline");
+ outlinePlugin && outlinePlugin.refresh();
+ }
+
+ toggle = (paragraph, display) => {
+ const idx = this.paragraphList.indexOf(paragraph.tagName);
+ const stop = this.paragraphList.slice(0, idx + 1);
let ele = paragraph.nextElementSibling;
while (ele && stop.indexOf(ele.tagName) === -1) {
- if (paragraphList.indexOf(ele.tagName) !== -1
- && ele.classList.contains(config.CLASS_NAME)
+ if (this.paragraphList.indexOf(ele.tagName) !== -1
+ && ele.classList.contains(this.config.CLASS_NAME)
&& display === "") {
ele.style.display = "";
- ele = toggle(ele, "none");
+ ele = this.toggle(ele, "none");
continue
}
@@ -43,27 +60,26 @@
return ele;
}
-
- const trigger = (paragraph, collapsed) => {
+ trigger = (paragraph, collapsed) => {
if (collapsed) {
- paragraph.classList.remove(config.CLASS_NAME);
- toggle(paragraph, "");
+ paragraph.classList.remove(this.config.CLASS_NAME);
+ this.toggle(paragraph, "");
} else {
- paragraph.classList.add(config.CLASS_NAME);
- toggle(paragraph, "none");
+ paragraph.classList.add(this.config.CLASS_NAME);
+ this.toggle(paragraph, "none");
}
}
- const rollback = start => {
- if (!document.querySelector(`#write > .${config.CLASS_NAME}`)) return;
+ rollback = start => {
+ if (!document.querySelector(`#write > .${this.config.CLASS_NAME}`)) return;
let ele = start.closest("#write > [cid]");
const pList = [];
while (ele) {
- const idx = paragraphList.indexOf(ele.tagName);
+ const idx = this.paragraphList.indexOf(ele.tagName);
if (idx !== -1) {
- if (pList.length === 0 || (pList[pList.length - 1].idx > idx && ele.classList.contains(config.CLASS_NAME))) {
+ if (pList.length === 0 || (pList[pList.length - 1].idx > idx && ele.classList.contains(this.config.CLASS_NAME))) {
pList.push({ele, idx})
if (pList[pList.length - 1].idx === 0) break;
}
@@ -73,14 +89,14 @@
if (pList.length > 0) {
for (let i = pList.length - 1; i >= 0; i--) {
- trigger(pList[i].ele, true);
+ this.trigger(pList[i].ele, true);
}
}
}
- const findSiblings = paragraph => {
- const idx = paragraphList.indexOf(paragraph.tagName);
- const stop = paragraphList.slice(0, idx);
+ findSiblings = paragraph => {
+ const idx = this.paragraphList.indexOf(paragraph.tagName);
+ const stop = this.paragraphList.slice(0, idx);
const result = [paragraph];
["previousElementSibling", "nextElementSibling"].forEach(direction => {
@@ -96,27 +112,13 @@
return result;
}
- const findAllSiblings = paragraph => document.querySelectorAll(`#write ${paragraph.tagName}`);
+ findAllSiblings = paragraph => document.querySelectorAll(`#write ${paragraph.tagName}`);
- document.getElementById("write").addEventListener("click", ev => {
- if (!global._pluginUtils.metaKeyPressed(ev)) return;
- const paragraph = ev.target.closest("h1, h2, h3, h4, h5, h6");
- if (!paragraph) return;
-
- document.activeElement.blur();
- const collapsed = paragraph.classList.contains(config.CLASS_NAME);
- const list = ev.altKey ? (ev.shiftKey ? findAllSiblings(paragraph) : findSiblings(paragraph)) : [paragraph];
- list.forEach(ele => trigger(ele, collapsed));
- callbackOtherPlugin();
- })
-
- //////////////////////// 以下是声明式插件系统代码 ////////////////////////
- const dynamicUtil = {target: null}
- const dynamicCallArgsGenerator = anchorNode => {
+ dynamicCallArgsGenerator = anchorNode => {
const target = anchorNode.closest("#write h1,h2,h3,h4,h5,h6");
if (!target) return;
- dynamicUtil.target = target;
+ this.dynamicUtil.target = target;
return [
{
@@ -134,7 +136,7 @@
]
}
- const callArgs = [
+ callArgs = [
{
arg_name: "折叠全部章节",
arg_value: "collapse_all"
@@ -145,48 +147,40 @@
},
];
- const dynamicCall = type => {
- if (!dynamicUtil.target) return;
+ dynamicCall = type => {
+ if (!this.dynamicUtil.target) return;
- const collapsed = dynamicUtil.target.classList.contains(config.CLASS_NAME);
+ const collapsed = this.dynamicUtil.target.classList.contains(this.config.CLASS_NAME);
let list;
if (type === "call_current") {
- list = [dynamicUtil.target];
+ list = [this.dynamicUtil.target];
} else if (type === "call_siblings") {
- list = findSiblings(dynamicUtil.target);
+ list = this.findSiblings(this.dynamicUtil.target);
} else if (type === "call_all_siblings") {
- list = findAllSiblings(dynamicUtil.target);
+ list = this.findAllSiblings(this.dynamicUtil.target);
}
if (list) {
- list.forEach(ele => trigger(ele, collapsed));
+ list.forEach(ele => this.trigger(ele, collapsed));
}
}
- const call = type => {
+ call = type => {
if (type === "collapse_all") {
- for (let i = paragraphList.length - 1; i >= 0; i--) {
- document.getElementsByTagName(paragraphList[i]).forEach(ele => trigger(ele, false));
+ for (let i = this.paragraphList.length - 1; i >= 0; i--) {
+ document.getElementsByTagName(this.paragraphList[i]).forEach(ele => this.trigger(ele, false));
}
} else if (type === "expand_all") {
- paragraphList.forEach(tag => document.getElementsByTagName(tag).forEach(ele => trigger(ele, true)));
+ this.paragraphList.forEach(tag => document.getElementsByTagName(tag).forEach(ele => this.trigger(ele, true)));
} else {
- dynamicCall(type);
+ this.dynamicCall(type);
}
- callbackOtherPlugin();
+ this.callbackOtherPlugin();
}
+}
- module.exports = {
- call,
- callArgs,
- dynamicCallArgsGenerator,
- meta: {
- call,
- trigger,
- rollback,
- }
- };
+module.exports = {
+ plugin: collapseParagraphPlugin
+};
- console.log("collapse_paragraph.js had been injected");
-})()
\ No newline at end of file
diff --git a/plugin/commander.js b/plugin/commander.js
index 82465fd0..7d451d52 100644
--- a/plugin/commander.js
+++ b/plugin/commander.js
@@ -1,14 +1,16 @@
-(() => {
- const config = global._pluginUtils.getPluginSetting("commander");
- const SHELL = {
- CMD_BASH: "cmd/bash",
- POWER_SHELL: "powershell",
- GIT_BASH: "gitbash",
- WSL: "wsl",
- };
+class commanderPlugin extends global._basePlugin {
+ beforeProcess() {
+ this.SHELL = {
+ CMD_BASH: "cmd/bash",
+ POWER_SHELL: "powershell",
+ GIT_BASH: "gitbash",
+ WSL: "wsl",
+ };
+ }
- (() => {
- const modal_css = `
+ style = () => {
+ const textID = "plugin-commander-style"
+ const text = `
#typora-commander {
position: fixed;
top: 30%;
@@ -91,23 +93,24 @@
#typora-commander-form input:focus, pre:focus {
outline: 0
}
- `
- global._pluginUtils.insertStyle("plugin-commander-style", modal_css);
+ `;
+ return {textID, text}
+ }
+ html = () => {
const windowOption = (File.isMac) ? `` : `
-
-
-
- `;
- const builtin = config.BUILTIN.map(ele => ``).join("");
- const builtinSelect = !config.USE_BUILTIN ? "" : ``;
+
+
+ `;
+ const builtin = this.config.BUILTIN.map(ele => ``).join("");
+ const builtinSelect = !this.config.USE_BUILTIN ? "" : ``;
const div = `
-
+
${builtinSelect}
@@ -119,30 +122,116 @@
const searchPanel = document.getElementById("md-searchpanel");
searchPanel.parentNode.insertBefore(modal, searchPanel.nextSibling);
- if (!config.USE_BUILTIN) {
+ if (!this.config.USE_BUILTIN) {
document.getElementById('typora-commander').style.width = "500px";
document.querySelector("#typora-commander-form input").style.width = "80%";
document.querySelector("#typora-commander-form .typora-commander-commit").style.left = "375px";
}
- })()
+ }
+
+ hotkey = () => {
+ return [{
+ hotkey: this.config.HOTKEY,
+ callback: this.call,
+ }]
+ }
+
+ init = () => {
+ this.modal = {
+ modal: document.getElementById('typora-commander'),
+ input: document.querySelector("#typora-commander-form input"),
+ shellSelect: document.querySelector("#typora-commander-form .typora-commander-shell"),
+ builtinSelect: document.querySelector("#typora-commander-form .typora-commander-builtin"),
+ commit: document.querySelector("#typora-commander-form .typora-commander-commit"),
+ output: document.querySelector(".typora-commander-output"),
+ pre: document.querySelector(".typora-commander-output pre"),
+ }
+
+ this.arg_value_prefix = "call_builtin-";
+ this.callArgs = [{arg_name: "显示/隐藏", arg_value: "show"}];
+ this.config.BUILTIN.forEach(builtin => {
+ if (builtin.name) {
+ this.callArgs.push({
+ arg_name: `${builtin.name}`,
+ arg_value: this.arg_value_prefix + builtin.name
+ })
+ }
+ });
+ }
+
+ process = () => {
+ this.init();
+
+ // 提供不同入口,让鼠标操作的用户不必切换回键盘操作
+ this.modal.commit.addEventListener("click", ev => {
+ this.commit();
+ ev.stopPropagation();
+ ev.preventDefault();
+ }, true);
+
+ this.modal.input.addEventListener("input", () => {
+ const cmd = this.modal.input.value.trim();
+ if (cmd) {
+ this.modal.commit.style.display = "block";
+ } else {
+ this.modal.commit.style.display = "none";
+ this.modal.builtinSelect.value = "";
+ }
+ })
+
+ this.modal.shellSelect.addEventListener("change", () => this.modal.input.focus());
+
+ this.modal.modal.addEventListener("keydown", ev => {
+ switch (ev.key) {
+ case "Enter":
+ const input = ev.target.closest("input")
+ if (input) {
+ this.commit();
+ ev.stopPropagation();
+ ev.preventDefault();
+ }
+ break
+ case "Escape":
+ ev.stopPropagation();
+ ev.preventDefault();
+ this.modal.modal.style.display = "none";
+ break
+ case "Tab":
+ const targetClass = this.config.USE_BUILTIN ? ".typora-commander-builtin" : ".typora-commander-shell";
+ const target = ev.target.closest(targetClass);
+ if (target) {
+ ev.stopPropagation();
+ ev.preventDefault();
+ this.modal.input.focus();
+ }
+ break
+ }
+ })
+
+ if (this.config.USE_BUILTIN) {
+ this.modal.builtinSelect.addEventListener("change", () => {
+ const option = this.modal.builtinSelect.options[this.modal.builtinSelect.selectedIndex];
+ this.modal.shellSelect.value = option.getAttribute("shell");
+ this.modal.input.value = option.value;
+ this.modal.input.dispatchEvent(new CustomEvent('input'));
+ this.modal.input.focus();
+ })
+ }
+
+ if (this.config.ALLOW_DRAG) {
+ this.utils.dragFixedModal(this.modal.input, this.modal.modal);
+ }
- const modal = {
- modal: document.getElementById('typora-commander'),
- input: document.querySelector("#typora-commander-form input"),
- shellSelect: document.querySelector("#typora-commander-form .typora-commander-shell"),
- builtinSelect: document.querySelector("#typora-commander-form .typora-commander-builtin"),
- commit: document.querySelector("#typora-commander-form .typora-commander-commit"),
- output: document.querySelector(".typora-commander-output"),
- pre: document.querySelector(".typora-commander-output pre"),
}
- const convertPath = (path, shell) => {
+
+ convertPath = (path, shell) => {
if (File.isMac) {
return path
}
switch (shell) {
- case SHELL.WSL:
- case SHELL.GIT_BASH:
+ case this.SHELL.WSL:
+ case this.SHELL.GIT_BASH:
path = path.replace(/\\/g, "/");
const tempList = path.split(":");
if (tempList.length !== 2) {
@@ -150,50 +239,50 @@
}
const disk = tempList[0].toLowerCase();
const remain = tempList[1];
- return (shell === SHELL.GIT_BASH) ? `/${disk}${remain}` : `/mnt/${disk}${remain}`
- case SHELL.CMD_BASH:
- case SHELL.POWER_SHELL:
+ return (shell === this.SHELL.GIT_BASH) ? `/${disk}${remain}` : `/mnt/${disk}${remain}`
+ case this.SHELL.CMD_BASH:
+ case this.SHELL.POWER_SHELL:
default:
return path
}
}
- const getFilePath = global._pluginUtils.getFilePath;
- const getFile = shell => convertPath(getFilePath(), shell);
- const getFolder = shell => convertPath(global._pluginUtils.Package.Path.dirname(getFilePath()), shell);
- const getMountFolder = shell => convertPath(File.getMountFolder(), shell);
+ getFilePath = this.utils.getFilePath;
+ getFile = shell => this.convertPath(this.getFilePath(), shell);
+ getFolder = shell => this.convertPath(this.utils.Package.Path.dirname(this.getFilePath()), shell);
+ getMountFolder = shell => this.convertPath(File.getMountFolder(), shell);
- const replaceArgs = (cmd, shell) => {
- const file = getFile(shell);
- const folder = getFolder(shell);
- const mount = getMountFolder(shell);
+ replaceArgs = (cmd, shell) => {
+ const file = this.getFile(shell);
+ const folder = this.getFolder(shell);
+ const mount = this.getMountFolder(shell);
cmd = cmd.replace(/\$f/g, `"${file}"`);
cmd = cmd.replace(/\$d/g, `"${folder}"`);
cmd = cmd.replace(/\$m/g, `"${mount}"`);
return cmd
}
- const getShellCommand = env => {
+ getShellCommand = env => {
switch (env) {
- case SHELL.GIT_BASH:
+ case this.SHELL.GIT_BASH:
return `bash.exe -c`
- case SHELL.POWER_SHELL:
+ case this.SHELL.POWER_SHELL:
return `powershell /C`
- case SHELL.WSL:
+ case this.SHELL.WSL:
return `wsl.exe -e bash -c`
default:
return File.isMac ? `bash -c` : `cmd /C`;
}
}
- const exec = (cmd, shell, resolve, reject) => {
- const _shell = getShellCommand(shell);
- const _cmd = replaceArgs(cmd, shell);
- global._pluginUtils.Package.ChildProcess.exec(
+ exec = (cmd, shell, resolve, reject) => {
+ const _shell = this.getShellCommand(shell);
+ const _cmd = this.replaceArgs(cmd, shell);
+ this.utils.Package.ChildProcess.exec(
`chcp 65001 | ${_shell} "${_cmd}"`,
{
encoding: 'utf8',
- cwd: getFolder(),
+ cwd: this.getFolder(),
},
(err, stdout, stderr) => {
if (err || stderr.length) {
@@ -206,142 +295,59 @@
})
}
- const showStdout = stdout => {
- modal.output.style.display = "block";
- modal.pre.classList.remove("error");
- modal.pre.textContent = stdout;
+ showStdout = stdout => {
+ this.modal.output.style.display = "block";
+ this.modal.pre.classList.remove("error");
+ this.modal.pre.textContent = stdout;
}
- const showStdErr = stderr => {
- showStdout(stderr);
- modal.pre.classList.add("error");
+ showStdErr = stderr => {
+ this.showStdout(stderr);
+ this.modal.pre.classList.add("error");
}
- const silentExec = (cmd, shell) => exec(cmd, shell, null, null);
- const errorExec = (cmd, shell) => exec(cmd, shell, null, showStdErr);
- const alwaysExec = (cmd, shell) => exec(cmd, shell, showStdout, showStdErr);
+ silentExec = (cmd, shell) => this.exec(cmd, shell, null, null);
+ errorExec = (cmd, shell) => this.exec(cmd, shell, null, this.showStdErr);
+ alwaysExec = (cmd, shell) => this.exec(cmd, shell, this.showStdout, this.showStdErr);
- const commit = () => {
- const cmd = modal.input.value;
+ commit = () => {
+ const cmd = this.modal.input.value;
if (!cmd) {
- showStdErr("command is empty");
+ this.showStdErr("command is empty");
return
}
- const option = modal.shellSelect.options[modal.shellSelect.selectedIndex];
+ const option = this.modal.shellSelect.options[this.modal.shellSelect.selectedIndex];
const shell = option.value;
- alwaysExec(cmd, shell);
+ this.alwaysExec(cmd, shell);
}
- // 提供不同入口,让鼠标操作的用户不必切换回键盘操作
- modal.commit.addEventListener("click", ev => {
- commit();
- ev.stopPropagation();
- ev.preventDefault();
- }, true);
-
- modal.input.addEventListener("input", ev => {
- const cmd = modal.input.value.trim();
- if (cmd) {
- modal.commit.style.display = "block";
- } else {
- modal.commit.style.display = "none";
- modal.builtinSelect.value = "";
- }
- })
-
- modal.shellSelect.addEventListener("change", ev => modal.input.focus());
-
- modal.modal.addEventListener("keydown", ev => {
- switch (ev.key) {
- case "Enter":
- const input = ev.target.closest("input")
- if (input) {
- commit();
- ev.stopPropagation();
- ev.preventDefault();
- }
- break
- case "Escape":
- ev.stopPropagation();
- ev.preventDefault();
- modal.modal.style.display = "none";
- break
- case "Tab":
- const targetClass = config.USE_BUILTIN ? ".typora-commander-builtin" : ".typora-commander-shell";
- const target = ev.target.closest(targetClass);
- if (target) {
- ev.stopPropagation();
- ev.preventDefault();
- modal.input.focus();
- }
- break
- }
- })
-
- if (config.USE_BUILTIN) {
- modal.builtinSelect.addEventListener("change", ev => {
- const option = modal.builtinSelect.options[modal.builtinSelect.selectedIndex];
- modal.shellSelect.value = option.getAttribute("shell");
- modal.input.value = option.value;
- modal.input.dispatchEvent(new CustomEvent('input'));
- modal.input.focus();
- })
- }
-
- if (config.ALLOW_DRAG) {
- global._pluginUtils.dragFixedModal(modal.input, modal.modal);
- }
-
- const arg_value_prefix = "call_builtin-";
-
- const quickExec = (cmd, shell) => {
- switch (config.QUICK_EXEC_SHOW) {
+ quickExec = (cmd, shell) => {
+ switch (this.config.QUICK_EXEC_SHOW) {
case "always":
- return alwaysExec(cmd, shell)
+ return this.alwaysExec(cmd, shell)
case "error":
- return errorExec(cmd, shell)
+ return this.errorExec(cmd, shell)
case "silent":
- return silentExec(cmd, shell)
+ return this.silentExec(cmd, shell)
}
}
- const callArgs = [{arg_name: "显示/隐藏", arg_value: "show"}];
- config.BUILTIN.forEach(builtin => {
- if (builtin.name) {
- callArgs.push({
- arg_name: `${builtin.name}`,
- arg_value: arg_value_prefix + builtin.name
- })
- }
- });
-
- const call = (type = "show") => {
+ call = (type = "show") => {
if (type === "show") {
- if (modal.modal.style.display === "block") {
- modal.modal.style.display = "none";
+ if (this.modal.modal.style.display === "block") {
+ this.modal.modal.style.display = "none";
} else {
- modal.modal.style.display = "block";
- modal.input.select();
+ this.modal.modal.style.display = "block";
+ this.modal.input.select();
}
- } else if (type.startsWith(arg_value_prefix)) {
- const name = type.slice(arg_value_prefix.length);
- const builtin = config.BUILTIN.find(builtin => builtin.name === name);
- builtin && quickExec(builtin.cmd, builtin.shell);
+ } else if (type.startsWith(this.arg_value_prefix)) {
+ const name = type.slice(this.arg_value_prefix.length);
+ const builtin = this.config.BUILTIN.find(builtin => builtin.name === name);
+ builtin && this.quickExec(builtin.cmd, builtin.shell);
}
}
+}
- global._pluginUtils.registerWindowHotkey(config.HOTKEY, call);
-
- module.exports = {
- call,
- callArgs,
- meta: {
- call,
- silentExec,
- errorExec,
- alwaysExec,
- }
- };
-
- console.log("commander.js had been injected");
-})()
\ No newline at end of file
+module.exports = {
+ plugin: commanderPlugin
+};
\ No newline at end of file
diff --git a/plugin/datatables/index.js b/plugin/datatables/index.js
index 12f0fa00..f13f5665 100644
--- a/plugin/datatables/index.js
+++ b/plugin/datatables/index.js
@@ -1,9 +1,7 @@
-(() => {
- (() => {
- const cssFilepath = global._pluginUtils.joinPath("./plugin/datatables/resource/datatables.min.css");
- global._pluginUtils.insertStyleFile("plugin-datatables-common-style", cssFilepath);
-
- const css = `
+class datatablesPlugin extends global._basePlugin {
+ style = () => {
+ const textID = "plugin-datatables-custom-style";
+ const text = `
#write figure select,
#write figure input {
border: 1px solid #ddd;
@@ -25,27 +23,29 @@
.dataTables_wrapper .dataTables_info {
padding-top: 0.25em;
- }
- `
- global._pluginUtils.insertStyle("plugin-datatables-custom-style", css);
+ }`;
- const jsFilepath = global._pluginUtils.joinPath("./plugin/datatables/resource/datatables.min.js");
- $.getScript(`file:///${jsFilepath}`).then(() => console.log("datatables.min.js has inserted"));
- })()
+ const fileID = "plugin-datatables-common-style";
+ const file = "./plugin/datatables/resource/datatables.min.css";
+ return {textID, text, fileID, file}
+ }
- const config = global._pluginUtils.getPluginSetting("datatables");
+ html = () => {
+ const jsFilepath = this.utils.joinPath("./plugin/datatables/resource/datatables.min.js");
+ $.getScript(`file:///${jsFilepath}`).then(() => console.log("datatables.min.js has inserted"));
+ }
- const dataTablesConfig = (() => {
- const cfg = {
- paging: config.PAGING,
- ordering: config.ORDERING,
- searching: config.SEARCHING,
- pageLength: config.PAGE_LENGTH,
- scrollCollapse: config.SROLL_COLLAPSE,
+ init = () => {
+ this.dataTablesConfig = {
+ paging: this.config.PAGING,
+ ordering: this.config.ORDERING,
+ searching: this.config.SEARCHING,
+ pageLength: this.config.PAGE_LENGTH,
+ scrollCollapse: this.config.SROLL_COLLAPSE,
processing: true,
search: {
- caseInsensitive: config.CASE_INSENSITIVE,
- regex: config.REGEX,
+ caseInsensitive: this.config.CASE_INSENSITIVE,
+ regex: this.config.REGEX,
},
language: {
"processing": "处理中...",
@@ -70,26 +70,53 @@
"thousands": "."
}
};
-
- if (config.SCROLLY > 0) {
- cfg["scrollY"] = config.SCROLLY;
+ if (this.config.SCROLLY > 0) {
+ this.dataTablesConfig = this.config.SCROLLY;
}
- if (!config.DEFAULT_ORDER) {
- cfg["order"] = [];
+ if (!this.config.DEFAULT_ORDER) {
+ this.dataTablesConfig["order"] = [];
}
- return cfg
- })()
- let tableList = [];
+ this.tableList = [];
+
+ this.dynamicUtil = {target: null, uuid: ""}
+ }
+
+ process = () => {
+ this.init();
+
+ this.utils.decorateOpenFile(null, () => {
+ this.tableList.forEach(table => table.table.api().destroy());
+ this.tableList = [];
+ })
- const addTfoot = $table => {
- const th = $table.find("thead th");
- const list = [...th].map(ele => `${ele.textContent}: | `);
- const tfoot = `${list.join("")}
`;
- $table.append(tfoot);
+ this.utils.decorate(
+ () => (File && File.editor && File.editor.tableEdit && File.editor.tableEdit.showTableEdit),
+ File.editor.tableEdit,
+ "showTableEdit",
+ (...args) => {
+ if (!args[0]) return;
+ const table = args[0].find("table");
+ if (table.length === 0) return
+
+ const uuid = table.attr("table-uuid");
+ const idx = this.tableList.findIndex(table => table.uuid === uuid);
+ if (idx !== -1) {
+ return this.utils.stopCallError
+ }
+ },
+ null
+ )
}
- const appendFilter = dataTable => {
+ // addTfoot = $table => {
+ // const th = $table.find("thead th");
+ // const list = [...th].map(ele => `${ele.textContent}: | `);
+ // const tfoot = `${list.join("")}
`;
+ // $table.append(tfoot);
+ // }
+
+ appendFilter = dataTable => {
dataTable.columns().flatten().each(function (colIdx) {
const select = $("").appendTo(dataTable.column(colIdx).header()).on("change", function () {
dataTable.column(colIdx).search($(this).val()).draw();
@@ -101,27 +128,27 @@
})
}
- const newDataTable = target => {
+ newDataTable = target => {
const edit = target.parentElement.querySelector(".md-table-edit");
const $table = $(target);
const uuid = Math.random() + "";
$table.attr("table-uuid", uuid);
// addTfoot($table);
- const table = $table.dataTable(dataTablesConfig);
- appendFilter(table.api());
- tableList.push({uuid, table});
+ const table = $table.dataTable(this.dataTablesConfig);
+ this.appendFilter(table.api());
+ this.tableList.push({uuid, table});
edit && edit.parentNode.removeChild(edit);
return uuid
}
- const removeDataTable = uuid => {
- const idx = tableList.findIndex(table => table.uuid === uuid);
+ removeDataTable = uuid => {
+ const idx = this.tableList.findIndex(table => table.uuid === uuid);
if (idx !== -1) {
- const table = tableList[idx].table;
+ const table = this.tableList[idx].table;
const target = table[0];
table.api().destroy();
target.removeAttribute("table-uuid");
- tableList.splice(idx, 1);
+ this.tableList.splice(idx, 1);
target.querySelectorAll("th select").forEach(ele => ele.parentNode.removeChild(ele));
if (target) {
const $fig = $(target.parentElement);
@@ -130,36 +157,13 @@
}
}
- global._pluginUtils.decorateOpenFile(null, () => {
- tableList.forEach(table => table.table.api().destroy());
- tableList = [];
- })
-
- global._pluginUtils.decorate(
- () => (File && File.editor && File.editor.tableEdit && File.editor.tableEdit.showTableEdit),
- File.editor.tableEdit,
- "showTableEdit",
- (...args) => {
- const table = args[0].find("table");
- if (table.length === 0) return
-
- const uuid = table.attr("table-uuid");
- const idx = tableList.findIndex(table => table.uuid === uuid);
- if (idx !== -1) {
- return global._pluginUtils.stopCallError
- }
- },
- null
- )
-
- const dynamicUtil = {target: null, uuid: ""}
- const dynamicCallArgsGenerator = anchorNode => {
+ dynamicCallArgsGenerator = anchorNode => {
const table = anchorNode.closest("#write table.md-table");
if (!table) return;
const uuid = table.getAttribute("table-uuid");
- dynamicUtil.uuid = uuid;
- dynamicUtil.target = table;
+ this.dynamicUtil.uuid = uuid;
+ this.dynamicUtil.target = table;
let arg_name = "增强表格";
let arg_value = "convert_current";
@@ -170,26 +174,19 @@
return [{arg_name, arg_value}]
}
- const call = type => {
+ call = type => {
if (type === "convert_current") {
- if (dynamicUtil.target) {
- newDataTable(dynamicUtil.target);
+ if (this.dynamicUtil.target) {
+ this.newDataTable(this.dynamicUtil.target);
}
} else if (type === "rollback_current") {
- if (dynamicUtil.uuid) {
- removeDataTable(dynamicUtil.uuid);
+ if (this.dynamicUtil.uuid) {
+ this.removeDataTable(this.dynamicUtil.uuid);
}
}
}
+}
- module.exports = {
- call,
- dynamicCallArgsGenerator,
- meta: {
- newDataTable,
- removeDataTable
- }
- };
-
- console.log("datatables.js had been injected");
-})()
\ No newline at end of file
+module.exports = {
+ plugin: datatablesPlugin,
+};
diff --git a/plugin/export_enhance.js b/plugin/export_enhance.js
index 2ded8d01..db82bf5d 100644
--- a/plugin/export_enhance.js
+++ b/plugin/export_enhance.js
@@ -1,105 +1,110 @@
-(() => {
- const config = global._pluginUtils.getPluginSetting("export_enhance");
- const Path = global._pluginUtils.Package.Path;
- const tempFolder = global._pluginUtils.tempFolder; // i‘d like to shit here
-
- const isNetworkImage = src => /^https?|(ftp):\/\//.test(src);
-
- const getCurDir = () => {
- const filepath = global._pluginUtils.getFilePath();
- return Path.dirname(filepath)
- }
-
- const toBase64 = imagePath => {
- const bitmap = global._pluginUtils.Package.Fs.readFileSync(imagePath);
- const data = Buffer.from(bitmap).toString('base64');
- return `data:image;base64,${data}`;
- }
-
- const simplePromise = result => new Promise(resolve => resolve(result));
-
- const decoMixin = {
- regexp: new RegExp(``, "gs"),
- writeIdx: -1,
- imageMap: {}, // map src to localFileName, use for network image only
-
- init: () => {
- decoMixin.writeIdx = -1
- decoMixin.imageMap = {}
- },
-
- downloadAllImage: async (html) => {
- for await (let result of html.matchAll(decoMixin.regexp)) {
- if (result.length !== 2 || result.index < decoMixin.writeIdx || !isNetworkImage(result[1])) continue
- const src = result[1];
- if (!decoMixin.imageMap.hasOwnProperty(src)) { // single flight
- const filename = Math.random() + "_" + Path.basename(src);
- const {state} = JSBridge.invoke("app.download", src, tempFolder, filename);
- if (state === "completed") {
- decoMixin.imageMap[src] = filename;
+class exportEnhancePlugin extends global._basePlugin {
+ init = () => {
+ this.Path = this.utils.Package.Path;
+ this.tempFolder = this.utils.tempFolder; // i‘d like to shit here
+
+ this.decoMixin = {
+ regexp: new RegExp(``, "gs"),
+ writeIdx: -1,
+ imageMap: {}, // map src to localFileName, use for network image only
+
+ init: () => {
+ this.decoMixin.writeIdx = -1
+ this.decoMixin.imageMap = {}
+ },
+
+ downloadAllImage: async (html) => {
+ for (let result of html.matchAll(this.decoMixin.regexp)) {
+ if (result.length !== 2 || result.index < this.decoMixin.writeIdx || !this.isNetworkImage(result[1])) continue
+ const src = result[1];
+ if (!this.decoMixin.imageMap.hasOwnProperty(src)) { // single flight
+ const filename = Math.random() + "_" + this.Path.basename(src);
+ const {state} = await JSBridge.invoke("app.download", src, this.tempFolder, filename);
+ if (state === "completed") {
+ this.decoMixin.imageMap[src] = filename;
+ }
}
}
- }
- },
+ },
- afterExportToHtml: async (exportResult, ...args) => {
- if (!config.ENABLE) return exportResult;
+ afterExportToHtml: async (exportResult, ...args) => {
+ if (!this.config.ENABLE) return exportResult;
- decoMixin.init();
+ this.decoMixin.init();
- const exportConfig = args[0];
- if (!exportConfig || exportConfig["type"] !== "html" && exportConfig["type"] !== "html-plain") return exportResult;
+ const exportConfig = args[0];
+ if (!exportConfig || exportConfig["type"] !== "html" && exportConfig["type"] !== "html-plain") return exportResult;
- const html = await exportResult;
- decoMixin.writeIdx = html.indexOf(`id='write'`);
- if (decoMixin.writeIdx === -1) return simplePromise(html);
+ const html = await exportResult;
+ this.decoMixin.writeIdx = html.indexOf(`id='write'`);
+ if (this.decoMixin.writeIdx === -1) return this.simplePromise(html);
- if (config.DOWNLOAD_NETWORK_IMAGE) {
- await decoMixin.downloadAllImage(html)
- }
+ if (this.config.DOWNLOAD_NETWORK_IMAGE) {
+ await this.decoMixin.downloadAllImage(html);
+ }
- const dirname = getCurDir();
- const newHtml = html.replace(decoMixin.regexp, (origin, src, srcIdx) => {
- if (srcIdx < decoMixin.writeIdx) return origin;
-
- let result = origin;
- let imagePath;
- try {
- if (isNetworkImage(src)) {
- if (!config.DOWNLOAD_NETWORK_IMAGE || !decoMixin.imageMap.hasOwnProperty(src)) return origin
- const path = decoMixin.imageMap[src];
- imagePath = Path.join(tempFolder, path);
- } else {
- imagePath = Path.join(dirname, src);
+ const dirname = this.getCurDir();
+ const newHtml = html.replace(this.decoMixin.regexp, (origin, src, srcIdx) => {
+ if (srcIdx < this.decoMixin.writeIdx) return origin;
+
+ let result = origin;
+ let imagePath;
+ try {
+ if (this.isNetworkImage(src)) {
+ if (!this.config.DOWNLOAD_NETWORK_IMAGE || !this.decoMixin.imageMap.hasOwnProperty(src)) return origin
+ const path = this.decoMixin.imageMap[src];
+ imagePath = this.Path.join(this.tempFolder, path);
+ } else {
+ imagePath = this.Path.join(dirname, src);
+ }
+ const base64Data = this.toBase64(imagePath);
+ result = origin.replace(src, base64Data);
+ } catch (e) {
+ console.log("export error:", e);
}
- const base64Data = toBase64(imagePath);
- result = origin.replace(src, base64Data);
- } catch (e) {
- console.log("export error:", e);
- }
- return result;
- })
- return simplePromise(newHtml);
+ return result;
+ })
+ return this.simplePromise(newHtml);
+ }
}
}
- global._pluginUtils.decorate(
- () => (File && File.editor && File.editor.export && File.editor.export.exportToHTML),
- File.editor.export,
- "exportToHTML",
- null,
- decoMixin.afterExportToHtml,
- true,
- );
+ process = () => {
+ this.init();
+
+ this.utils.decorate(
+ () => (File && File.editor && File.editor.export && File.editor.export.exportToHTML),
+ File.editor.export,
+ "exportToHTML",
+ null,
+ this.decoMixin.afterExportToHtml,
+ true,
+ );
+ }
+
+ isNetworkImage = src => /^https?|(ftp):\/\//.test(src);
+
+ getCurDir = () => {
+ const filepath = this.utils.getFilePath();
+ return this.Path.dirname(filepath)
+ }
+
+ toBase64 = imagePath => {
+ const bitmap = this.utils.Package.Fs.readFileSync(imagePath);
+ const data = Buffer.from(bitmap).toString('base64');
+ return `data:image;base64,${data}`;
+ }
- const dynamicCallArgsGenerator = () => {
+ simplePromise = result => new Promise(resolve => resolve(result));
+
+ dynamicCallArgsGenerator = () => {
const call_args = [];
- if (config.DOWNLOAD_NETWORK_IMAGE) {
+ if (this.config.DOWNLOAD_NETWORK_IMAGE) {
call_args.push({arg_name: "导出HTML时不下载网络图片", arg_value: "dont_download_network_image"});
} else {
call_args.push({arg_name: "导出HTML时下载网络图片", arg_value: "download_network_image"});
}
- if (config.ENABLE) {
+ if (this.config.ENABLE) {
call_args.push({arg_name: "禁用", arg_value: "disable"});
} else {
call_args.push({arg_name: "启用", arg_value: "enable"})
@@ -108,25 +113,19 @@
return call_args
}
- const call = type => {
+ call = type => {
if (type === "download_network_image") {
- config.DOWNLOAD_NETWORK_IMAGE = true
+ this.config.DOWNLOAD_NETWORK_IMAGE = true
} else if (type === "dont_download_network_image") {
- config.DOWNLOAD_NETWORK_IMAGE = false
+ this.config.DOWNLOAD_NETWORK_IMAGE = false
} else if (type === "disable") {
- config.ENABLE = false
+ this.config.ENABLE = false
} else if (type === "enable") {
- config.ENABLE = true
+ this.config.ENABLE = true
}
}
+}
- module.exports = {
- call,
- dynamicCallArgsGenerator,
- meta: {
- call
- }
- };
-
- console.log("export_enhance.js had been injected");
-})()
\ No newline at end of file
+module.exports = {
+ plugin: exportEnhancePlugin
+};
\ No newline at end of file
diff --git a/plugin/fence_enhance.js b/plugin/fence_enhance.js
index bf6e2a1b..f9c9f991 100644
--- a/plugin/fence_enhance.js
+++ b/plugin/fence_enhance.js
@@ -1,21 +1,23 @@
-(() => {
- /* 1. Typora是延迟加载页面的,文件内容都是通过延迟执行的js写入document的,具体代码在frame.js中$__System.registerDynamic函数中。
- 2. 糟糕的是md-fences在frame.js中是很晚生成的,并且有清空innerHTML操作的,你必须等到frame.js执行完毕后才能执行你的脚本,使用onload,DOMContentLoaded,statechange什么的都不行。
- 否则你插入的标签都会被清空,一切白费。原因很简单:frame.js执行的时机很晚,你可以认为是一个在网页全部加载完毕后执行的Ajax请求。
- 3. 这里给出清空md-fences的函数链条,打个断点就知道了:
- restoreEditStateFromData -> refresh -> refreshUnder -> refreshEditor -> addCodeBlock -> b.addClass("ty-contain-cm").html("");
- 4. 解决方法有很多,比如:
- 1. 使用::before伪标签。既然标签会被清空,伪标签不就可以了么
- 2. 循环检测md-fences的状态,检测到全部加载完成后执行脚本。
- 5. 我选择的是装饰器。给上述逻辑链条的addCodeBlock函数注入一段after逻辑。
- 这样的好处是:不管是文件本身就存在的,还是用户编辑文件时新增的都可以自动执行脚本,不必整一个MutationObserver。
- 坏处是:绿皮
- */
- const config = global._pluginUtils.getPluginSetting("fence_enhance");
- let enableIndent = config.ENABLE_INDENT && !global._pluginUtils.isBetaVersion;
-
- (() => {
- const css = `
+/* 1. Typora是延迟加载页面的,文件内容都是通过延迟执行的js写入document的,具体代码在frame.js中$__System.registerDynamic函数中。
+ 2. 糟糕的是md-fences在frame.js中是很晚生成的,并且有清空innerHTML操作的,你必须等到frame.js执行完毕后才能执行你的脚本,使用onload,DOMContentLoaded,statechange什么的都不行。
+ 否则你插入的标签都会被清空,一切白费。原因很简单:frame.js执行的时机很晚,你可以认为是一个在网页全部加载完毕后执行的Ajax请求。
+ 3. 这里给出清空md-fences的函数链条,打个断点就知道了:
+ restoreEditStateFromData -> refresh -> refreshUnder -> refreshEditor -> addCodeBlock -> b.addClass("ty-contain-cm").html("");
+ 4. 解决方法有很多,比如:
+ 1. 使用::before伪标签。既然标签会被清空,伪标签不就可以了么
+ 2. 循环检测md-fences的状态,检测到全部加载完成后执行脚本。
+ 5. 我选择的是装饰器。给上述逻辑链条的addCodeBlock函数注入一段after逻辑。
+ 这样的好处是:不管是文件本身就存在的,还是用户编辑文件时新增的都可以自动执行脚本,不必整一个MutationObserver。
+ 坏处是:绿皮
+*/
+class fenceEnhancePlugin extends global._basePlugin {
+ beforeProcess = () => {
+ this.enableIndent = this.config.ENABLE_INDENT && !this.utils.isBetaVersion;
+ }
+
+ style = () => {
+ const textID = "plugin-fence-enhance-style";
+ const text = `
#write .md-fences .fence-enhance {
display: inline-flex;
position: absolute;
@@ -30,12 +32,130 @@
}
#write .fence-enhance .typora-copy-code, .typora-indent-code {
margin-left: .5em;
+ }`;
+ return {textID, text}
+ }
+
+ init = () => {
+ this.lastClickTime = 0;
+ this.badChars = [
+ "%E2%80%8B", // ZERO WIDTH SPACE \u200b
+ "%C2%A0", // NO-BREAK SPACE \u00A0
+ "%0A" // NO-BREAK SPACE \u0A
+ ];
+ this.replaceChars = ["", "%20", ""];
+ this.dynamicUtil = {target: null};
+ this.callArgs = [
+ {
+ arg_name: "自动隐藏/显示按钮",
+ arg_value: "set_auto_hide",
+ },
+ {
+ arg_name: "禁用/启用折叠按钮",
+ arg_value: "disable_or_enable_fold",
+ },
+ {
+ arg_name: "禁用/启用复制按钮",
+ arg_value: "disable_or_enable_copy",
+ },
+ {
+ arg_name: "总是折叠代码块",
+ arg_value: "fold_all",
+ },
+ {
+ arg_name: "总是展开代码块",
+ arg_value: "expand_all",
+ },
+ ];
+
+ if (this.enableIndent) {
+ this.callArgs.splice(2, 0, {
+ arg_name: "禁用/启用缩进调整按钮",
+ arg_value: "disable_or_enable_indent",
+ });
+ }
+
+ this.callMap = {
+ disable_or_enable_fold: () => {
+ this.config.ENABLE_FOLD = !this.config.ENABLE_FOLD;
+ if (!this.config.ENABLE_FOLD) {
+ document.querySelectorAll(".typora-fold-code.folded").forEach(ele => ele.click());
+ }
+ const display = (this.config.ENABLE_FOLD) ? "block" : "none";
+ document.querySelectorAll(".fence-enhance .typora-fold-code").forEach(ele => ele.style.display = display);
+ },
+ disable_or_enable_copy: () => {
+ this.config.ENABLE_COPY = !this.config.ENABLE_COPY;
+ const display = (this.config.ENABLE_COPY) ? "block" : "none";
+ document.querySelectorAll(".fence-enhance .typora-copy-code").forEach(ele => ele.style.display = display);
+ },
+ disable_or_enable_indent: () => {
+ this.enableIndent = !this.enableIndent;
+ const display = (this.enableIndent) ? "block" : "none";
+ document.querySelectorAll(".fence-enhance .typora-indent-code").forEach(ele => ele.style.display = display);
+ },
+ fold_all: () => {
+ document.querySelectorAll(".typora-fold-code:not(.folded)").forEach(ele => ele.click());
+ this.config.FOLD_DEFAULT = true;
+ },
+ expand_all: () => {
+ document.querySelectorAll(".typora-fold-code.folded").forEach(ele => ele.click());
+ this.config.FOLD_DEFAULT = false;
+ },
+ fold_current: () => this.foldFence(this.dynamicUtil.target),
+ copy_current: () => this.copyFence(this.dynamicUtil.target),
+ indent_current: () => this.indentFence(this.dynamicUtil.target),
+ set_auto_hide: () => {
+ this.config.AUTO_HIDE = !this.config.AUTO_HIDE;
+ const visibility = (this.config.AUTO_HIDE) ? "hidden" : "";
+ document.querySelectorAll(".fence-enhance").forEach(ele => ele.style.visibility = visibility);
+ }
+ }
+ }
+
+ process = () => {
+ this.init();
+
+ this.utils.decorateAddCodeBlock(null, (result, ...args) => {
+ const cid = args[0];
+ if (cid) {
+ const ele = document.querySelector(`#write .md-fences[cid=${cid}]`);
+ this.addEnhanceElement(ele);
+ }
+ })
+
+ document.getElementById("write").addEventListener("click", ev => {
+ const copy = ev.target.closest(".typora-copy-code");
+ const fold = ev.target.closest(".typora-fold-code");
+ const indent = ev.target.closest(".typora-indent-code");
+ if (!copy && !fold && !indent) return;
+
+ ev.preventDefault();
+ ev.stopPropagation();
+ document.activeElement.blur();
+
+ if (copy) {
+ this.copyCode(ev, copy);
+ } else if (fold) {
+ this.foldCode(ev, fold);
+ } else {
+ this.indentCode(ev, indent);
}
- `
- global._pluginUtils.insertStyle("plugin-fence-enhance-style", css);
- })()
+ })
- const createButton = (className, hint, iconClassName) => {
+ const config = this.config;
+ $("#write").on("mouseenter", ".md-fences", function () {
+ if (config.AUTO_HIDE) {
+ this.querySelector(".fence-enhance").style.visibility = "";
+ }
+ }).on("mouseleave", ".md-fences", function () {
+ if (config.AUTO_HIDE && !this.querySelector(".typora-fold-code.folded")) {
+ this.querySelector(".fence-enhance").style.visibility = "hidden";
+ }
+ })
+ }
+
+ createButton = (className, hint, iconClassName) => {
const button = document.createElement("div");
button.classList.add(className);
hint && button.setAttribute("ty-hint", hint);
@@ -45,86 +165,55 @@
return button
}
- const addEnhanceElement = fence => {
+ addEnhanceElement = fence => {
let enhance = fence.querySelector(".fence-enhance");
if (!enhance) {
enhance = document.createElement("div");
enhance.setAttribute("class", "fence-enhance");
- if (config.AUTO_HIDE) {
+ if (this.config.AUTO_HIDE) {
enhance.style.visibility = "hidden";
}
- let foldButton;
- if (config.ENABLE_FOLD) {
- foldButton = createButton("typora-fold-code", "折叠", "fa fa-minus");
- enhance.appendChild(foldButton);
+ const foldButton = this.createButton("typora-fold-code", "折叠", "fa fa-minus");
+ if (!this.config.ENABLE_FOLD) {
+ foldButton.style.display = "none";
}
- if (enableIndent) {
- const indentButton = createButton("typora-indent-code", "调整缩进", "fa fa-indent");
- enhance.appendChild(indentButton);
+
+ const indentButton = this.createButton("typora-indent-code", "调整缩进", "fa fa-indent");
+ if (!this.enableIndent) {
+ indentButton.style.display = "none";
}
- if (config.ENABLE_COPY) {
- const copyButton = createButton("typora-copy-code", "复制", "fa fa-clipboard");
- enhance.appendChild(copyButton);
+
+ const copyButton = this.createButton("typora-copy-code", "复制", "fa fa-clipboard");
+ if (!this.config.ENABLE_COPY) {
+ copyButton.style.display = "none";
}
+ enhance.appendChild(foldButton);
+ enhance.appendChild(indentButton);
+ enhance.appendChild(copyButton);
fence.appendChild(enhance);
- if (config.FOLD_DEFAULT && foldButton) {
+ if (this.config.FOLD_DEFAULT) {
foldButton.click();
}
}
}
- global._pluginUtils.decorateAddCodeBlock(null, (result, ...args) => {
- const cid = args[0];
- if (cid) {
- const ele = document.querySelector(`#write .md-fences[cid=${cid}]`);
- addEnhanceElement(ele);
- }
- })
-
- document.getElementById("write").addEventListener("click", ev => {
- const copy = ev.target.closest(".typora-copy-code");
- const fold = ev.target.closest(".typora-fold-code");
- const indent = ev.target.closest(".typora-indent-code");
- if (!copy && !fold && !indent) return;
-
- ev.preventDefault();
- ev.stopPropagation();
- document.activeElement.blur();
-
- if (copy) {
- copyCode(ev, copy);
- } else if (fold) {
- foldCode(ev, fold);
- } else {
- indentCode(ev, indent);
- }
- })
-
- let lastClickTime = 0;
- const badChars = [
- "%E2%80%8B", // ZERO WIDTH SPACE \u200b
- "%C2%A0", // NO-BREAK SPACE \u00A0
- "%0A" // NO-BREAK SPACE \u0A
- ];
- const replaceChars = ["", "%20", ""];
-
- const copyCode = (ev, copyButton) => {
- if (ev.timeStamp - lastClickTime < config.CLICK_CHECK_INTERVAL) return;
- lastClickTime = ev.timeStamp;
+ copyCode = (ev, copyButton) => {
+ if (ev.timeStamp - this.lastClickTime < this.config.CLICK_CHECK_INTERVAL) return;
+ this.lastClickTime = ev.timeStamp;
- const lines = copyButton.closest(".md-fences").querySelectorAll(".CodeMirror-code .CodeMirror-line")
+ const lines = copyButton.closest(".md-fences").querySelectorAll(".CodeMirror-code .CodeMirror-line");
if (lines.length === 0) return;
const contentList = [];
lines.forEach(line => {
let encodeText = encodeURI(line.textContent);
- for (let i = 0; i < badChars.length; i++) {
- if (encodeText.indexOf(badChars[i]) !== -1) {
- encodeText = encodeText.replace(new RegExp(badChars[i], "g"), replaceChars[i]);
+ for (let i = 0; i < this.badChars.length; i++) {
+ if (encodeText.indexOf(this.badChars[i]) !== -1) {
+ encodeText = encodeText.replace(new RegExp(this.badChars[i], "g"), this.replaceChars[i]);
}
}
const decodeText = decodeURI(encodeText);
@@ -136,10 +225,10 @@
// File.editor.UserOp.setClipboard(null, null, result);
copyButton.firstElementChild.className = "fa fa-check";
- setTimeout(() => copyButton.firstElementChild.className = "fa fa-clipboard", config.WAIT_RECOVER_INTERVAL);
+ setTimeout(() => copyButton.firstElementChild.className = "fa fa-clipboard", this.config.WAIT_RECOVER_INTERVAL);
}
- const foldCode = (ev, foldButton) => {
+ foldCode = (ev, foldButton) => {
const scroll = foldButton.closest(".md-fences").querySelector(".CodeMirror-scroll");
if (!scroll) return;
@@ -150,13 +239,13 @@
foldButton.firstElementChild.className = "fa fa-minus";
} else {
scroll.style.height = window.getComputedStyle(scroll).lineHeight;
- scroll.style.overflowY = config.FOLD_OVERFLOW;
+ scroll.style.overflowY = this.config.FOLD_OVERFLOW;
foldButton.classList.add("folded");
foldButton.firstElementChild.className = "fa fa-plus";
}
}
- const indentCode = (ev, indentButton) => {
+ indentCode = (ev, indentButton) => {
const fence = indentButton.closest(".md-fences");
if (!fence || !File.editor.fences.formatContent) return;
@@ -165,26 +254,14 @@
File.editor.fences.formatContent();
indentButton.firstElementChild.className = "fa fa-check";
- setTimeout(() => indentButton.firstElementChild.className = "fa fa-indent", config.WAIT_RECOVER_INTERVAL);
+ setTimeout(() => indentButton.firstElementChild.className = "fa fa-indent", this.config.WAIT_RECOVER_INTERVAL);
}
- $("#write").on("mouseenter", ".md-fences", function () {
- if (config.AUTO_HIDE) {
- this.querySelector(".fence-enhance").style.visibility = "";
- }
- }).on("mouseleave", ".md-fences", function () {
- if (config.AUTO_HIDE && !this.querySelector(".typora-fold-code.folded")) {
- this.querySelector(".fence-enhance").style.visibility = "hidden";
- }
- })
-
- //////////////////////// 以下是声明式插件系统代码 ////////////////////////
- const dynamicUtil = {target: null}
- const dynamicCallArgsGenerator = anchorNode => {
+ dynamicCallArgsGenerator = anchorNode => {
const target = anchorNode.closest("#write .md-fences");
if (!target) return;
- dynamicUtil.target = target;
+ this.dynamicUtil.target = target;
const arr = [
{
@@ -196,7 +273,7 @@
arg_value: "copy_current",
},
]
- enableIndent && arr.push({
+ this.enableIndent && arr.push({
arg_name: "调整缩进",
arg_value: "indent_current"
})
@@ -204,99 +281,20 @@
return arr
}
- const callArgs = [
- {
- arg_name: "自动隐藏/显示按钮",
- arg_value: "set_auto_hide",
- },
- {
- arg_name: "禁用/启用折叠按钮",
- arg_value: "disable_or_enable_fold",
- },
- {
- arg_name: "禁用/启用复制按钮",
- arg_value: "disable_or_enable_copy",
- },
- {
- arg_name: "总是折叠代码块",
- arg_value: "fold_all",
- },
- {
- arg_name: "总是展开代码块",
- arg_value: "expand_all",
- },
- ];
-
- if (enableIndent) {
- callArgs.splice(2, 0, {
- arg_name: "禁用/启用缩进调整按钮",
- arg_value: "disable_or_enable_indent",
- });
- }
-
- const copyFence = target => target.querySelector(".typora-copy-code").click();
- const indentFence = target => target.querySelector(".typora-indent-code").click();
- const foldFence = target => target.querySelector(".typora-fold-code").click();
-
- const expandFence = fence => {
+ copyFence = target => target.querySelector(".typora-copy-code").click();
+ indentFence = target => target.querySelector(".typora-indent-code").click();
+ foldFence = target => target.querySelector(".typora-fold-code").click();
+ expandFence = fence => {
const button = fence.querySelector(".fence-enhance .typora-fold-code.folded");
button && button.click();
}
- const callMap = {
- disable_or_enable_fold: () => {
- config.ENABLE_FOLD = !config.ENABLE_FOLD;
- if (!config.ENABLE_FOLD) {
- document.querySelectorAll(".typora-fold-code.folded").forEach(ele => ele.click());
- }
- const display = (config.ENABLE_FOLD) ? "block" : "none";
- document.querySelectorAll(".fence-enhance .typora-fold-code").forEach(ele => ele.style.display = display);
- },
- disable_or_enable_copy: () => {
- config.ENABLE_COPY = !config.ENABLE_COPY;
- const display = (config.ENABLE_COPY) ? "block" : "none";
- document.querySelectorAll(".fence-enhance .typora-copy-code").forEach(ele => ele.style.display = display);
- },
- disable_or_enable_indent: () => {
- enableIndent = !enableIndent;
- const display = (enableIndent) ? "block" : "none";
- document.querySelectorAll(".fence-enhance .typora-indent-code").forEach(ele => ele.style.display = display);
- },
- fold_all: () => {
- document.querySelectorAll(".typora-fold-code:not(.folded)").forEach(ele => ele.click());
- config.FOLD_DEFAULT = true;
- },
- expand_all: () => {
- document.querySelectorAll(".typora-fold-code.folded").forEach(ele => ele.click());
- config.FOLD_DEFAULT = false;
- },
- fold_current: () => foldFence(dynamicUtil.target),
- copy_current: () => copyFence(dynamicUtil.target),
- indent_current: () => indentFence(dynamicUtil.target),
- set_auto_hide: () => {
- config.AUTO_HIDE = !config.AUTO_HIDE;
- const visibility = (config.AUTO_HIDE) ? "hidden" : "";
- document.querySelectorAll(".fence-enhance").forEach(ele => ele.style.visibility = visibility);
- }
- }
-
- const call = type => {
- const func = callMap[type];
+ call = type => {
+ const func = this.callMap[type];
func && func();
}
+}
- module.exports = {
- call,
- callArgs,
- dynamicCallArgsGenerator,
- meta: {
- call,
- copyFence,
- indentFence,
- foldFence,
- expandFence
- }
- };
-
- console.log("fence_enhance.js had been injected");
-})()
\ No newline at end of file
+module.exports = {
+ plugin: fenceEnhancePlugin,
+};
\ No newline at end of file
diff --git a/plugin/file_counter.js b/plugin/file_counter.js
index 051ae837..1bf9742d 100644
--- a/plugin/file_counter.js
+++ b/plugin/file_counter.js
@@ -1,40 +1,68 @@
-(() => {
- const config = global._pluginUtils.getPluginSetting("file_counter");
- const Package = global._pluginUtils.Package;
-
- (() => {
- const css = `
- .${config.CLASS_NAME} {
- display: inline-block;
- float: right;
- white-space: nowrap;
- overflow-x: visible;
- overflow-y: hidden;
- margin-right: 10px;
- padding-left: 3px;
- padding-right: 3px;
- border-radius: 3px;
- background: var(--active-file-bg-color);
- color: var(--active-file-text-color);
- opacity: 1;
- }
- `
- global._pluginUtils.insertStyle("plugin-file-counter-style", css);
- })()
+class fileCounterPlugin extends global._basePlugin {
+ style = () => {
+ const textID = "plugin-file-counter-style";
+ const text = `
+ .${this.config.CLASS_NAME} {
+ display: inline-block;
+ float: right;
+ white-space: nowrap;
+ overflow-x: visible;
+ overflow-y: hidden;
+ margin-right: 10px;
+ padding-left: 3px;
+ padding-right: 3px;
+ border-radius: 3px;
+ background: var(--active-file-bg-color);
+ color: var(--active-file-text-color);
+ opacity: 1;
+ }`;
+ return {textID, text}
+ }
+
+ init = () => {
+ this.Package = this.utils.Package;
+ }
+
+ process = () => {
+ this.init();
+
+ this.utils.loopDetector(this.setAllDirCount, null, this.config.LOOP_DETECT_INTERVAL);
- const verifyExt = filename => {
+ new MutationObserver(mutationList => {
+ if (mutationList.length === 1) {
+ const add = mutationList[0].addedNodes[0];
+ if (add && add.classList && add.classList.contains("file-library-node")) {
+ this.setDirCount(add);
+ return
+ }
+ }
+
+ for (const mutation of mutationList) {
+ if (mutation.target && mutation.target.classList && mutation.target.classList.contains(this.config.CLASS_NAME)
+ || mutation.addedNodes[0] && mutation.addedNodes[0].classList && mutation.addedNodes[0].classList.contains(this.config.CLASS_NAME)) {
+ continue
+ }
+ this.setAllDirCount();
+ return
+ }
+ }).observe(document.getElementById("file-library-tree"), {subtree: true, childList: true});
+ }
+
+ verifyExt = filename => {
if (filename[0] === ".") {
return false
}
- const ext = Package.Path.extname(filename).replace(/^\./, '');
- if (~config.ALLOW_EXT.indexOf(ext.toLowerCase())) {
+ const ext = this.Package.Path.extname(filename).replace(/^\./, '');
+ if (~this.config.ALLOW_EXT.indexOf(ext.toLowerCase())) {
return true
}
}
- const verifySize = (stat) => 0 > config.MAX_SIZE || stat.size < config.MAX_SIZE;
- const allowRead = (filepath, stat) => verifySize(stat) && verifyExt(filepath);
- const countFiles = (dir, filter, then) => {
+ verifySize = (stat) => 0 > this.config.MAX_SIZE || stat.size < this.config.MAX_SIZE;
+ allowRead = (filepath, stat) => this.verifySize(stat) && this.verifyExt(filepath);
+
+ countFiles = (dir, filter, then) => {
+ const Package = this.Package;
let fileCount = 0;
async function traverse(dir) {
@@ -54,7 +82,7 @@
traverse(dir).then(() => then(fileCount)).catch(err => console.error(err));
}
- const getChild = (ele, className) => {
+ getChild = (ele, className) => {
for (const child of ele.children) {
if (child.classList.contains(className)) {
return child
@@ -63,59 +91,39 @@
return false
}
- const setDirCount = treeNode => {
+ setDirCount = treeNode => {
const dir = treeNode.getAttribute("data-path");
- countFiles(dir, allowRead, fileCount => {
- let countDiv = getChild(treeNode, config.CLASS_NAME);
+ this.countFiles(dir, this.allowRead, fileCount => {
+ let countDiv = this.getChild(treeNode, this.config.CLASS_NAME);
if (!countDiv) {
countDiv = document.createElement("div");
- countDiv.classList.add(config.CLASS_NAME);
+ countDiv.classList.add(this.config.CLASS_NAME);
const background = treeNode.querySelector(".file-node-background");
treeNode.insertBefore(countDiv, background.nextElementSibling);
}
countDiv.innerText = fileCount + "";
})
- const children = getChild(treeNode, "file-node-children");
+ const children = this.getChild(treeNode, "file-node-children");
if (children && children.children) {
children.children.forEach(child => {
if (child.getAttribute("data-has-sub") === "true") {
- setDirCount(child);
+ this.setDirCount(child);
}
})
}
}
- const setAllDirCount = () => {
+ setAllDirCount = () => {
const root = document.querySelector("#file-library-tree > .file-library-node");
if (!root) return false;
console.log("setAllDirCount");
- setDirCount(root);
+ this.setDirCount(root);
return true
}
+}
- new MutationObserver(mutationList => {
- if (mutationList.length === 1) {
- const add = mutationList[0].addedNodes[0];
- if (add && add.classList && add.classList.contains("file-library-node")) {
- setDirCount(add);
- return
- }
- }
-
- for (const mutation of mutationList) {
- if (mutation.target && mutation.target.classList && mutation.target.classList.contains(config.CLASS_NAME)
- || mutation.addedNodes[0] && mutation.addedNodes[0].classList && mutation.addedNodes[0].classList.contains(config.CLASS_NAME)) {
- continue
- }
- setAllDirCount();
- return
- }
- }).observe(document.getElementById("file-library-tree"), {subtree: true, childList: true});
-
- global._pluginUtils.loopDetector(setAllDirCount, null, config.LOOP_DETECT_INTERVAL);
-
- module.exports = {};
- console.log("file_counter.js had been injected");
-})()
\ No newline at end of file
+module.exports = {
+ plugin: fileCounterPlugin
+};
\ No newline at end of file
diff --git a/plugin/global/core/plugin.js b/plugin/global/core/plugin.js
new file mode 100644
index 00000000..a41ffec2
--- /dev/null
+++ b/plugin/global/core/plugin.js
@@ -0,0 +1,340 @@
+class utils {
+ static isBetaVersion = parseInt(window._options.appVersion.split(".")[0]) === 0
+ static tempFolder = File.option.tempPath
+
+ static stopLoadPluginError = new Error("stopLoadPlugin")
+ static stopCallError = new Error("stopCall")
+ static detectorContainer = {}
+ static Package = {
+ Path: reqnode("path"),
+ Fs: reqnode("fs"),
+ ChildProcess: reqnode('child_process'),
+ }
+
+ static insertStyle = (id, css) => {
+ const style = document.createElement('style');
+ style.id = id;
+ style.type = 'text/css';
+ style.innerHTML = css;
+ document.getElementsByTagName("head")[0].appendChild(style);
+ }
+
+ static insertStyleFile = (id, filepath) => {
+ const link = document.createElement('link');
+ link.type = 'text/css'
+ link.rel = 'stylesheet'
+ link.href = filepath;
+ document.getElementsByTagName('head')[0].appendChild(link);
+ }
+
+ static metaKeyPressed = ev => File.isMac ? ev.metaKey : ev.ctrlKey
+ static shiftKeyPressed = ev => !!ev.shiftKey
+ static altKeyPressed = ev => !!ev.altKey
+
+ static getPlugin = fixed_name => global._plugins[fixed_name]
+ static getDirname = () => global.dirname || global.__dirname
+ static getFilePath = () => File.filePath || File.bundle && File.bundle.filePath
+ static joinPath = (...paths) => this.Package.Path.join(this.getDirname(), ...paths)
+
+ static requireFilePath = (...paths) => {
+ const filepath = this.joinPath(...paths);
+ return reqnode(filepath)
+ }
+
+ static readFileSync = filepath => {
+ filepath = this.joinPath(filepath);
+ return this.Package.Fs.readFileSync(filepath, 'utf8');
+ }
+
+ static readToml = filepath => {
+ const pluginsFile = this.readFileSync(filepath);
+ const tomlParser = this.requireFilePath("./plugin/global/utils/toml");
+ return tomlParser.parse(pluginsFile);
+ }
+
+ static toHotkeyFunc = hotkeyString => {
+ const keyList = hotkeyString.toLowerCase().split("+").map(k => k.trim());
+ const ctrl = keyList.indexOf("ctrl") !== -1;
+ const shift = keyList.indexOf("shift") !== -1;
+ const alt = keyList.indexOf("alt") !== -1;
+ const key = keyList.filter(key => key !== "ctrl" && key !== "shift" && key !== "alt")[0];
+
+ return ev => this.metaKeyPressed(ev) === ctrl
+ && this.shiftKeyPressed(ev) === shift
+ && this.altKeyPressed(ev) === alt
+ && ev.key.toLowerCase() === key
+ }
+
+ static decorate = (until, obj, func, before, after, changeResult = false) => {
+ const start = new Date().getTime();
+ const uuid = Math.random();
+ this.detectorContainer[uuid] = setInterval(() => {
+ if (new Date().getTime() - start > 10000) {
+ console.log("decorate timeout!", until, obj, func, before, after, changeResult);
+ clearInterval(this.detectorContainer[uuid]);
+ delete this.detectorContainer[uuid];
+ return;
+ }
+
+ if (!until()) return;
+ clearInterval(this.detectorContainer[uuid]);
+ const decorator = (original, before, after) => {
+ return function () {
+ if (before) {
+ const error = before.call(this, ...arguments);
+ if (error === utils.stopCallError) return;
+ }
+
+ let result = original.apply(this, arguments);
+
+ if (after) {
+ const afterResult = after.call(this, result, ...arguments);
+ if (changeResult) {
+ result = afterResult;
+ }
+ }
+ return result;
+ };
+ }
+ obj[func] = decorator(obj[func], before, after);
+ delete this.detectorContainer[uuid];
+ }, 20);
+ }
+
+ static decorateOpenFile = (before, after) => {
+ this.decorate(() => (File && File.editor && File.editor.library && File.editor.library.openFile),
+ File.editor.library, "openFile", before, after)
+ }
+
+ static decorateAddCodeBlock = (before, after) => {
+ this.decorate(() => (File && File.editor && File.editor.fences && File.editor.fences.addCodeBlock),
+ File.editor.fences, "addCodeBlock", before, after)
+ }
+
+ static loopDetector = (until, after, detectInterval = 20) => {
+ const uuid = Math.random();
+ this.detectorContainer[uuid] = setInterval(() => {
+ if (until()) {
+ clearInterval(this.detectorContainer[uuid]);
+ after && after();
+ delete this.detectorContainer[uuid];
+ }
+ }, detectInterval);
+ }
+
+ static showHiddenElementByPlugin = target => {
+ if (!target) return;
+ const collapsePlugin = this.getPlugin("collapse_paragraph");
+ const truncatePlugin = this.getPlugin("truncate_text");
+ collapsePlugin && collapsePlugin.rollback(target);
+ truncatePlugin && truncatePlugin.rollback(target);
+ }
+
+ static dragFixedModal = (handleElement, moveElement, withMetaKey = true) => {
+ handleElement.addEventListener("mousedown", ev => {
+ if (withMetaKey && !this.metaKeyPressed(ev) || ev.button !== 0) return;
+ ev.stopPropagation();
+ const rect = moveElement.getBoundingClientRect();
+ const shiftX = ev.clientX - rect.left;
+ const shiftY = ev.clientY - rect.top;
+
+ const onMouseMove = ev => {
+ if (withMetaKey && !this.metaKeyPressed(ev) || ev.button !== 0) return;
+ ev.stopPropagation();
+ ev.preventDefault();
+ requestAnimationFrame(() => {
+ moveElement.style.left = ev.clientX - shiftX + 'px';
+ moveElement.style.top = ev.clientY - shiftY + 'px';
+ });
+ }
+
+ document.addEventListener("mouseup", ev => {
+ if (withMetaKey && !this.metaKeyPressed(ev) || ev.button !== 0) return;
+ ev.stopPropagation();
+ ev.preventDefault();
+ document.removeEventListener('mousemove', onMouseMove);
+ moveElement.onmouseup = null;
+ }
+ )
+
+ document.addEventListener('mousemove', onMouseMove);
+ })
+ handleElement.ondragstart = () => false
+ }
+}
+
+class pluginInterface {
+ enable() {
+ throw new Error('Method enable not implemented.')
+ }
+
+ disable() {
+ throw new Error('Method disable not implemented.')
+ }
+
+ onEvent(eventType, payload) {
+ throw new Error('Method onEvent not implemented.')
+ }
+
+ beforeProcess() {
+ throw new Error('Method beforeProcess not implemented.')
+ }
+
+ process() {
+ throw new Error('Method process not implemented.')
+ }
+
+ afterProcess() {
+ throw new Error('Method afterProcess not implemented.')
+ }
+}
+
+class basePlugin extends pluginInterface {
+ constructor(setting) {
+ super();
+ this.fixed_name = setting.fixed_name;
+ this.config = setting;
+ this.utils = utils
+ }
+
+ enable() {
+ this.config.ENABLE = true;
+ this.onEvent("enable", null);
+ }
+
+ disable() {
+ this.config.ENABLE = false;
+ this.onEvent("disable", null);
+ }
+
+ beforeProcess() {
+ }
+
+ style() {
+ }
+
+ html() {
+ }
+
+ hotkey() {
+ }
+
+ process() {
+ }
+
+ afterProcess() {
+ }
+}
+
+global._basePlugin = basePlugin;
+
+class hotkeyHelper {
+ constructor() {
+ this.utils = utils;
+ this.hotkeyList = [];
+ }
+
+ _register = (hotkey, call) => {
+ if (typeof hotkey === "string") {
+ hotkey = this.utils.toHotkeyFunc(hotkey);
+ this.hotkeyList.push({hotkey, call});
+ } else if (hotkey instanceof Array) {
+ for (const hk of hotkey) {
+ this._register(hk, call);
+ }
+ }
+ }
+
+ register(hotkeyList) {
+ if (hotkeyList) {
+ for (const hotkey of hotkeyList) {
+ this._register(hotkey.hotkey, hotkey.callback);
+ }
+ }
+ }
+
+ listen = () => {
+ window.addEventListener("keydown", ev => {
+ for (const hotkey of this.hotkeyList) {
+ if (hotkey.hotkey(ev)) {
+ hotkey.call();
+ ev.preventDefault();
+ ev.stopPropagation();
+ return
+ }
+ }
+ }, true)
+ }
+}
+
+class process {
+ constructor() {
+ this.utils = utils;
+ this.helper = new hotkeyHelper();
+ }
+
+ insertStyle(style) {
+ if (!style) return;
+ const textID = style["textID"] || null;
+ const text = style["text"] || null;
+ const fileID = style["fileID"] || null;
+ const file = style["file"] || null;
+ if (fileID && file) {
+ this.utils.insertStyleFile(fileID, file);
+ }
+ if (textID && text) {
+ this.utils.insertStyle(textID, text);
+ }
+ }
+
+ loadPlugin(pluginClass, pluginSetting) {
+ const plugin = new pluginClass(pluginSetting);
+
+ const error = plugin.beforeProcess();
+ if (error !== this.utils.stopLoadPluginError) {
+ this.insertStyle(plugin.style());
+ plugin.html();
+ this.helper.register(plugin.hotkey());
+ plugin.process();
+ plugin.afterProcess();
+ console.log(`plugin had been injected: [ ${plugin.fixed_name} ] `);
+ }
+ return plugin
+ }
+
+ run() {
+ global._plugins = {};
+ global._pluginsHadInjected = false;
+
+ const pluginSettings = this.utils.readToml("./plugin/global/settings/settings.toml");
+ const promises = [];
+
+ for (const fixed_name in pluginSettings) {
+ const pluginSetting = pluginSettings[fixed_name];
+ pluginSetting.fixed_name = fixed_name;
+
+ if (!pluginSetting.ENABLE) continue;
+
+ const filepath = this.utils.joinPath("./plugin", fixed_name);
+ const promise = new Promise(resolve => {
+ try {
+ const {plugin} = reqnode(filepath);
+ global._plugins[fixed_name] = this.loadPlugin(plugin, pluginSetting);
+ } catch (e) {
+ console.error("plugin err:", e);
+ }
+ resolve();
+ })
+ promises.push(promise);
+ }
+
+ Promise.all(promises).then(() => {
+ this.helper.listen();
+ global._pluginsHadInjected = true;
+ })
+ }
+}
+
+module.exports = {
+ process
+};
\ No newline at end of file
diff --git a/plugin/global/settings.js b/plugin/global/settings.js
deleted file mode 100644
index 6657e08c..00000000
--- a/plugin/global/settings.js
+++ /dev/null
@@ -1,12 +0,0 @@
-(() => {
- const readSettingFile = () => {
- const filepath = global._pluginUtils.joinPath("./plugin/global/settings/settings.toml");
- const {parse} = global._pluginUtils.requireFile("./plugin/global/toml/index.js");
- const settingFile = global._pluginUtils.Package.Fs.readFileSync(filepath, 'utf8');
- return parse(settingFile)
- }
-
- module.exports = {
- pluginSettings: readSettingFile()
- };
-})()
\ No newline at end of file
diff --git a/plugin/global/settings/settings.toml b/plugin/global/settings/settings.toml
index 4078e86a..e865a3d4 100644
--- a/plugin/global/settings/settings.toml
+++ b/plugin/global/settings/settings.toml
@@ -3,6 +3,10 @@
[window_tab]
# 启用插件
ENABLE = true
+# 在右键菜单中展示的名称
+NAME = "标签页管理"
+# 是否在右键菜单中可点击
+CLICKABLE = true
# 隐藏titleBar
HIDE_WINDOW_TITLE_BAR = true
# 拖拽排序标签页的方式(1 or 2)
@@ -27,6 +31,10 @@ SWITCH_PREVIOUS_TAB_HOTKEY = ["ctrl+PageUp", "ctrl+shift+Tab"]
[search_multi]
# 启用插件
ENABLE = true
+# 在右键菜单中展示的名称
+NAME = "全局多关键字搜索"
+# 是否在右键菜单中可点击
+CLICKABLE = true
# 允许拖动模态框
ALLOW_DRAG = true
# 模态框自动隐藏
@@ -36,7 +44,7 @@ REFOUCE_WHEN_OPEN_FILE = true
# 搜索内容时大小写敏感(此选项不必手动调整,可以在UI设置)
CASE_SENSITIVE = false
# 将文件路径加入搜索内容(此选项不必手动调整,可以在UI设置)
-INCLUDE_FILE_PATH = false
+INCLUDE_FILE_PATH = true
# 展示文件路径时使用相对路径
RELATIVE_PATH = true
# 关键词按空格分割
@@ -55,6 +63,10 @@ HOTKEY = "ctrl+shift+p"
[multi_highlighter]
# 启用插件
ENABLE = true
+# 在右键菜单中展示的名称
+NAME = "多关键字高亮"
+# 是否在右键菜单中可点击
+CLICKABLE = true
# 快捷键
HOTKEY = "ctrl+shift+h"
# 允许拖拽
@@ -119,6 +131,10 @@ CLEAR_LIST_THRESHOLD = 12
[outline]
# 启用插件
ENABLE = true
+# 在右键菜单中展示的名称
+NAME = "类别大纲"
+# 是否在右键菜单中可点击
+CLICKABLE = true
# 默认使用的大纲类型 fence/image/table/all
DEFAULT_TYPE = "fence"
# 是否使用混合标签
@@ -140,6 +156,10 @@ table = "Table"
[commander]
# 启用插件
ENABLE = true
+# 在右键菜单中展示的名称
+NAME = "命令行环境"
+# 是否在右键菜单中可点击
+CLICKABLE = true
# 快捷键
HOTKEY = "ctrl+g"
# 允许拖动模态框
@@ -178,6 +198,10 @@ cmd = "cd $m && git add . && git commit -m \"message\""
[md_padding]
# 启用插件
ENABLE = true
+# 在右键菜单中展示的名称
+NAME = "中英文混排优化"
+# 是否在右键菜单中可点击
+CLICKABLE = true
# 快捷键
HOTKEY = ["ctrl+shift+k", "ctrl+shift+b"]
@@ -186,6 +210,10 @@ HOTKEY = ["ctrl+shift+k", "ctrl+shift+b"]
[read_only]
# 启用插件
ENABLE = true
+# 在右键菜单中展示的名称
+NAME = "只读模式"
+# 是否在右键菜单中可点击
+CLICKABLE = true
# 进入和脱离只读模式的快捷键
HOTKEY = "ctrl+shift+r"
# 默认使用只读模式
@@ -242,6 +270,10 @@ CLICK_CHECK_INTERVAL = 500
[resize_image]
# 启用插件
ENABLE = true
+# 在右键菜单中展示的名称
+NAME = "图片调整"
+# 是否在右键菜单中可点击
+CLICKABLE = true
# 滚动的放缩倍率
SCALE = 0.1
# 图片水平位置:center/left/right
@@ -252,6 +284,10 @@ IMAGE_ALIGN = "center"
[datatables]
# 启用插件
ENABLE = true
+# 在右键菜单中展示的名称
+NAME = "表格增强"
+# 是否在右键菜单中可点击
+CLICKABLE = true
# 是否分页
PAGING = true
# 使用分页时,单页显示的数据条数
@@ -276,6 +312,10 @@ REGEX = false
[go_top]
# 启用插件
ENABLE = true
+# 在右键菜单中展示的名称
+NAME = "一键到顶"
+# 是否在右键菜单中可点击
+CLICKABLE = true
# 距顶部50像素开始显示
THRESHOLD = 50
# 滚动所用时间
@@ -290,12 +330,20 @@ DIV_ID = "plugin-go-top"
[mindmap]
# 启用插件
ENABLE = true
+# 在右键菜单中展示的名称
+NAME = "思维导图"
+# 是否在右键菜单中可点击
+CLICKABLE = true
############### auto_number ###############
[auto_number]
# 启用插件
ENABLE = true
+# 在右键菜单中展示的名称
+NAME = "自动编号"
+# 是否在右键菜单中可点击
+CLICKABLE = true
# 侧边栏自动编号
ENABLE_SIDE_BAR = true
# 正文自动编号
@@ -313,7 +361,7 @@ ENABLE_WHEN_EXPORT = true
# 添加的ID
ID = "plugin-auto-number-style"
# 下标名称
-[auto_number.NAME]
+[auto_number.NAMES]
table = "Table"
image = "Figure"
fence = "Fence"
@@ -323,6 +371,10 @@ fence = "Fence"
[fence_enhance]
# 启用插件
ENABLE = true
+# 在右键菜单中展示的名称
+NAME = "代码块增强"
+# 是否在右键菜单中可点击
+CLICKABLE = true
# 自动隐藏,鼠标移动到fence才显示
AUTO_HIDE = false
# 启用复制代码功能
@@ -344,6 +396,10 @@ WAIT_RECOVER_INTERVAL = 1000
[collapse_paragraph]
# 启用插件
ENABLE = true
+# 在右键菜单中展示的名称
+NAME = "章节折叠"
+# 是否在右键菜单中可点击
+CLICKABLE = true
# 添加的class
CLASS_NAME = "plugin-collapsed-paragraph"
@@ -352,16 +408,36 @@ CLASS_NAME = "plugin-collapsed-paragraph"
[truncate_text]
# 启用插件
ENABLE = true
+# 在右键菜单中展示的名称
+NAME = "文段截断"
+# 是否在右键菜单中可点击
+CLICKABLE = true
# 剩余文本段
REMAIN_LENGTH = 80
# 添加的class
CLASS_NAME = "plugin-truncate-text"
+############### export_enhance ###############
+[export_enhance]
+# 启用插件
+ENABLE = true
+# 在右键菜单中展示的名称
+NAME = "导出增强"
+# 是否在右键菜单中可点击
+CLICKABLE = true
+# 是否下载网络图片(若为true,有可能因为网络问题导致超时)
+DOWNLOAD_NETWORK_IMAGE = false
+
+
############### right_click_menu ###############
[right_click_menu]
# 启用插件
ENABLE = true
+# 在右键菜单中展示的名称
+NAME = "右键菜单"
+# 是否在右键菜单中可点击
+CLICKABLE = true
# 点击后是否隐藏菜单
DO_NOT_HIDE = false
# 内部使用
@@ -369,20 +445,14 @@ NOT_AVAILABLE_VALUE = "__not_available__"
LOOP_DETECT_INTERVAL = 200
-############### resize_table ###############
-[resize_table]
-# 启用插件
-ENABLE = true
-# 是否去除表格单元格最小宽度限制
-REMOVE_MIX_WIDTH = true
-# 单元格边线的拖拽范围
-THRESHOLD = 20
-
-
############### file_counter ###############
[file_counter]
# 启用插件
ENABLE = true
+# 在右键菜单中展示的名称
+NAME = "文件计数"
+# 是否在右键菜单中可点击
+CLICKABLE = false
# Typora允许打开小于2000000(即MAX_FILE_SIZE)的文件,大于maxSize的文件在搜索时将被忽略。若maxSize<0则不过滤
MAX_SIZE = 2000000
# Typora允许打开的文件的后缀名,此外的文件在搜索时将被忽略
@@ -393,21 +463,35 @@ CLASS_NAME = "plugin-file-counter"
LOOP_DETECT_INTERVAL = 300
-############### export_enhance ###############
-[export_enhance]
+############### resize_table ###############
+[resize_table]
# 启用插件
ENABLE = true
-# 是否下载网络图片(若为true,有可能因为网络问题导致超时)
-DOWNLOAD_NETWORK_IMAGE = false
+# 在右键菜单中展示的名称
+NAME = "表格调整"
+# 是否在右键菜单中可点击
+CLICKABLE = false
+# 是否去除表格单元格最小宽度限制
+REMOVE_MIX_WIDTH = true
+# 单元格边线的拖拽范围
+THRESHOLD = 20
############### mermaid_replace ###############
[mermaid_replace]
# 启用插件
ENABLE = false
+# 在右键菜单中展示的名称
+NAME = "mermaid组件替换"
+# 是否在右键菜单中可点击
+CLICKABLE = false
############### test ###############
[test]
# 启用插件
-ENABLE = false
\ No newline at end of file
+ENABLE = false
+# 在右键菜单中展示的名称
+NAME = "测试专用"
+# 是否在右键菜单中可点击
+CLICKABLE = false
\ No newline at end of file
diff --git a/plugin/global/utils.js b/plugin/global/utils.js
deleted file mode 100644
index f296491b..00000000
--- a/plugin/global/utils.js
+++ /dev/null
@@ -1,199 +0,0 @@
-(() => {
- const isBetaVersion = parseInt(window._options.appVersion.split(".")[0]) === 0;
-
- const tempFolder = File.option.tempPath;
-
- const insertStyle = (id, css) => {
- const style = document.createElement('style');
- style.id = id;
- style.type = 'text/css';
- style.innerHTML = css;
- document.getElementsByTagName("head")[0].appendChild(style);
- }
-
- const insertStyleFile = (id, filepath) => {
- const link = document.createElement('link');
- link.type = 'text/css'
- link.rel = 'stylesheet'
- link.href = filepath;
- document.getElementsByTagName('head')[0].appendChild(link);
- }
-
- const getPlugin = fixed_name => {
- const idx = global._plugins.findIndex(plugin => plugin.enable && plugin.fixed_name === fixed_name)
- if (idx !== -1) {
- return global._plugins[idx];
- }
- }
-
- const metaKeyPressed = ev => File.isMac ? ev.metaKey : ev.ctrlKey;
- const shiftKeyPressed = ev => !!ev.shiftKey;
- const altKeyPressed = ev => !!ev.altKey;
-
- const getPluginSetting = fixed_name => global._pluginSettings[fixed_name];
- const getDirname = () => global.dirname || global.__dirname;
- const getFilePath = () => File.filePath || File.bundle && File.bundle.filePath;
- const joinPath = (...paths) => Package.Path.join(getDirname(), ...paths);
-
- const requireFile = (...paths) => {
- const filepath = joinPath(...paths);
- return reqnode(filepath)
- }
-
- const Package = {
- Path: reqnode("path"),
- Fs: reqnode("fs"),
- ChildProcess: reqnode('child_process'),
- };
-
- const stopCallError = new Error("stopCall");
-
- const detectorContainer = {}
-
- const decorate = (until, obj, func, before, after, changeResult = false) => {
- const start = new Date().getTime();
- const uuid = Math.random();
- detectorContainer[uuid] = setInterval(() => {
- if (new Date().getTime() - start > 10000) {
- console.log("decorate timeout!", until, obj, func, before, after, changeResult);
- clearInterval(detectorContainer[uuid]);
- delete detectorContainer[uuid];
- return;
- }
-
- if (!until()) return;
- clearInterval(detectorContainer[uuid]);
- const decorator = (original, before, after) => {
- return function () {
- if (before) {
- const error = before.call(this, ...arguments);
- if (error === stopCallError) return;
- }
-
- let result = original.apply(this, arguments);
-
- if (after) {
- const afterResult = after.call(this, result, ...arguments);
- if (changeResult) {
- result = afterResult;
- }
- }
- return result;
- };
- }
- obj[func] = decorator(obj[func], before, after);
- delete detectorContainer[uuid];
- }, 20);
- }
-
- const decorateOpenFile = (before, after) => {
- decorate(() => (File && File.editor && File.editor.library && File.editor.library.openFile), File.editor.library, "openFile", before, after)
- }
-
- const decorateAddCodeBlock = (before, after) => {
- decorate(() => (File && File.editor && File.editor.fences && File.editor.fences.addCodeBlock), File.editor.fences, "addCodeBlock", before, after)
- }
-
- const loopDetector = (until, after, detectInterval = 20) => {
- const uuid = Math.random();
- detectorContainer[uuid] = setInterval(() => {
- if (until()) {
- clearInterval(detectorContainer[uuid]);
- after && after();
- delete detectorContainer[uuid];
- }
- }, detectInterval);
- }
-
- const toHotkeyFunc = hotkeyString => {
- const keyList = hotkeyString.toLowerCase().split("+").map(k => k.trim());
- const ctrl = keyList.indexOf("ctrl") !== -1;
- const shift = keyList.indexOf("shift") !== -1;
- const alt = keyList.indexOf("alt") !== -1;
- const key = keyList.filter(key => key !== "ctrl" && key !== "shift" && key !== "alt")[0];
-
- return ev => global._pluginUtils.metaKeyPressed(ev) === ctrl
- && global._pluginUtils.shiftKeyPressed(ev) === shift
- && global._pluginUtils.altKeyPressed(ev) === alt
- && ev.key.toLowerCase() === key
- }
-
- const hotkeyList = []
- const registerWindowHotkey = (hotkey, call) => {
- if (typeof hotkey === "string") {
- hotkey = toHotkeyFunc(hotkey);
- hotkeyList.push({hotkey, call});
- } else if (hotkey instanceof Array) {
- for (const h of hotkey) {
- registerWindowHotkey(h, call);
- }
- }
- };
- window.addEventListener("keydown", ev => {
- for (let hotkey of hotkeyList) {
- if (hotkey.hotkey(ev)) {
- hotkey.call();
- ev.preventDefault();
- ev.stopPropagation();
- return
- }
- }
- }, true)
-
- const dragFixedModal = (handleElement, moveElement, withMetaKey = true) => {
- handleElement.addEventListener("mousedown", ev => {
- if (withMetaKey && !metaKeyPressed(ev) || ev.button !== 0) return;
- ev.stopPropagation();
- const rect = moveElement.getBoundingClientRect();
- const shiftX = ev.clientX - rect.left;
- const shiftY = ev.clientY - rect.top;
-
- const onMouseMove = ev => {
- if (withMetaKey && !metaKeyPressed(ev) || ev.button !== 0) return;
- ev.stopPropagation();
- ev.preventDefault();
- requestAnimationFrame(() => {
- moveElement.style.left = ev.clientX - shiftX + 'px';
- moveElement.style.top = ev.clientY - shiftY + 'px';
- });
- }
-
- document.addEventListener("mouseup", ev => {
- if (withMetaKey && !metaKeyPressed(ev) || ev.button !== 0) return;
- ev.stopPropagation();
- ev.preventDefault();
- document.removeEventListener('mousemove', onMouseMove);
- moveElement.onmouseup = null;
- }
- )
-
- document.addEventListener('mousemove', onMouseMove);
- })
- handleElement.ondragstart = () => false
- }
-
- module.exports = {
- isBetaVersion,
- tempFolder,
- insertStyle,
- insertStyleFile,
- getPlugin,
- getPluginSetting,
- metaKeyPressed,
- shiftKeyPressed,
- altKeyPressed,
- getDirname,
- getFilePath,
- joinPath,
- requireFile,
- Package,
- stopCallError,
- decorate,
- decorateOpenFile,
- decorateAddCodeBlock,
- loopDetector,
- toHotkeyFunc,
- registerWindowHotkey,
- dragFixedModal,
- };
-})()
\ No newline at end of file
diff --git a/plugin/md_padding/md-padding/dist/bin/md-padding.js b/plugin/global/utils/md-padding/bin/md-padding.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/bin/md-padding.js
rename to plugin/global/utils/md-padding/bin/md-padding.js
diff --git a/plugin/md_padding/md-padding/dist/index.js b/plugin/global/utils/md-padding/index.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/index.js
rename to plugin/global/utils/md-padding/index.js
diff --git a/plugin/md_padding/md-padding/dist/nodes/alphabet-numeric.js b/plugin/global/utils/md-padding/nodes/alphabet-numeric.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/nodes/alphabet-numeric.js
rename to plugin/global/utils/md-padding/nodes/alphabet-numeric.js
diff --git a/plugin/md_padding/md-padding/dist/nodes/blank.js b/plugin/global/utils/md-padding/nodes/blank.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/nodes/blank.js
rename to plugin/global/utils/md-padding/nodes/blank.js
diff --git a/plugin/md_padding/md-padding/dist/nodes/block-code.js b/plugin/global/utils/md-padding/nodes/block-code.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/nodes/block-code.js
rename to plugin/global/utils/md-padding/nodes/block-code.js
diff --git a/plugin/md_padding/md-padding/dist/nodes/delimited.js b/plugin/global/utils/md-padding/nodes/delimited.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/nodes/delimited.js
rename to plugin/global/utils/md-padding/nodes/delimited.js
diff --git a/plugin/md_padding/md-padding/dist/nodes/document.js b/plugin/global/utils/md-padding/nodes/document.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/nodes/document.js
rename to plugin/global/utils/md-padding/nodes/document.js
diff --git a/plugin/md_padding/md-padding/dist/nodes/empasis.js b/plugin/global/utils/md-padding/nodes/empasis.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/nodes/empasis.js
rename to plugin/global/utils/md-padding/nodes/empasis.js
diff --git a/plugin/md_padding/md-padding/dist/nodes/html-tag.js b/plugin/global/utils/md-padding/nodes/html-tag.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/nodes/html-tag.js
rename to plugin/global/utils/md-padding/nodes/html-tag.js
diff --git a/plugin/md_padding/md-padding/dist/nodes/inline-code.js b/plugin/global/utils/md-padding/nodes/inline-code.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/nodes/inline-code.js
rename to plugin/global/utils/md-padding/nodes/inline-code.js
diff --git a/plugin/md_padding/md-padding/dist/nodes/inline-image.js b/plugin/global/utils/md-padding/nodes/inline-image.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/nodes/inline-image.js
rename to plugin/global/utils/md-padding/nodes/inline-image.js
diff --git a/plugin/md_padding/md-padding/dist/nodes/inline-link.js b/plugin/global/utils/md-padding/nodes/inline-link.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/nodes/inline-link.js
rename to plugin/global/utils/md-padding/nodes/inline-link.js
diff --git a/plugin/md_padding/md-padding/dist/nodes/math.js b/plugin/global/utils/md-padding/nodes/math.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/nodes/math.js
rename to plugin/global/utils/md-padding/nodes/math.js
diff --git a/plugin/md_padding/md-padding/dist/nodes/node-kind.js b/plugin/global/utils/md-padding/nodes/node-kind.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/nodes/node-kind.js
rename to plugin/global/utils/md-padding/nodes/node-kind.js
diff --git a/plugin/md_padding/md-padding/dist/nodes/node.js b/plugin/global/utils/md-padding/nodes/node.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/nodes/node.js
rename to plugin/global/utils/md-padding/nodes/node.js
diff --git a/plugin/md_padding/md-padding/dist/nodes/ordered-list-item.js b/plugin/global/utils/md-padding/nodes/ordered-list-item.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/nodes/ordered-list-item.js
rename to plugin/global/utils/md-padding/nodes/ordered-list-item.js
diff --git a/plugin/md_padding/md-padding/dist/nodes/punctuation.js b/plugin/global/utils/md-padding/nodes/punctuation.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/nodes/punctuation.js
rename to plugin/global/utils/md-padding/nodes/punctuation.js
diff --git a/plugin/md_padding/md-padding/dist/nodes/quoted.js b/plugin/global/utils/md-padding/nodes/quoted.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/nodes/quoted.js
rename to plugin/global/utils/md-padding/nodes/quoted.js
diff --git a/plugin/md_padding/md-padding/dist/nodes/raw.js b/plugin/global/utils/md-padding/nodes/raw.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/nodes/raw.js
rename to plugin/global/utils/md-padding/nodes/raw.js
diff --git a/plugin/md_padding/md-padding/dist/nodes/reference-definition.js b/plugin/global/utils/md-padding/nodes/reference-definition.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/nodes/reference-definition.js
rename to plugin/global/utils/md-padding/nodes/reference-definition.js
diff --git a/plugin/md_padding/md-padding/dist/nodes/reference-image.js b/plugin/global/utils/md-padding/nodes/reference-image.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/nodes/reference-image.js
rename to plugin/global/utils/md-padding/nodes/reference-image.js
diff --git a/plugin/md_padding/md-padding/dist/nodes/reference-link.js b/plugin/global/utils/md-padding/nodes/reference-link.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/nodes/reference-link.js
rename to plugin/global/utils/md-padding/nodes/reference-link.js
diff --git a/plugin/md_padding/md-padding/dist/nodes/square-quoted.js b/plugin/global/utils/md-padding/nodes/square-quoted.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/nodes/square-quoted.js
rename to plugin/global/utils/md-padding/nodes/square-quoted.js
diff --git a/plugin/md_padding/md-padding/dist/nodes/strikethrough.js b/plugin/global/utils/md-padding/nodes/strikethrough.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/nodes/strikethrough.js
rename to plugin/global/utils/md-padding/nodes/strikethrough.js
diff --git a/plugin/md_padding/md-padding/dist/nodes/strong.js b/plugin/global/utils/md-padding/nodes/strong.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/nodes/strong.js
rename to plugin/global/utils/md-padding/nodes/strong.js
diff --git a/plugin/md_padding/md-padding/dist/nodes/type-guards.js b/plugin/global/utils/md-padding/nodes/type-guards.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/nodes/type-guards.js
rename to plugin/global/utils/md-padding/nodes/type-guards.js
diff --git a/plugin/md_padding/md-padding/dist/nodes/unicode-string.js b/plugin/global/utils/md-padding/nodes/unicode-string.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/nodes/unicode-string.js
rename to plugin/global/utils/md-padding/nodes/unicode-string.js
diff --git a/plugin/md_padding/md-padding/dist/nodes/unordered-list-item.js b/plugin/global/utils/md-padding/nodes/unordered-list-item.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/nodes/unordered-list-item.js
rename to plugin/global/utils/md-padding/nodes/unordered-list-item.js
diff --git a/plugin/md_padding/md-padding/dist/parser/context.js b/plugin/global/utils/md-padding/parser/context.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/parser/context.js
rename to plugin/global/utils/md-padding/parser/context.js
diff --git a/plugin/md_padding/md-padding/dist/parser/mask.js b/plugin/global/utils/md-padding/parser/mask.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/parser/mask.js
rename to plugin/global/utils/md-padding/parser/mask.js
diff --git a/plugin/md_padding/md-padding/dist/parser/parse-code.js b/plugin/global/utils/md-padding/parser/parse-code.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/parser/parse-code.js
rename to plugin/global/utils/md-padding/parser/parse-code.js
diff --git a/plugin/md_padding/md-padding/dist/parser/parse.js b/plugin/global/utils/md-padding/parser/parse.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/parser/parse.js
rename to plugin/global/utils/md-padding/parser/parse.js
diff --git a/plugin/md_padding/md-padding/dist/parser/state-masks.js b/plugin/global/utils/md-padding/parser/state-masks.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/parser/state-masks.js
rename to plugin/global/utils/md-padding/parser/state-masks.js
diff --git a/plugin/md_padding/md-padding/dist/parser/state.js b/plugin/global/utils/md-padding/parser/state.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/parser/state.js
rename to plugin/global/utils/md-padding/parser/state.js
diff --git a/plugin/md_padding/md-padding/dist/transformers/compact.js b/plugin/global/utils/md-padding/transformers/compact.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/transformers/compact.js
rename to plugin/global/utils/md-padding/transformers/compact.js
diff --git a/plugin/md_padding/md-padding/dist/transformers/pad-between-nodes.js b/plugin/global/utils/md-padding/transformers/pad-between-nodes.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/transformers/pad-between-nodes.js
rename to plugin/global/utils/md-padding/transformers/pad-between-nodes.js
diff --git a/plugin/md_padding/md-padding/dist/transformers/pad-markdown-options.js b/plugin/global/utils/md-padding/transformers/pad-markdown-options.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/transformers/pad-markdown-options.js
rename to plugin/global/utils/md-padding/transformers/pad-markdown-options.js
diff --git a/plugin/md_padding/md-padding/dist/transformers/pad-markdown.js b/plugin/global/utils/md-padding/transformers/pad-markdown.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/transformers/pad-markdown.js
rename to plugin/global/utils/md-padding/transformers/pad-markdown.js
diff --git a/plugin/md_padding/md-padding/dist/transformers/pad-recursively.js b/plugin/global/utils/md-padding/transformers/pad-recursively.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/transformers/pad-recursively.js
rename to plugin/global/utils/md-padding/transformers/pad-recursively.js
diff --git a/plugin/md_padding/md-padding/dist/utils/char.js b/plugin/global/utils/md-padding/utils/char.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/utils/char.js
rename to plugin/global/utils/md-padding/utils/char.js
diff --git a/plugin/md_padding/md-padding/dist/utils/dfs.js b/plugin/global/utils/md-padding/utils/dfs.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/utils/dfs.js
rename to plugin/global/utils/md-padding/utils/dfs.js
diff --git a/plugin/md_padding/md-padding/dist/utils/stack.js b/plugin/global/utils/md-padding/utils/stack.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/utils/stack.js
rename to plugin/global/utils/md-padding/utils/stack.js
diff --git a/plugin/md_padding/md-padding/dist/utils/string.js b/plugin/global/utils/md-padding/utils/string.js
similarity index 100%
rename from plugin/md_padding/md-padding/dist/utils/string.js
rename to plugin/global/utils/md-padding/utils/string.js
diff --git a/plugin/md_padding/md-padding/node_modules/ansi-regex/index.js b/plugin/global/utils/node_modules/ansi-regex/index.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/ansi-regex/index.js
rename to plugin/global/utils/node_modules/ansi-regex/index.js
diff --git a/plugin/md_padding/md-padding/node_modules/ansi-regex/package.json b/plugin/global/utils/node_modules/ansi-regex/package.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/ansi-regex/package.json
rename to plugin/global/utils/node_modules/ansi-regex/package.json
diff --git a/plugin/md_padding/md-padding/node_modules/ansi-styles/index.js b/plugin/global/utils/node_modules/ansi-styles/index.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/ansi-styles/index.js
rename to plugin/global/utils/node_modules/ansi-styles/index.js
diff --git a/plugin/md_padding/md-padding/node_modules/ansi-styles/package.json b/plugin/global/utils/node_modules/ansi-styles/package.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/ansi-styles/package.json
rename to plugin/global/utils/node_modules/ansi-styles/package.json
diff --git a/plugin/md_padding/md-padding/node_modules/camelcase/index.js b/plugin/global/utils/node_modules/camelcase/index.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/camelcase/index.js
rename to plugin/global/utils/node_modules/camelcase/index.js
diff --git a/plugin/md_padding/md-padding/node_modules/camelcase/package.json b/plugin/global/utils/node_modules/camelcase/package.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/camelcase/package.json
rename to plugin/global/utils/node_modules/camelcase/package.json
diff --git a/plugin/md_padding/md-padding/node_modules/cliui/index.js b/plugin/global/utils/node_modules/cliui/index.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/cliui/index.js
rename to plugin/global/utils/node_modules/cliui/index.js
diff --git a/plugin/md_padding/md-padding/node_modules/cliui/package.json b/plugin/global/utils/node_modules/cliui/package.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/cliui/package.json
rename to plugin/global/utils/node_modules/cliui/package.json
diff --git a/plugin/md_padding/md-padding/node_modules/color-convert/conversions.js b/plugin/global/utils/node_modules/color-convert/conversions.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/color-convert/conversions.js
rename to plugin/global/utils/node_modules/color-convert/conversions.js
diff --git a/plugin/md_padding/md-padding/node_modules/color-convert/index.js b/plugin/global/utils/node_modules/color-convert/index.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/color-convert/index.js
rename to plugin/global/utils/node_modules/color-convert/index.js
diff --git a/plugin/md_padding/md-padding/node_modules/color-convert/package.json b/plugin/global/utils/node_modules/color-convert/package.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/color-convert/package.json
rename to plugin/global/utils/node_modules/color-convert/package.json
diff --git a/plugin/md_padding/md-padding/node_modules/color-convert/route.js b/plugin/global/utils/node_modules/color-convert/route.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/color-convert/route.js
rename to plugin/global/utils/node_modules/color-convert/route.js
diff --git a/plugin/md_padding/md-padding/node_modules/color-name/index.js b/plugin/global/utils/node_modules/color-name/index.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/color-name/index.js
rename to plugin/global/utils/node_modules/color-name/index.js
diff --git a/plugin/md_padding/md-padding/node_modules/color-name/package.json b/plugin/global/utils/node_modules/color-name/package.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/color-name/package.json
rename to plugin/global/utils/node_modules/color-name/package.json
diff --git a/plugin/md_padding/md-padding/node_modules/decamelize/index.js b/plugin/global/utils/node_modules/decamelize/index.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/decamelize/index.js
rename to plugin/global/utils/node_modules/decamelize/index.js
diff --git a/plugin/md_padding/md-padding/node_modules/decamelize/package.json b/plugin/global/utils/node_modules/decamelize/package.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/decamelize/package.json
rename to plugin/global/utils/node_modules/decamelize/package.json
diff --git a/plugin/md_padding/md-padding/node_modules/emoji-regex/es2015/index.js b/plugin/global/utils/node_modules/emoji-regex/es2015/index.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/emoji-regex/es2015/index.js
rename to plugin/global/utils/node_modules/emoji-regex/es2015/index.js
diff --git a/plugin/md_padding/md-padding/node_modules/emoji-regex/es2015/text.js b/plugin/global/utils/node_modules/emoji-regex/es2015/text.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/emoji-regex/es2015/text.js
rename to plugin/global/utils/node_modules/emoji-regex/es2015/text.js
diff --git a/plugin/md_padding/md-padding/node_modules/emoji-regex/index.js b/plugin/global/utils/node_modules/emoji-regex/index.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/emoji-regex/index.js
rename to plugin/global/utils/node_modules/emoji-regex/index.js
diff --git a/plugin/md_padding/md-padding/node_modules/emoji-regex/package.json b/plugin/global/utils/node_modules/emoji-regex/package.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/emoji-regex/package.json
rename to plugin/global/utils/node_modules/emoji-regex/package.json
diff --git a/plugin/md_padding/md-padding/node_modules/emoji-regex/text.js b/plugin/global/utils/node_modules/emoji-regex/text.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/emoji-regex/text.js
rename to plugin/global/utils/node_modules/emoji-regex/text.js
diff --git a/plugin/md_padding/md-padding/node_modules/find-up/index.js b/plugin/global/utils/node_modules/find-up/index.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/find-up/index.js
rename to plugin/global/utils/node_modules/find-up/index.js
diff --git a/plugin/md_padding/md-padding/node_modules/find-up/package.json b/plugin/global/utils/node_modules/find-up/package.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/find-up/package.json
rename to plugin/global/utils/node_modules/find-up/package.json
diff --git a/plugin/md_padding/md-padding/node_modules/get-caller-file/index.js b/plugin/global/utils/node_modules/get-caller-file/index.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/get-caller-file/index.js
rename to plugin/global/utils/node_modules/get-caller-file/index.js
diff --git a/plugin/md_padding/md-padding/node_modules/get-caller-file/package.json b/plugin/global/utils/node_modules/get-caller-file/package.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/get-caller-file/package.json
rename to plugin/global/utils/node_modules/get-caller-file/package.json
diff --git a/plugin/md_padding/md-padding/node_modules/is-fullwidth-code-point/index.js b/plugin/global/utils/node_modules/is-fullwidth-code-point/index.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/is-fullwidth-code-point/index.js
rename to plugin/global/utils/node_modules/is-fullwidth-code-point/index.js
diff --git a/plugin/md_padding/md-padding/node_modules/is-fullwidth-code-point/package.json b/plugin/global/utils/node_modules/is-fullwidth-code-point/package.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/is-fullwidth-code-point/package.json
rename to plugin/global/utils/node_modules/is-fullwidth-code-point/package.json
diff --git a/plugin/md_padding/md-padding/node_modules/locate-path/index.js b/plugin/global/utils/node_modules/locate-path/index.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/locate-path/index.js
rename to plugin/global/utils/node_modules/locate-path/index.js
diff --git a/plugin/md_padding/md-padding/node_modules/locate-path/package.json b/plugin/global/utils/node_modules/locate-path/package.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/locate-path/package.json
rename to plugin/global/utils/node_modules/locate-path/package.json
diff --git a/plugin/md_padding/md-padding/node_modules/p-limit/index.js b/plugin/global/utils/node_modules/p-limit/index.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/p-limit/index.js
rename to plugin/global/utils/node_modules/p-limit/index.js
diff --git a/plugin/md_padding/md-padding/node_modules/p-limit/package.json b/plugin/global/utils/node_modules/p-limit/package.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/p-limit/package.json
rename to plugin/global/utils/node_modules/p-limit/package.json
diff --git a/plugin/md_padding/md-padding/node_modules/p-locate/index.js b/plugin/global/utils/node_modules/p-locate/index.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/p-locate/index.js
rename to plugin/global/utils/node_modules/p-locate/index.js
diff --git a/plugin/md_padding/md-padding/node_modules/p-locate/package.json b/plugin/global/utils/node_modules/p-locate/package.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/p-locate/package.json
rename to plugin/global/utils/node_modules/p-locate/package.json
diff --git a/plugin/md_padding/md-padding/node_modules/p-try/index.js b/plugin/global/utils/node_modules/p-try/index.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/p-try/index.js
rename to plugin/global/utils/node_modules/p-try/index.js
diff --git a/plugin/md_padding/md-padding/node_modules/p-try/package.json b/plugin/global/utils/node_modules/p-try/package.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/p-try/package.json
rename to plugin/global/utils/node_modules/p-try/package.json
diff --git a/plugin/md_padding/md-padding/node_modules/path-exists/index.js b/plugin/global/utils/node_modules/path-exists/index.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/path-exists/index.js
rename to plugin/global/utils/node_modules/path-exists/index.js
diff --git a/plugin/md_padding/md-padding/node_modules/path-exists/package.json b/plugin/global/utils/node_modules/path-exists/package.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/path-exists/package.json
rename to plugin/global/utils/node_modules/path-exists/package.json
diff --git a/plugin/md_padding/md-padding/node_modules/require-directory/.jshintrc b/plugin/global/utils/node_modules/require-directory/.jshintrc
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/require-directory/.jshintrc
rename to plugin/global/utils/node_modules/require-directory/.jshintrc
diff --git a/plugin/md_padding/md-padding/node_modules/require-directory/.npmignore b/plugin/global/utils/node_modules/require-directory/.npmignore
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/require-directory/.npmignore
rename to plugin/global/utils/node_modules/require-directory/.npmignore
diff --git a/plugin/md_padding/md-padding/node_modules/require-directory/.travis.yml b/plugin/global/utils/node_modules/require-directory/.travis.yml
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/require-directory/.travis.yml
rename to plugin/global/utils/node_modules/require-directory/.travis.yml
diff --git a/plugin/md_padding/md-padding/node_modules/require-directory/index.js b/plugin/global/utils/node_modules/require-directory/index.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/require-directory/index.js
rename to plugin/global/utils/node_modules/require-directory/index.js
diff --git a/plugin/md_padding/md-padding/node_modules/require-directory/package.json b/plugin/global/utils/node_modules/require-directory/package.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/require-directory/package.json
rename to plugin/global/utils/node_modules/require-directory/package.json
diff --git a/plugin/md_padding/md-padding/node_modules/require-main-filename/index.js b/plugin/global/utils/node_modules/require-main-filename/index.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/require-main-filename/index.js
rename to plugin/global/utils/node_modules/require-main-filename/index.js
diff --git a/plugin/md_padding/md-padding/node_modules/require-main-filename/package.json b/plugin/global/utils/node_modules/require-main-filename/package.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/require-main-filename/package.json
rename to plugin/global/utils/node_modules/require-main-filename/package.json
diff --git a/plugin/md_padding/md-padding/node_modules/set-blocking/index.js b/plugin/global/utils/node_modules/set-blocking/index.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/set-blocking/index.js
rename to plugin/global/utils/node_modules/set-blocking/index.js
diff --git a/plugin/md_padding/md-padding/node_modules/set-blocking/package.json b/plugin/global/utils/node_modules/set-blocking/package.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/set-blocking/package.json
rename to plugin/global/utils/node_modules/set-blocking/package.json
diff --git a/plugin/md_padding/md-padding/node_modules/string-width/index.js b/plugin/global/utils/node_modules/string-width/index.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/string-width/index.js
rename to plugin/global/utils/node_modules/string-width/index.js
diff --git a/plugin/md_padding/md-padding/node_modules/string-width/package.json b/plugin/global/utils/node_modules/string-width/package.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/string-width/package.json
rename to plugin/global/utils/node_modules/string-width/package.json
diff --git a/plugin/md_padding/md-padding/node_modules/strip-ansi/index.js b/plugin/global/utils/node_modules/strip-ansi/index.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/strip-ansi/index.js
rename to plugin/global/utils/node_modules/strip-ansi/index.js
diff --git a/plugin/md_padding/md-padding/node_modules/strip-ansi/package.json b/plugin/global/utils/node_modules/strip-ansi/package.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/strip-ansi/package.json
rename to plugin/global/utils/node_modules/strip-ansi/package.json
diff --git a/plugin/md_padding/md-padding/node_modules/which-module/index.js b/plugin/global/utils/node_modules/which-module/index.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/which-module/index.js
rename to plugin/global/utils/node_modules/which-module/index.js
diff --git a/plugin/md_padding/md-padding/node_modules/which-module/package.json b/plugin/global/utils/node_modules/which-module/package.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/which-module/package.json
rename to plugin/global/utils/node_modules/which-module/package.json
diff --git a/plugin/md_padding/md-padding/node_modules/wrap-ansi/index.js b/plugin/global/utils/node_modules/wrap-ansi/index.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/wrap-ansi/index.js
rename to plugin/global/utils/node_modules/wrap-ansi/index.js
diff --git a/plugin/md_padding/md-padding/node_modules/wrap-ansi/package.json b/plugin/global/utils/node_modules/wrap-ansi/package.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/wrap-ansi/package.json
rename to plugin/global/utils/node_modules/wrap-ansi/package.json
diff --git a/plugin/md_padding/md-padding/node_modules/y18n/index.js b/plugin/global/utils/node_modules/y18n/index.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/y18n/index.js
rename to plugin/global/utils/node_modules/y18n/index.js
diff --git a/plugin/md_padding/md-padding/node_modules/y18n/package.json b/plugin/global/utils/node_modules/y18n/package.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/y18n/package.json
rename to plugin/global/utils/node_modules/y18n/package.json
diff --git a/plugin/md_padding/md-padding/node_modules/yargs-parser/index.js b/plugin/global/utils/node_modules/yargs-parser/index.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs-parser/index.js
rename to plugin/global/utils/node_modules/yargs-parser/index.js
diff --git a/plugin/md_padding/md-padding/node_modules/yargs-parser/lib/tokenize-arg-string.js b/plugin/global/utils/node_modules/yargs-parser/lib/tokenize-arg-string.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs-parser/lib/tokenize-arg-string.js
rename to plugin/global/utils/node_modules/yargs-parser/lib/tokenize-arg-string.js
diff --git a/plugin/md_padding/md-padding/node_modules/yargs-parser/package.json b/plugin/global/utils/node_modules/yargs-parser/package.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs-parser/package.json
rename to plugin/global/utils/node_modules/yargs-parser/package.json
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/build/lib/apply-extends.js b/plugin/global/utils/node_modules/yargs/build/lib/apply-extends.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/build/lib/apply-extends.js
rename to plugin/global/utils/node_modules/yargs/build/lib/apply-extends.js
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/build/lib/argsert.js b/plugin/global/utils/node_modules/yargs/build/lib/argsert.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/build/lib/argsert.js
rename to plugin/global/utils/node_modules/yargs/build/lib/argsert.js
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/build/lib/command.js b/plugin/global/utils/node_modules/yargs/build/lib/command.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/build/lib/command.js
rename to plugin/global/utils/node_modules/yargs/build/lib/command.js
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/build/lib/common-types.js b/plugin/global/utils/node_modules/yargs/build/lib/common-types.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/build/lib/common-types.js
rename to plugin/global/utils/node_modules/yargs/build/lib/common-types.js
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/build/lib/completion-templates.js b/plugin/global/utils/node_modules/yargs/build/lib/completion-templates.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/build/lib/completion-templates.js
rename to plugin/global/utils/node_modules/yargs/build/lib/completion-templates.js
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/build/lib/completion.js b/plugin/global/utils/node_modules/yargs/build/lib/completion.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/build/lib/completion.js
rename to plugin/global/utils/node_modules/yargs/build/lib/completion.js
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/build/lib/is-promise.js b/plugin/global/utils/node_modules/yargs/build/lib/is-promise.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/build/lib/is-promise.js
rename to plugin/global/utils/node_modules/yargs/build/lib/is-promise.js
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/build/lib/levenshtein.js b/plugin/global/utils/node_modules/yargs/build/lib/levenshtein.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/build/lib/levenshtein.js
rename to plugin/global/utils/node_modules/yargs/build/lib/levenshtein.js
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/build/lib/middleware.js b/plugin/global/utils/node_modules/yargs/build/lib/middleware.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/build/lib/middleware.js
rename to plugin/global/utils/node_modules/yargs/build/lib/middleware.js
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/build/lib/obj-filter.js b/plugin/global/utils/node_modules/yargs/build/lib/obj-filter.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/build/lib/obj-filter.js
rename to plugin/global/utils/node_modules/yargs/build/lib/obj-filter.js
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/build/lib/parse-command.js b/plugin/global/utils/node_modules/yargs/build/lib/parse-command.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/build/lib/parse-command.js
rename to plugin/global/utils/node_modules/yargs/build/lib/parse-command.js
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/build/lib/process-argv.js b/plugin/global/utils/node_modules/yargs/build/lib/process-argv.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/build/lib/process-argv.js
rename to plugin/global/utils/node_modules/yargs/build/lib/process-argv.js
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/build/lib/usage.js b/plugin/global/utils/node_modules/yargs/build/lib/usage.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/build/lib/usage.js
rename to plugin/global/utils/node_modules/yargs/build/lib/usage.js
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/build/lib/validation.js b/plugin/global/utils/node_modules/yargs/build/lib/validation.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/build/lib/validation.js
rename to plugin/global/utils/node_modules/yargs/build/lib/validation.js
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/build/lib/yargs.js b/plugin/global/utils/node_modules/yargs/build/lib/yargs.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/build/lib/yargs.js
rename to plugin/global/utils/node_modules/yargs/build/lib/yargs.js
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/build/lib/yerror.js b/plugin/global/utils/node_modules/yargs/build/lib/yerror.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/build/lib/yerror.js
rename to plugin/global/utils/node_modules/yargs/build/lib/yerror.js
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/index.js b/plugin/global/utils/node_modules/yargs/index.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/index.js
rename to plugin/global/utils/node_modules/yargs/index.js
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/locales/be.json b/plugin/global/utils/node_modules/yargs/locales/be.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/locales/be.json
rename to plugin/global/utils/node_modules/yargs/locales/be.json
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/locales/de.json b/plugin/global/utils/node_modules/yargs/locales/de.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/locales/de.json
rename to plugin/global/utils/node_modules/yargs/locales/de.json
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/locales/en.json b/plugin/global/utils/node_modules/yargs/locales/en.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/locales/en.json
rename to plugin/global/utils/node_modules/yargs/locales/en.json
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/locales/es.json b/plugin/global/utils/node_modules/yargs/locales/es.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/locales/es.json
rename to plugin/global/utils/node_modules/yargs/locales/es.json
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/locales/fi.json b/plugin/global/utils/node_modules/yargs/locales/fi.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/locales/fi.json
rename to plugin/global/utils/node_modules/yargs/locales/fi.json
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/locales/fr.json b/plugin/global/utils/node_modules/yargs/locales/fr.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/locales/fr.json
rename to plugin/global/utils/node_modules/yargs/locales/fr.json
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/locales/hi.json b/plugin/global/utils/node_modules/yargs/locales/hi.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/locales/hi.json
rename to plugin/global/utils/node_modules/yargs/locales/hi.json
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/locales/hu.json b/plugin/global/utils/node_modules/yargs/locales/hu.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/locales/hu.json
rename to plugin/global/utils/node_modules/yargs/locales/hu.json
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/locales/id.json b/plugin/global/utils/node_modules/yargs/locales/id.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/locales/id.json
rename to plugin/global/utils/node_modules/yargs/locales/id.json
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/locales/it.json b/plugin/global/utils/node_modules/yargs/locales/it.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/locales/it.json
rename to plugin/global/utils/node_modules/yargs/locales/it.json
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/locales/ja.json b/plugin/global/utils/node_modules/yargs/locales/ja.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/locales/ja.json
rename to plugin/global/utils/node_modules/yargs/locales/ja.json
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/locales/ko.json b/plugin/global/utils/node_modules/yargs/locales/ko.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/locales/ko.json
rename to plugin/global/utils/node_modules/yargs/locales/ko.json
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/locales/nb.json b/plugin/global/utils/node_modules/yargs/locales/nb.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/locales/nb.json
rename to plugin/global/utils/node_modules/yargs/locales/nb.json
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/locales/nl.json b/plugin/global/utils/node_modules/yargs/locales/nl.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/locales/nl.json
rename to plugin/global/utils/node_modules/yargs/locales/nl.json
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/locales/nn.json b/plugin/global/utils/node_modules/yargs/locales/nn.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/locales/nn.json
rename to plugin/global/utils/node_modules/yargs/locales/nn.json
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/locales/pirate.json b/plugin/global/utils/node_modules/yargs/locales/pirate.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/locales/pirate.json
rename to plugin/global/utils/node_modules/yargs/locales/pirate.json
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/locales/pl.json b/plugin/global/utils/node_modules/yargs/locales/pl.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/locales/pl.json
rename to plugin/global/utils/node_modules/yargs/locales/pl.json
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/locales/pt.json b/plugin/global/utils/node_modules/yargs/locales/pt.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/locales/pt.json
rename to plugin/global/utils/node_modules/yargs/locales/pt.json
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/locales/pt_BR.json b/plugin/global/utils/node_modules/yargs/locales/pt_BR.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/locales/pt_BR.json
rename to plugin/global/utils/node_modules/yargs/locales/pt_BR.json
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/locales/ru.json b/plugin/global/utils/node_modules/yargs/locales/ru.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/locales/ru.json
rename to plugin/global/utils/node_modules/yargs/locales/ru.json
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/locales/th.json b/plugin/global/utils/node_modules/yargs/locales/th.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/locales/th.json
rename to plugin/global/utils/node_modules/yargs/locales/th.json
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/locales/tr.json b/plugin/global/utils/node_modules/yargs/locales/tr.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/locales/tr.json
rename to plugin/global/utils/node_modules/yargs/locales/tr.json
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/locales/zh_CN.json b/plugin/global/utils/node_modules/yargs/locales/zh_CN.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/locales/zh_CN.json
rename to plugin/global/utils/node_modules/yargs/locales/zh_CN.json
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/locales/zh_TW.json b/plugin/global/utils/node_modules/yargs/locales/zh_TW.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/locales/zh_TW.json
rename to plugin/global/utils/node_modules/yargs/locales/zh_TW.json
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/package.json b/plugin/global/utils/node_modules/yargs/package.json
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/package.json
rename to plugin/global/utils/node_modules/yargs/package.json
diff --git a/plugin/md_padding/md-padding/node_modules/yargs/yargs.js b/plugin/global/utils/node_modules/yargs/yargs.js
similarity index 100%
rename from plugin/md_padding/md-padding/node_modules/yargs/yargs.js
rename to plugin/global/utils/node_modules/yargs/yargs.js
diff --git a/plugin/md_padding/md-padding/package-lock.json b/plugin/global/utils/package-lock.json
similarity index 100%
rename from plugin/md_padding/md-padding/package-lock.json
rename to plugin/global/utils/package-lock.json
diff --git a/plugin/md_padding/md-padding/package.json b/plugin/global/utils/package.json
similarity index 100%
rename from plugin/md_padding/md-padding/package.json
rename to plugin/global/utils/package.json
diff --git a/plugin/global/toml/compiler.js b/plugin/global/utils/toml/compiler.js
similarity index 100%
rename from plugin/global/toml/compiler.js
rename to plugin/global/utils/toml/compiler.js
diff --git a/plugin/global/toml/index.js b/plugin/global/utils/toml/index.js
similarity index 100%
rename from plugin/global/toml/index.js
rename to plugin/global/utils/toml/index.js
diff --git a/plugin/global/toml/parser.js b/plugin/global/utils/toml/parser.js
similarity index 100%
rename from plugin/global/toml/parser.js
rename to plugin/global/utils/toml/parser.js
diff --git a/plugin/go_top.js b/plugin/go_top.js
index 868c3fdd..e6970231 100644
--- a/plugin/go_top.js
+++ b/plugin/go_top.js
@@ -1,42 +1,49 @@
-(() => {
- const config = global._pluginUtils.getPluginSetting("go_top");
+class goTopPlugin extends global._basePlugin {
+ html = () => {
+ const goTop = document.createElement("div");
+ goTop.id = this.config.DIV_ID;
+ goTop.style.position = "fixed";
+ goTop.style.right = "50px";
+ goTop.style.bottom = "50px";
+ goTop.style.zIndex = "99999";
+ goTop.style.cursor = "pointer";
+ goTop.style.fontSize = "50px";
+ goTop.style.color = this.config.COLOR;
+ goTop.style.display = "none";
+ const i = document.createElement("i");
+ i.classList.add("ion-arrow-up-c");
+ goTop.appendChild(i);
+ document.querySelector("body").appendChild(goTop);
+ }
+
+ init = () => {
+ this.goTop = document.getElementById(this.config.DIV_ID);
+ }
- const goTop = document.createElement("div");
- goTop.id = config.DIV_ID;
- goTop.style.position = "fixed";
- goTop.style.right = "50px";
- goTop.style.bottom = "50px";
- goTop.style.zIndex = "99999";
- goTop.style.cursor = "pointer";
- goTop.style.fontSize = "50px";
- goTop.style.color = config.COLOR;
- goTop.style.display = "none";
- const i = document.createElement("i");
- i.classList.add("ion-arrow-up-c");
- goTop.appendChild(i);
- document.querySelector("body").appendChild(goTop);
+ process = () => {
+ this.init();
- document.getElementById(config.DIV_ID).addEventListener("click", ev => {
- call();
- ev.preventDefault();
- ev.stopPropagation();
- });
+ document.getElementById(this.config.DIV_ID).addEventListener("click", ev => {
+ this.call();
+ ev.preventDefault();
+ ev.stopPropagation();
+ });
- const content = document.querySelector("content");
- content.addEventListener("scroll", ev => {
- goTop.style.display = (content.scrollTop > config.THRESHOLD) ? "" : "none";
- })
+ const content = document.querySelector("content");
+ content.addEventListener("scroll", () => {
+ this.goTop.style.display = (content.scrollTop > this.config.THRESHOLD) ? "" : "none";
+ })
+ }
- const call = direction => {
+ call = direction => {
let scrollTop = '0';
if (direction === "go-bottom") {
scrollTop = document.querySelector("#write").getBoundingClientRect().height;
}
- $("content").animate({scrollTop: scrollTop}, config.SCROLL_TIME);
+ $("content").animate({scrollTop: scrollTop}, this.config.SCROLL_TIME);
}
+}
- module.exports = {
- call,
- };
- console.log("go_top.js had been injected");
-})()
\ No newline at end of file
+module.exports = {
+ plugin: goTopPlugin,
+};
\ No newline at end of file
diff --git a/plugin/index.js b/plugin/index.js
index fac94823..f8063ebb 100644
--- a/plugin/index.js
+++ b/plugin/index.js
@@ -1,203 +1,5 @@
-/* 1. 整个插件系统向外暴露的变量:
- 1. global._pluginsHadInjected: 是否所有的插件都已加载完毕
- 2. global._plugins: 全部的插件
- 3. global._pluginUtils: 通用的工具
- 4. global._pluginSettings: 全部的插件配置
- 2. global._plugins使用声明式(声明替代代码开发)
- 1. name: 展示的插件名
- 2. fixed_name: 固定的插件名(可以看作是插件的UUID)
- 3. enable: 是否启用
- 4. clickable: 是否在右键菜单中可点击
- 5. call: 插件的入口函数
- 6. call_args: 固定的插件参数,如果存在,那么将在右键菜单中会显示第三级菜单,当用户点击后就会传递参数给call函数
- 7. dynamic_call_args_generator: 插件动态参数,用户在不同区域、不同时间点击右键菜单时,显示不同的第三级菜单
- 8. meta: 用于传递自定义变量
- 3. 核心逻辑位于right_click_menu.js中,
- 4. 使用例子可以看collapse_paragraph.js。此插件实现了用户在不同区域(标题处点击、非标题处点击)右键菜单会有不同的第三级菜单。
-*/
window.onload = () => {
- global._pluginsHadInjected = false;
- global._plugins = [
- {
- name: "标签页管理",
- fixed_name: "window_tab",
- src: "./plugin/window_tab/window_tab.js",
- clickable: true,
- },
- {
- name: "全局多关键字搜索",
- fixed_name: "search_multi",
- src: "./plugin/search_multi.js",
- clickable: true,
- },
- {
- name: "多关键字高亮",
- fixed_name: "multi_highlighter",
- src: "./plugin/multi_highlighter/index.js",
- clickable: true,
- },
- {
- name: "表格调整",
- fixed_name: "resize_table",
- src: "./plugin/resize_table.js",
- clickable: false,
- },
- {
- name: "类别大纲",
- fixed_name: "outline",
- src: "./plugin/outline.js",
- clickable: true,
- },
- {
- name: "命令行环境",
- fixed_name: "commander",
- src: "./plugin/commander.js",
- clickable: true,
- },
- {
- name: "中英文混排优化",
- fixed_name: "md_padding",
- src: "./plugin/md_padding/index.js",
- clickable: true,
- },
- {
- name: "只读模式",
- fixed_name: "read_only",
- src: "./plugin/read_only.js",
- clickable: true,
- },
- {
- name: "图片调整",
- fixed_name: "resize_image",
- src: "./plugin/resize_image.js",
- clickable: true,
- },
- {
- name: "表格增强",
- fixed_name: "datatables",
- src: "./plugin/datatables/index.js",
- clickable: true,
- },
- {
- name: "一键到顶",
- fixed_name: "go_top",
- src: "./plugin/go_top.js",
- clickable: true,
- },
- {
- name: "思维导图",
- fixed_name: "mindmap",
- src: "./plugin/mindmap.js",
- clickable: true,
- },
- {
- name: "自动编号",
- fixed_name: "auto_number",
- src: "./plugin/auto_number.js",
- clickable: true,
- },
- {
- name: "代码块增强",
- fixed_name: "fence_enhance",
- src: "./plugin/fence_enhance.js",
- clickable: true,
- },
- {
- name: "章节折叠",
- fixed_name: "collapse_paragraph",
- src: "./plugin/collapse_paragraph.js",
- clickable: true,
- },
- {
- name: "文件计数",
- fixed_name: "file_counter",
- src: "./plugin/file_counter.js",
- clickable: false,
- },
- {
- name: "文段截断",
- fixed_name: "truncate_text",
- src: "./plugin/truncate_text.js",
- clickable: true,
- },
- {
- name: "导出增强",
- fixed_name: "export_enhance",
- src: "./plugin/export_enhance.js",
- clickable: true,
- },
- {
- name: "mermaid替换",
- fixed_name: "mermaid_replace",
- src: "./plugin/mermaid_replace/index.js",
- clickable: false,
- },
- {
- name: "右键菜单",
- fixed_name: "right_click_menu",
- src: "./plugin/right_click_menu.js",
- clickable: true,
- },
- {
- name: "测试专用",
- fixed_name: "test",
- src: "./plugin/test.js",
- clickable: false,
- },
- ]
-
- const loadPlugins = (join, access, dirname) => {
- const promises = [];
- global._plugins.forEach(plugin => {
- plugin.enable = global._pluginSettings[plugin.fixed_name].ENABLE;
- if (!plugin.enable) return;
- const filepath = join(dirname, plugin.src);
- const promise = new Promise(resolve => {
- access(filepath, err => {
- if (!err) {
- try {
- const {call, callArgs, dynamicCallArgsGenerator, meta} = reqnode(filepath);
- plugin.call = call || null;
- plugin.call_args = callArgs || null;
- plugin.dynamic_call_args_generator = dynamicCallArgsGenerator || null;
- plugin.meta = meta || null;
- } catch (e) {
- plugin.enable = false;
- console.log("plugin err:", e);
- }
- } else {
- plugin.enable = false;
- console.log("has no path:", filepath);
- }
- resolve(plugin);
- })
- })
- promises.push(promise);
- })
-
- Promise.all(promises).then(() => global._pluginsHadInjected = true)
- }
-
- const loadUtils = (join, dirname) => {
- const filepath = join(dirname, "./plugin/global/utils.js");
- global._pluginUtils = reqnode(filepath);
- }
-
- const loadSettings = (join, dirname) => {
- const configPath = join(dirname, "./plugin/global/settings.js");
- const {pluginSettings} = reqnode(configPath);
- global._pluginSettings = pluginSettings;
- }
-
- const load = () => {
- const join = reqnode("path").join;
- const access = reqnode("fs").access;
- const dirname = global.dirname || global.__dirname;
-
- loadUtils(join, dirname);
- loadSettings(join, dirname);
- loadPlugins(join, access, dirname);
- }
-
- load();
+ const pluginFile = reqnode('path').join(global.dirname || global.__dirname, "./plugin/global/core/plugin.js");
+ const {process} = reqnode(pluginFile);
+ new process().run();
}
diff --git a/plugin/md_padding.js b/plugin/md_padding.js
new file mode 100644
index 00000000..81d350ac
--- /dev/null
+++ b/plugin/md_padding.js
@@ -0,0 +1,42 @@
+class mdPaddingPlugin extends global._basePlugin {
+ hotkey = () => {
+ return [{
+ hotkey: this.config.HOTKEY,
+ callback: this.call,
+ }]
+ }
+
+ read = filepath => this.utils.Package.Fs.readFileSync(filepath, 'utf-8');
+ write = (filepath, content) => this.utils.Package.Fs.writeFileSync(filepath, content);
+ save = () => File.saveUseNode();
+
+ reload = content => {
+ // const scrollTop = document.querySelector("content").scrollTop;
+ File.reloadContent(content, {"fromDiskChange": false})
+ // document.querySelector("content").scrollTop = scrollTop;
+ };
+
+ getFormatter = () => {
+ const {padMarkdown} = this.utils.requireFilePath("./plugin/global/utils/md-padding");
+ return padMarkdown;
+ }
+
+ formatFile = content => {
+ const formatter = this.getFormatter();
+ return formatter(content)
+ }
+
+ call = () => {
+ this.save().then(() => {
+ const filepath = this.utils.getFilePath();
+ const content = this.read(filepath);
+ const formattedContent = this.formatFile(content);
+ this.write(filepath, formattedContent);
+ this.reload(formattedContent);
+ })
+ }
+}
+
+module.exports = {
+ plugin: mdPaddingPlugin
+};
\ No newline at end of file
diff --git a/plugin/md_padding/index.js b/plugin/md_padding/index.js
deleted file mode 100644
index 4b15fb48..00000000
--- a/plugin/md_padding/index.js
+++ /dev/null
@@ -1,44 +0,0 @@
-(() => {
- const config = global._pluginUtils.getPluginSetting("md_padding");
-
- const read = filepath => global._pluginUtils.Package.Fs.readFileSync(filepath, 'utf-8');
- const write = (filepath, content) => global._pluginUtils.Package.Fs.writeFileSync(filepath, content);
- const save = () => File.saveUseNode();
- const reload = content => {
- // const scrollTop = document.querySelector("content").scrollTop;
- File.reloadContent(content, {"fromDiskChange": false})
- // document.querySelector("content").scrollTop = scrollTop;
- };
-
- const getFormatter = () => {
- const {padMarkdown} = global._pluginUtils.requireFile("./plugin/md_padding/md-padding");
- return padMarkdown;
- }
-
- const call = () => {
- save().then(() => {
- const filepath = global._pluginUtils.getFilePath();
- const content = read(filepath);
- const formattedContent = formatFile(content);
- write(filepath, formattedContent);
- reload(formattedContent);
- })
- }
-
- const formatFile = content => {
- const formatter = getFormatter();
- return formatter(content)
- }
-
- global._pluginUtils.registerWindowHotkey(config.HOTKEY, call);
-
- module.exports = {
- call,
- meta: {
- formatFile,
- call,
- }
- };
-
- console.log("md_padding.js had been injected");
-})()
\ No newline at end of file
diff --git a/plugin/mermaid_replace/index.js b/plugin/mermaid_replace/index.js
index 61e49fc8..23ff4728 100644
--- a/plugin/mermaid_replace/index.js
+++ b/plugin/mermaid_replace/index.js
@@ -1,16 +1,20 @@
-(() => {
- // 在 cdnjs.com 或者 unpkg.com 上找到最新版本的 `mermaid.min.js`,eg: https://unpkg.com/mermaid/dist/mermaid.min.js
- // 之后替换 mermaid.min.js 文件。(当前文件版本: 9.3.0)
- global._pluginUtils.loopDetector(
- () => window.editor && window.editor.diagrams && window.mermaidAPI,
- () => {
- const filepath = global._pluginUtils.joinPath("./plugin/mermaid_replace/mermaid.min.js");
- $.getScript(`file:///${filepath}`).then(() => {
- mermaidAPI = mermaid.mermaidAPI;
- window.editor.diagrams.refreshDiagram(editor);
- });
- }
- );
+class mermaidReplacePlugin extends global._basePlugin {
+ process = () => {
+ // 在 cdnjs.com 或者 unpkg.com 上找到最新版本的 `mermaid.min.js`,eg: https://unpkg.com/mermaid/dist/mermaid.min.js
+ // 之后替换 mermaid.min.js 文件。(当前文件版本: 9.3.0)
+ this.utils.loopDetector(
+ () => window.editor && window.editor.diagrams && window.mermaidAPI,
+ () => {
+ const filepath = this.utils.joinPath("./plugin/mermaid_replace/mermaid.min.js");
+ $.getScript(`file:///${filepath}`).then(() => {
+ window.mermaidAPI = mermaid.mermaidAPI;
+ window.editor.diagrams.refreshDiagram(editor);
+ });
+ }
+ );
+ }
+}
- console.log("mermaid_replace.js had been injected");
-})()
\ No newline at end of file
+module.exports = {
+ plugin: mermaidReplacePlugin
+};
\ No newline at end of file
diff --git a/plugin/mindmap.js b/plugin/mindmap.js
index c5136ee6..a0044617 100644
--- a/plugin/mindmap.js
+++ b/plugin/mindmap.js
@@ -1,9 +1,23 @@
-(() => {
- const config = global._pluginUtils.getPluginSetting("mindmap");
+class mindmapPlugin extends global._basePlugin {
+ init = () => {
+ this.paragraphList = ["H0", "H1", "H2", "H3", "H4", "H5", "H6"];
+ this.callArgs = [
+ {
+ arg_name: "复制到剪切板:mindmap",
+ arg_value: "set_clipboard_mindmap"
+ },
+ {
+ arg_name: "复制到剪切板:graph",
+ arg_value: "set_clipboard_graph"
+ },
+ ];
+ }
- const paragraphList = ["H0", "H1", "H2", "H3", "H4", "H5", "H6"];
+ process = () => {
+ this.init();
+ }
- const getFileName = () => {
+ getFileName = () => {
let filename = File.getFileName();
const idx = filename.lastIndexOf(".");
if (idx !== -1) {
@@ -12,27 +26,34 @@
return filename
}
- const cleanMindMapTitle = title => `("${title.replace(/"/g, "")}")`;
- const cleanGraphTitle = title => `("${title.replace(/"/g, "")}")`;
+ cleanMindMapTitle = title => `("${title.replace(/"/g, "")}")`;
+ cleanGraphTitle = title => `("${title.replace(/"/g, "")}")`;
- const wrapMermaid = content => `\`\`\`mermaid\n${content}\`\`\``;
+ wrapMermaid = content => "```mermaid\n" + this.wrapErrorMsg() + content + "```";
+ wrapErrorMsg = () => {
+ if (!window.mermaidAPI.defaultConfig.mindmap) {
+ const url = "https://mermaid.live/";
+ return `%%你的mermaid组件版本过低,不支持mindmap语法。内容已复制到剪贴板,请粘贴到${url}查看\n`
+ }
+ return ""
+ }
- const mindmap = (pList, root) => {
+ mindmap = (pList, root) => {
const lines = [
"mindmap", "\n",
- "\t", `root${cleanMindMapTitle(root)}`, "\n",
+ "\t", `root${this.cleanMindMapTitle(root)}`, "\n",
];
- pList.forEach(ele => lines.push("\t".repeat(ele.levelIdx + 1), cleanMindMapTitle(ele.title), "\n"))
- return wrapMermaid(lines.join(""))
+ pList.forEach(ele => lines.push("\t".repeat(ele.levelIdx + 1), this.cleanMindMapTitle(ele.title), "\n"))
+ return this.wrapMermaid(lines.join(""))
}
- const graph = (pList, root) => {
+ graph = (pList, root) => {
const getItemTitle = item => {
if (item.used) {
return item.id
}
item.used = true;
- const title = cleanGraphTitle(item.title);
+ const title = this.cleanGraphTitle(item.title);
return item.id + title
}
@@ -58,11 +79,11 @@
lines.push(getParentItemTitle(item), "-->", getItemTitle(item), "\n");
})
- return wrapMermaid(lines.join(""))
+ return this.wrapMermaid(lines.join(""))
}
- const dynamicCallArgsGenerator = anchorNode => {
- if (global._pluginUtils.isBetaVersion) {
+ dynamicCallArgsGenerator = anchorNode => {
+ if (this.utils.isBetaVersion) {
const target = anchorNode.closest(`#write > p[mdtype="paragraph"]`);
if (!target) return;
if (target.querySelector("p > span")) return;
@@ -83,29 +104,18 @@
]
}
- const callArgs = [
- {
- arg_name: "复制到剪切板:mindmap",
- arg_value: "set_clipboard_mindmap"
- },
- {
- arg_name: "复制到剪切板:graph",
- arg_value: "set_clipboard_graph"
- },
- ];
-
- const call = type => {
+ call = type => {
const pList = [];
document.querySelectorAll("#write > .md-heading").forEach(ele => {
const tagName = ele.tagName;
- const levelIdx = paragraphList.indexOf(tagName);
+ const levelIdx = this.paragraphList.indexOf(tagName);
const title = ele.firstElementChild.textContent;
pList.push({tagName, title, levelIdx});
})
if (pList.length === 0) return
- let root = getFileName();
+ let root = this.getFileName();
if (pList.filter(ele => ele.tagName === pList[0].tagName).length === 1) {
root = pList[0].title;
pList.shift();
@@ -113,9 +123,9 @@
let result;
if (type === "set_clipboard_mindmap" || type === "insert_mindmap") {
- result = mindmap(pList, root);
+ result = this.mindmap(pList, root);
} else if (type === "set_clipboard_graph" || type === "insert_graph") {
- result = graph(pList, root);
+ result = this.graph(pList, root);
}
navigator.clipboard.writeText(result).then(() => {
@@ -125,12 +135,8 @@
}
});
}
+}
- module.exports = {
- call,
- callArgs,
- dynamicCallArgsGenerator,
- };
-
- console.log("mindmap.js had been injected");
-})()
\ No newline at end of file
+module.exports = {
+ plugin: mindmapPlugin
+};
diff --git a/plugin/multi_highlighter/index.js b/plugin/multi_highlighter/index.js
index d5cbffc2..7cb9a933 100644
--- a/plugin/multi_highlighter/index.js
+++ b/plugin/multi_highlighter/index.js
@@ -1,35 +1,36 @@
-(() => {
- /*
- 1. 对比普通网页,给Typora添加多关键字高亮有两个难点:可编辑、延迟加载Fence
- 2. 可编辑:
- 1. 给关键字添加高亮是通过添加标签实现的。但是为了保证数据安全,Typora是不允许需求#write的标签结构的。所以需要及时地撤销添加的标签,恢复可用。
- 2. 同时,Typora监控着#write的结构,以确保发生异常时能进行回滚操作。所以撤销添加的标签还不够,你还需要阅读frame.js研究Typora是怎么监控的,然后找出刷新方法。代码中的refreshFences函数就是用于此。
- 3. 延迟加载Fence:
- 1. Typora的代码块是延迟加载的。对大文件来说,当你滚动到文档底部时,那里的代码块才会进行加载。
- 2. 这就导致了你添加的高亮标签会被刷掉,你需要重新搜索高亮一次。
- 3. 每个延迟加载的代码块都要全文搜索高亮一次肯定不太好,所以你需要少量的、针对性的搜索高亮,然后将这些高亮标签全都记录在案。fenceMultiHighlighterList就是用于此。整个过程也会消耗大量内存。
- 4. 同时你还需要提供高亮关键字的定位功能,所以你必须协同每个MultiHighlighter对象。
- 5. 这种情况还造成了定位功能的时机问题。本来是简单的管理MultiHighlighter对象就行。现在变成了:
- 1. 判断下一个关键字是否处于未加载的Fence中
- 2. 若是,则需要记录这个关键字的特征,滚动到这个Fence,触发Fence的加载
- 3. 使用装饰器劫持Fence的加载函数,并再函数的最后执行搜索高亮操作。然后根据上面的特征找出特定的关键字(Fence中可能有多个关键字),再将滚动条滚动到这个位置,最后在对这个关键字提供位置提示。
- 4. 将这个过程产生的高亮对象记录在案,并在合适的时机取消高亮。
- 4. 这整套下来,导致逻辑被切的稀碎。同时你还需要注意很多小细节,比如图片和链接上的关键字,你需要显示其markdown源码后才能定位。
- 5. 解决方式:我本来想使用类似于Golang的channel。channel非常适合这种逻辑代码各种跳跃的情况,且十分优雅。想来想去,去他妈,直接硬撸算了,全局变量直接上,没有遵循任何设计原则,代码非常难懂。
- 6. 下面代码就是本着【又不是不能用】的心态码的,只追求实现速度。若你有心重构,我帮你抽象出了multi_highlighter.js文件,可以方便的搜索并添加高亮标签,接下来你需要的就是和Typora混淆后的frame.js做斗争,和Typora各自特性作斗争。
- */
- const config = global._pluginUtils.getPluginSetting("multi_highlighter");
-
- (() => {
+/*
+1. 对比普通网页,给Typora添加多关键字高亮有两个难点:可编辑、延迟加载Fence
+2. 可编辑:
+ 1. 给关键字添加高亮是通过添加标签实现的。但是为了保证数据安全,Typora是不允许需求#write的标签结构的。所以需要及时地撤销添加的标签,恢复可用。
+ 2. 同时,Typora监控着#write的结构,以确保发生异常时能进行回滚操作。所以撤销添加的标签还不够,你还需要阅读frame.js研究Typora是怎么监控的,然后找出刷新方法。代码中的refreshFences函数就是用于此。
+3. 延迟加载Fence:
+ 1. Typora的代码块是延迟加载的。对大文件来说,当你滚动到文档底部时,那里的代码块才会进行加载。
+ 2. 这就导致了你添加的高亮标签会被刷掉,你需要重新搜索高亮一次。
+ 3. 每个延迟加载的代码块都要全文搜索高亮一次肯定不太好,所以你需要少量的、针对性的搜索高亮,然后将这些高亮标签全都记录在案。fenceMultiHighlighterList就是用于此。整个过程也会消耗大量内存。
+ 4. 同时你还需要提供高亮关键字的定位功能,所以你必须协同每个MultiHighlighter对象。
+ 5. 这种情况还造成了定位功能的时机问题。本来是简单的管理MultiHighlighter对象就行。现在变成了:
+ 1. 判断下一个关键字是否处于未加载的Fence中
+ 2. 若是,则需要记录这个关键字的特征,滚动到这个Fence,触发Fence的加载
+ 3. 使用装饰器劫持Fence的加载函数,并再函数的最后执行搜索高亮操作。然后根据上面的特征找出特定的关键字(Fence中可能有多个关键字),再将滚动条滚动到这个位置,最后在对这个关键字提供位置提示。
+ 4. 将这个过程产生的高亮对象记录在案,并在合适的时机取消高亮。
+4. 这整套下来,导致逻辑被切的稀碎。同时你还需要注意很多小细节,比如图片和链接上的关键字,你需要显示其markdown源码后才能定位。
+5. 解决方式:我本来想使用类似于Golang的channel。channel非常适合这种逻辑代码各种跳跃的情况,且十分优雅。想来想去,去他妈,直接硬撸算了,全局变量直接上,没有遵循任何设计原则,代码非常难懂。
+6. 下面代码就是本着【又不是不能用】的心态码的,只追求实现速度。若你有心重构,我帮你抽象出了multi_highlighter.js文件,可以方便的搜索并添加高亮标签,接下来你需要的就是和Typora混淆后的frame.js做斗争,和Typora各自特性作斗争。
+*/
+
+class multiHighlighterPlugin extends global._basePlugin {
+ style = () => {
const run_style = {
- input_width: (config.SHOW_RUN_BUTTON) ? "95%" : "100%",
- case_button_right: (config.SHOW_RUN_BUTTON) ? "32px" : "6px",
- run_button_display: (config.SHOW_RUN_BUTTON) ? "" : "none",
+ input_width: (this.config.SHOW_RUN_BUTTON) ? "95%" : "100%",
+ case_button_right: (this.config.SHOW_RUN_BUTTON) ? "32px" : "6px",
+ run_button_display: (this.config.SHOW_RUN_BUTTON) ? "" : "none",
}
- const colors = config.STYLE_COLOR.map((color, idx) => `.plugin-search-hit${idx} { background-color: ${color}; }`)
+ const colors = this.config.STYLE_COLOR.map((color, idx) => `.plugin-search-hit${idx} { background-color: ${color}; }`)
const colorsStyle = colors.join("\n");
- const css = `
+
+ const textID = "plugin-window-tab-style";
+ const text = `
#plugin-multi-highlighter {
position: fixed;
top: 15%;
@@ -137,13 +138,15 @@
${colorsStyle}
`
- global._pluginUtils.insertStyle("plugin-multi-highlighter-style", css);
+ return {textID, text}
+ }
+ html = () => {
const div = `
`
document.querySelector("header").appendChild(modal);
- })()
-
- const entities = {
- modal: document.getElementById("plugin-outline"),
- header: document.querySelector("#plugin-outline .plugin-outline-header"),
- list: document.querySelector("#plugin-outline .plugin-outline-list"),
- footer: document.querySelector("#plugin-outline .plugin-outline-footer"),
- move: document.querySelector(`#plugin-outline .plugin-outline-icon[Type="move"]`),
}
-
- class _collectUtil {
- constructor() {
- this.paragraphIdx = 0;
- this.tableIdx = 0;
- this.imageIdx = 0;
- this.fenceIdx = 0;
- this.collection = {table: [], image: [], fence: []};
+ init = () => {
+ this.entities = {
+ modal: document.getElementById("plugin-outline"),
+ header: document.querySelector("#plugin-outline .plugin-outline-header"),
+ list: document.querySelector("#plugin-outline .plugin-outline-list"),
+ footer: document.querySelector("#plugin-outline .plugin-outline-footer"),
+ move: document.querySelector(`#plugin-outline .plugin-outline-icon[Type="move"]`),
}
+ this.collectUtil = new _collectUtil(this.config, this.entities);
+ }
- clear() {
- this.paragraphIdx = this.tableIdx = this.imageIdx = this.fenceIdx = 0;
- this.collection = {table: [], image: [], fence: []};
- }
+ process = () => {
+ this.init();
- collect() {
- this.clear();
- const write = document.querySelector("#write");
- for (let ele = write.firstElementChild; ele; ele = ele.nextElementSibling) {
- if (!config.SHOW_HIDDEN && ele.style.display === "none") {
- continue
- }
+ this.utils.dragFixedModal(this.entities.move, this.entities.modal, false);
- const tagName = ele.tagName;
- if (tagName === "H1") {
- this.paragraphIdx = 0;
- this.tableIdx = this.imageIdx = this.fenceIdx = 0;
- continue
- } else if (tagName === "H2") {
- this.paragraphIdx++;
- this.tableIdx = this.imageIdx = this.fenceIdx = 0;
- continue
- }
+ this.utils.decorateOpenFile(null, () => {
+ (this.config.AUTO_REFRESH_WHEN_OPEN_FILE && this.entities.modal.style.display === "block") && setTimeout(this.refresh, 300);
+ })
- const cid = ele.getAttribute("cid");
- // table
- if (tagName === "FIGURE") {
- this.tableIdx++;
- this.collection.table.push({
- cid: cid,
- type: "table",
- paragraphIdx: this.paragraphIdx,
- idx: this.tableIdx
- });
- // fence
- } else if (ele.classList.contains("md-fences")) {
- this.fenceIdx++;
- this.collection.fence.push({
- cid: cid,
- type: "fence",
- paragraphIdx: this.paragraphIdx,
- idx: this.fenceIdx
- });
- // image
- } else if (ele.querySelector("img")) {
- this.imageIdx++;
- this.collection.image.push({
- cid: cid,
- type: "image",
- paragraphIdx: this.paragraphIdx,
- idx: this.imageIdx
- });
- }
- }
- }
+ this.entities.modal.addEventListener("click", ev => {
+ const item = ev.target.closest(".plugin-outline-item");
+ const headerIcon = ev.target.closest(".plugin-outline-header .plugin-outline-icon");
+ const footerIcon = ev.target.closest(".plugin-outline-footer .plugin-outline-icon");
- compare(p) {
- return function (m, n) {
- const cid1 = parseInt(m[p].replace("n", ""));
- const cid2 = parseInt(n[p].replace("n", ""));
- return cid1 - cid2;
- }
- }
+ if (!item && !headerIcon && !footerIcon) return;
- getCollection(Type) {
- if (Type !== "all") {
- return this.collection[Type]
- }
- let list = [];
- for (const type in this.collection) {
- list.push(...this.collection[type])
- }
- list.sort(this.compare("cid"));
- return list
- }
+ ev.stopPropagation();
+ ev.preventDefault();
- setColor = (ele, item, type) => {
- if (type === "all") {
- if (item.type === "table") {
- ele.style.backgroundColor = "aliceblue";
- } else if (item.type === "fence") {
- ele.style.backgroundColor = "antiquewhite";
- } else if (item.type === "image") {
- ele.style.backgroundColor = "beige";
- }
+ if (item) {
+ const cid = item.querySelector("span").getAttribute("data-ref");
+ this.scroll(cid);
+ } else if (footerIcon) {
+ const Type = footerIcon.getAttribute("type");
+ this.collectAndShow(Type);
} else {
- ele.style.backgroundColor = "";
- }
- }
-
- // 简易数据单向绑定
- bindDOM(Type) {
- const typeCollection = this.getCollection(Type);
-
- const first = entities.list.firstElementChild;
- if (first && !first.classList.contains("plugin-outline-item")) {
- entities.list.removeChild(first);
- }
-
- while (typeCollection.length !== entities.list.childElementCount) {
- if (typeCollection.length > entities.list.childElementCount) {
- const div = document.createElement("div");
- div.classList.add("plugin-outline-item");
- div.appendChild(document.createElement("span"));
- entities.list.appendChild(div);
- } else {
- entities.list.removeChild(entities.list.firstElementChild);
+ const Type = headerIcon.getAttribute("type");
+ if (Type === "close") {
+ this.hide();
+ } else if (Type === "refresh") {
+ this.refresh();
+ this.rotate(headerIcon.firstElementChild);
+ } else if (Type === "eye") {
+ this.toggleEye(headerIcon);
+ this.refresh();
}
}
-
- if (entities.list.childElementCount === 0) {
- const div = document.createElement("div");
- div.innerText = "Empty";
- div.style.display = "block";
- div.style.textAlign = "center";
- div.style.padding = "10px";
- entities.list.appendChild(div);
- return
- }
-
- let ele = entities.list.firstElementChild;
- typeCollection.forEach(item => {
- if (config.SET_COLOR_IN_ALL) {
- this.setColor(ele, item, Type);
- }
- const span = ele.firstElementChild;
- span.setAttribute("data-ref", item.cid);
- span.innerText = `${config.SHOW_NAME[item.type]} ${item.paragraphIdx}-${item.idx}`;
- ele = ele.nextElementSibling;
- })
- }
- }
-
- const collectUtil = new _collectUtil();
-
- const collectAndShow = Type => {
- setFooterActive(Type);
- collectUtil.collect();
- collectUtil.bindDOM(Type);
- entities.modal.style.display = "block";
+ })
}
- const collapsePlugin = global._pluginUtils.getPlugin("collapse_paragraph");
- const truncatePlugin = global._pluginUtils.getPlugin("truncate_text");
- const compatibleOtherPlugin = target => {
- if (!target) return;
-
- collapsePlugin && collapsePlugin.meta && collapsePlugin.meta.rollback && collapsePlugin.meta.rollback(target);
- truncatePlugin && truncatePlugin.meta && truncatePlugin.meta.rollback && truncatePlugin.meta.rollback(target);
+ collectAndShow = Type => {
+ this.setFooterActive(Type);
+ this.collectUtil.collect();
+ this.collectUtil.bindDOM(Type);
+ this.entities.modal.style.display = "block";
}
- const scroll = cid => {
+ scroll = cid => {
const target = File.editor.findElemById(cid);
- compatibleOtherPlugin(target[0]);
+ this.utils.showHiddenElementByPlugin(target[0]);
File.editor.focusAndRestorePos();
File.editor.selection.scrollAdjust(target, 10);
File.isFocusMode && File.editor.updateFocusMode(false);
}
- const setFooterActive = Type => {
- for (let ele = entities.footer.firstElementChild; !!ele; ele = ele.nextElementSibling) {
+ setFooterActive = Type => {
+ for (let ele = this.entities.footer.firstElementChild; !!ele; ele = ele.nextElementSibling) {
if (ele.getAttribute("type") === Type) {
ele.classList.add("select");
} else {
@@ -272,15 +162,15 @@
}
}
- const refresh = () => {
- if (entities.modal.style.display === "block") {
- const search = entities.footer.querySelector(".plugin-outline-icon.select");
- collectAndShow(search.getAttribute("Type"));
+ refresh = () => {
+ if (this.entities.modal.style.display === "block") {
+ const search = this.entities.footer.querySelector(".plugin-outline-icon.select");
+ this.collectAndShow(search.getAttribute("Type"));
}
}
// 因为比较简单,就不用CSS做了
- const rotate = ele => {
+ rotate = ele => {
let angle = 0;
const timer = setInterval(() => {
angle += 10;
@@ -289,8 +179,8 @@
}, 10)
}
- const toggleEye = icon => {
- config.SHOW_HIDDEN = !config.SHOW_HIDDEN;
+ toggleEye = icon => {
+ this.config.SHOW_HIDDEN = !this.config.SHOW_HIDDEN;
if (icon.classList.contains("ion-eye")) {
icon.classList.remove("ion-eye");
icon.classList.add("ion-eye-disabled");
@@ -302,59 +192,163 @@
}
}
- entities.modal.addEventListener("click", ev => {
- const item = ev.target.closest(".plugin-outline-item");
- const headerIcon = ev.target.closest(".plugin-outline-header .plugin-outline-icon");
- const footerIcon = ev.target.closest(".plugin-outline-footer .plugin-outline-icon");
+ call = () => {
+ if (this.entities.modal.style.display === "block") {
+ this.hide();
+ } else {
+ this.collectAndShow(this.config.DEFAULT_TYPE);
+ }
+ };
- if (!item && !headerIcon && !footerIcon) return;
+ hide = () => this.entities.modal.style.display = "none";
+}
- ev.stopPropagation();
- ev.preventDefault();
+class _collectUtil {
+ constructor(config, entities) {
+ this.config = config;
+ this.entities = entities;
- if (item) {
- const cid = item.querySelector("span").getAttribute("data-ref");
- scroll(cid);
- } else if (footerIcon) {
- const Type = footerIcon.getAttribute("type");
- collectAndShow(Type);
- } else {
- const Type = headerIcon.getAttribute("type");
- if (Type === "close") {
- hide();
- } else if (Type === "refresh") {
- refresh();
- rotate(headerIcon.firstElementChild);
- } else if (Type === "eye") {
- toggleEye(headerIcon);
- refresh();
+ this.paragraphIdx = 0;
+ this.tableIdx = 0;
+ this.imageIdx = 0;
+ this.fenceIdx = 0;
+ this.collection = {table: [], image: [], fence: []};
+ }
+
+ clear() {
+ this.paragraphIdx = this.tableIdx = this.imageIdx = this.fenceIdx = 0;
+ this.collection = {table: [], image: [], fence: []};
+ }
+
+ collect() {
+ this.clear();
+ const write = document.querySelector("#write");
+ for (let ele = write.firstElementChild; ele; ele = ele.nextElementSibling) {
+ if (!this.config.SHOW_HIDDEN && ele.style.display === "none") {
+ continue
+ }
+
+ const tagName = ele.tagName;
+ if (tagName === "H1") {
+ this.paragraphIdx = 0;
+ this.tableIdx = this.imageIdx = this.fenceIdx = 0;
+ continue
+ } else if (tagName === "H2") {
+ this.paragraphIdx++;
+ this.tableIdx = this.imageIdx = this.fenceIdx = 0;
+ continue
+ }
+
+ const cid = ele.getAttribute("cid");
+ // table
+ if (tagName === "FIGURE") {
+ this.tableIdx++;
+ this.collection.table.push({
+ cid: cid,
+ type: "table",
+ paragraphIdx: this.paragraphIdx,
+ idx: this.tableIdx
+ });
+ // fence
+ } else if (ele.classList.contains("md-fences")) {
+ this.fenceIdx++;
+ this.collection.fence.push({
+ cid: cid,
+ type: "fence",
+ paragraphIdx: this.paragraphIdx,
+ idx: this.fenceIdx
+ });
+ // image
+ } else if (ele.querySelector("img")) {
+ this.imageIdx++;
+ this.collection.image.push({
+ cid: cid,
+ type: "image",
+ paragraphIdx: this.paragraphIdx,
+ idx: this.imageIdx
+ });
}
}
- })
+ }
- global._pluginUtils.dragFixedModal(entities.move, entities.modal, false);
+ compare(p) {
+ return function (m, n) {
+ const cid1 = parseInt(m[p].replace("n", ""));
+ const cid2 = parseInt(n[p].replace("n", ""));
+ return cid1 - cid2;
+ }
+ }
- global._pluginUtils.decorateOpenFile(null, () => {
- (config.AUTO_REFRESH_WHEN_OPEN_FILE && entities.modal.style.display === "block") && setTimeout(refresh, 300);
- })
+ getCollection(Type) {
+ if (Type !== "all") {
+ return this.collection[Type]
+ }
+ let list = [];
+ for (const type in this.collection) {
+ list.push(...this.collection[type])
+ }
+ list.sort(this.compare("cid"));
+ return list
+ }
- const call = () => {
- if (entities.modal.style.display === "block") {
- hide();
+ setColor = (ele, item, type) => {
+ if (type === "all") {
+ if (item.type === "table") {
+ ele.style.backgroundColor = "aliceblue";
+ } else if (item.type === "fence") {
+ ele.style.backgroundColor = "antiquewhite";
+ } else if (item.type === "image") {
+ ele.style.backgroundColor = "beige";
+ }
} else {
- collectAndShow(config.DEFAULT_TYPE);
+ ele.style.backgroundColor = "";
}
- };
+ }
- const hide = () => entities.modal.style.display = "none";
+ // 简易数据单向绑定
+ bindDOM(Type) {
+ const typeCollection = this.getCollection(Type);
- module.exports = {
- call,
- meta: {
- hide,
- refresh,
+ const first = this.entities.list.firstElementChild;
+ if (first && !first.classList.contains("plugin-outline-item")) {
+ this.entities.list.removeChild(first);
}
- };
- console.log("outline.js had been injected");
-})()
\ No newline at end of file
+ while (typeCollection.length !== this.entities.list.childElementCount) {
+ if (typeCollection.length > this.entities.list.childElementCount) {
+ const div = document.createElement("div");
+ div.classList.add("plugin-outline-item");
+ div.appendChild(document.createElement("span"));
+ this.entities.list.appendChild(div);
+ } else {
+ this.entities.list.removeChild(this.entities.list.firstElementChild);
+ }
+ }
+
+ if (this.entities.list.childElementCount === 0) {
+ const div = document.createElement("div");
+ div.innerText = "Empty";
+ div.style.display = "block";
+ div.style.textAlign = "center";
+ div.style.padding = "10px";
+ this.entities.list.appendChild(div);
+ return
+ }
+
+ let ele = this.entities.list.firstElementChild;
+ typeCollection.forEach(item => {
+ if (this.config.SET_COLOR_IN_ALL) {
+ this.setColor(ele, item, Type);
+ }
+ const span = ele.firstElementChild;
+ span.setAttribute("data-ref", item.cid);
+ span.innerText = `${this.config.SHOW_NAME[item.type]} ${item.paragraphIdx}-${item.idx}`;
+ ele = ele.nextElementSibling;
+ })
+ }
+}
+
+module.exports = {
+ plugin: outlinePlugin
+};
+
diff --git a/plugin/read_only.js b/plugin/read_only.js
index 5f404d93..da0118fc 100644
--- a/plugin/read_only.js
+++ b/plugin/read_only.js
@@ -1,15 +1,56 @@
-(() => {
- const config = global._pluginUtils.getPluginSetting("read_only");
+class readOnlyPlugin extends global._basePlugin {
+ style = () => {
+ const textID = "plugin-read-only-style";
+ const text = `#footer-word-count-label::before {content: attr(data-value) !important}`;
+ return {textID, text}
+ }
+
+ hotkey = () => {
+ return [{
+ hotkey: this.config.HOTKEY,
+ callback: this.call,
+ }]
+ }
+
+ init = () => {
+ this.excludeList = this.config.EXCLUDE_HOTKEY.map(h => this.utils.toHotkeyFunc(h));
+ this.lastClickTime = 0;
+ }
- (() => {
- const css = `#footer-word-count-label::before {content: attr(data-value) !important}`;
- global._pluginUtils.insertStyle("plugin-read-only-style", css);
- })()
+ process = () => {
+ this.init();
- const excludeList = config.EXCLUDE_HOTKEY.map(h => global._pluginUtils.toHotkeyFunc(h));
+ const write = document.getElementById("write");
+ write.addEventListener("keydown", this.stopKeyboard, true);
+ write.addEventListener("mousedown", this.stopMouse, true);
+ write.addEventListener("click", this.stopMouse, true);
- const isExclude = ev => {
- for (const func of excludeList) {
+ if (this.config.READ_ONLY_DEFAULT) {
+ this.utils.loopDetector(() => !!File, this.call);
+ }
+
+ this.utils.decorate(
+ () => (File && File.freshLock),
+ File,
+ "freshLock",
+ null,
+ () => {
+ if (!File.isLocked) return;
+ [
+ "#typora-search-multi-input input",
+ "#typora-commander-form input",
+ "#plugin-multi-highlighter-input input",
+ "#typora-quick-open-input input",
+ ].forEach(selector => {
+ const input = document.querySelector(selector);
+ input && input.removeAttribute("readonly");
+ })
+ }
+ )
+ }
+
+ isExclude = ev => {
+ for (const func of this.excludeList) {
if (func(ev)) {
return true
}
@@ -17,7 +58,7 @@
return false
}
- const stopMouse = ev => {
+ stopMouse = ev => {
if (!File.isLocked) return;
const target = ev.target.closest('.footnotes, figure[mdtype="table"], .md-task-list-item, .md-image, .ty-cm-lang-input, input[type="checkbox"]');
@@ -28,29 +69,23 @@
}
}
- let lastClickTime = 0;
- const stopKeyboard = ev => {
+ stopKeyboard = ev => {
if (!File.isLocked) return;
- if (ev.timeStamp - lastClickTime > config.CLICK_CHECK_INTERVAL) {
+ if (ev.timeStamp - this.lastClickTime > this.config.CLICK_CHECK_INTERVAL) {
File.lock();
}
// File.isLocked 也挡不住回车键 :(
// 为什么要使用isExclude排除按键?因为输入法激活状态下键入能突破 File.isLocked
- if ((ev.key === "Enter") || !isExclude(ev)) {
+ if ((ev.key === "Enter") || !this.isExclude(ev)) {
document.activeElement.blur();
ev.preventDefault();
ev.stopPropagation();
}
}
- const write = document.getElementById("write");
- write.addEventListener("keydown", stopKeyboard, true);
- write.addEventListener("mousedown", stopMouse, true);
- write.addEventListener("click", stopMouse, true);
-
- const call = () => {
+ call = () => {
const span = document.getElementById("footer-word-count-label");
if (File.isLocked) {
File.unlock();
@@ -61,35 +96,8 @@
span.setAttribute("data-value", "ReadOnly" + String.fromCharCode(160).repeat(3));
}
}
+}
- global._pluginUtils.registerWindowHotkey(config.HOTKEY, call);
-
- global._pluginUtils.decorate(
- () => (File && File.freshLock),
- File,
- "freshLock",
- null,
- () => {
- if (!File.isLocked) return;
- [
- "#typora-search-multi-input input",
- "#typora-commander-form input",
- "#plugin-multi-highlighter-input input",
- "#typora-quick-open-input input",
- ].forEach(selector => {
- const input = document.querySelector(selector);
- input && input.removeAttribute("readonly");
- })
- }
- )
-
- if (config.READ_ONLY_DEFAULT) {
- global._pluginUtils.loopDetector(() => !!File, call);
- }
-
- module.exports = {
- call,
- };
-
- console.log("read_only.js had been injected");
-})()
\ No newline at end of file
+module.exports = {
+ plugin: readOnlyPlugin,
+};
diff --git a/plugin/resize_image.js b/plugin/resize_image.js
index 4a27b2d6..ffa36faf 100644
--- a/plugin/resize_image.js
+++ b/plugin/resize_image.js
@@ -1,12 +1,37 @@
-(() => {
- const config = global._pluginUtils.getPluginSetting("resize_image");
+class resizeImagePlugin extends global._basePlugin {
+ init = () => {
+ this.dynamicUtil = {target: null}
+ this.dynamicCallMap = {
+ zoom_out_20_percent: () => this.zoom(this.dynamicUtil.target, true, 0.2),
+ zoom_in_20_percent: () => this.zoom(this.dynamicUtil.target, false, 0.2),
+ set_align_left: () => this.setAlign("left", this.dynamicUtil.target),
+ set_align_center: () => this.setAlign("center", this.dynamicUtil.target),
+ set_align_right: () => this.setAlign("right", this.dynamicUtil.target),
+ }
+ }
+
+ process = () => {
+ this.init();
+
+ document.getElementById("write").addEventListener("wheel", ev => {
+ if (!this.utils.metaKeyPressed(ev)) return;
+
+ const target = ev.target.closest("img");
+ if (!target) return;
+
+ ev.stopPropagation();
+
+ const zoomOut = ev.deltaY > 0;
+ this.zoom(target, zoomOut, this.config.SCALE);
+ }, true);
+ }
- const getWidth = image => {
+ getWidth = image => {
const {width} = image.getBoundingClientRect();
return (!image.style.width) ? width : parseInt(image.style.width.replace("px", ""));
}
- const setAlign = (align, image, maxWidth) => {
+ setAlign = (align, image, maxWidth) => {
image.setAttribute("align", align);
if (!maxWidth) {
maxWidth = image.parentElement.offsetWidth;
@@ -14,46 +39,32 @@
image.style.marginRight = "";
image.style.marginLeft = "";
if (align !== "center") {
- const width = getWidth(image);
+ const width = this.getWidth(image);
const margin = (align === "left") ? "marginRight" : "marginLeft";
image.style[margin] = maxWidth - width + "px";
}
}
- const zoom = (image, zoomOut, scale) => {
- let width = getWidth(image);
- width = zoomOut ? width * (1 - scale) : width * (1 + config.SCALE);
+ zoom = (image, zoomOut, scale) => {
+ let width = this.getWidth(image);
+ width = zoomOut ? width * (1 - scale) : width * (1 + this.config.SCALE);
const maxWidth = image.parentElement.offsetWidth;
width = Math.min(width, maxWidth);
image.style.width = width + "px";
- setAlign(config.IMAGE_ALIGN, image, maxWidth);
+ this.setAlign(this.config.IMAGE_ALIGN, image, maxWidth);
}
- document.getElementById("write").addEventListener("wheel", ev => {
- if (!global._pluginUtils.metaKeyPressed(ev)) return;
-
- const target = ev.target.closest("img");
- if (!target) return;
-
- ev.stopPropagation();
-
- const zoomOut = ev.deltaY > 0;
- zoom(target, zoomOut, config.SCALE);
- }, true);
-
- //////////////////////// 以下是声明式插件系统代码 ////////////////////////
- const dynamicUtil = {target: null}
- const dynamicCallArgsGenerator = anchorNode => {
+ dynamicCallArgsGenerator = anchorNode => {
const images = anchorNode.closest("#write .md-image");
if (!images) return;
const image = images.querySelector("img");
if (!image) return;
- dynamicUtil.target = image;
+ this.dynamicUtil.target = image;
const args = [{arg_name: "缩小20%", arg_value: "zoom_out_20_percent"}];
- if (getWidth(image) < image.parentElement.offsetWidth) {
+ if (this.getWidth(image) < image.parentElement.offsetWidth) {
args.push({arg_name: "放大20%", arg_value: "zoom_in_20_percent"})
}
args.push(
@@ -64,25 +75,14 @@
return args
}
- const dynamicCallMap = {
- zoom_out_20_percent: () => zoom(dynamicUtil.target, true, 0.2),
- zoom_in_20_percent: () => zoom(dynamicUtil.target, false, 0.2),
- set_align_left: () => setAlign("left", dynamicUtil.target),
- set_align_center: () => setAlign("center", dynamicUtil.target),
- set_align_right: () => setAlign("right", dynamicUtil.target),
- }
-
- const call = type => {
- if (!dynamicUtil.target) return;
+ call = type => {
+ if (!this.dynamicUtil.target) return;
- const func = dynamicCallMap[type];
+ const func = this.dynamicCallMap[type];
func && func();
}
+}
- module.exports = {
- call,
- dynamicCallArgsGenerator,
- };
-
- console.log("resize_image.js had been injected");
-})()
+module.exports = {
+ plugin: resizeImagePlugin
+};
\ No newline at end of file
diff --git a/plugin/resize_table.js b/plugin/resize_table.js
index 82659633..0f26fc39 100644
--- a/plugin/resize_table.js
+++ b/plugin/resize_table.js
@@ -1,14 +1,81 @@
-(() => {
- const config = global._pluginUtils.getPluginSetting("resize_table");
-
- (() => {
- if (config.REMOVE_MIX_WIDTH) {
- const css = `table.md-table td { min-width: 1px !important; }`;
- global._pluginUtils.insertStyle("plugin-resize-table-style", css);
+class resizeTablePlugin extends global._basePlugin {
+ style = () => {
+ if (this.config.REMOVE_MIX_WIDTH) {
+ const textID = "plugin-resize-table-style";
+ const text = `table.md-table td { min-width: 1px !important; }`;
+ return {textID, text}
}
- })()
+ }
+
+ process = () => {
+ document.querySelector("#write").addEventListener("mousedown", ev => {
+ if (!this.utils.metaKeyPressed(ev)) return;
+ ev.stopPropagation();
+ ev.preventDefault();
+
+ let closet = "thead";
+ let self = "th";
+ let ele = ev.target.closest(self);
+ if (!ele) {
+ closet = "tbody";
+ self = "td";
+ ele = ev.target.closest(self);
+ }
+
+ if (!ele) return;
+
+ const {target, direction} = this.findTarget(ele, ev);
+ if ((!target) || (direction !== "right" && direction !== "bottom")) return;
+
+ const rect = target.getBoundingClientRect();
+ const startWidth = rect.width;
+ const startHeight = rect.height;
+ const startX = ev.clientX;
+ const startY = ev.clientY;
+
+ target.style.width = startWidth + "px";
+ target.style.height = startHeight + "px";
+
+ if (direction === "right") {
+ target.style.cursor = "w-resize";
+ const num = this.whichChildOfParent(target);
+ const eleList = target.closest(closet).querySelectorAll(`tr ${self}:nth-child(${num})`);
+ this.cleanStyle(eleList, target, "width");
+ } else if (direction === "bottom") {
+ target.style.cursor = "s-resize";
+ const tds = target.parentElement.children;
+ this.cleanStyle(tds, target, "height");
+ }
+
+ const onMouseMove = ev => {
+ ev.stopPropagation();
+ ev.preventDefault();
+
+ if (!this.utils.metaKeyPressed(ev)) return;
+
+ requestAnimationFrame(() => {
+ if (direction === "right") {
+ target.style.width = startWidth + ev.clientX - startX + "px";
+ } else if (direction === "bottom") {
+ target.style.height = startHeight + ev.clientY - startY + "px";
+ }
+ });
+ }
+
+ document.addEventListener("mouseup", ev => {
+ ev.stopPropagation();
+ ev.preventDefault();
+ target.style.cursor = "default";
+ document.removeEventListener('mousemove', onMouseMove);
+ target.onmouseup = null;
+ }
+ )
+
+ document.addEventListener('mousemove', onMouseMove);
+ })
+ }
- const whichChildOfParent = child => {
+ whichChildOfParent = child => {
let i = 1;
for (const sibling of child.parentElement.children) {
if (sibling && sibling === child) {
@@ -18,19 +85,19 @@
}
}
- const getDirection = (target, ev) => {
+ getDirection = (target, ev) => {
if (!target) return ""
const rect = target.getBoundingClientRect();
- if (rect.right - config.THRESHOLD < ev.clientX && ev.clientX < rect.right + config.THRESHOLD) {
+ if (rect.right - this.config.THRESHOLD < ev.clientX && ev.clientX < rect.right + this.config.THRESHOLD) {
return "right"
- } else if (rect.bottom - config.THRESHOLD < ev.clientY && ev.clientY < rect.bottom + config.THRESHOLD) {
+ } else if (rect.bottom - this.config.THRESHOLD < ev.clientY && ev.clientY < rect.bottom + this.config.THRESHOLD) {
return "bottom"
} else {
return ""
}
}
- const findTarget = (ele, ev) => {
+ findTarget = (ele, ev) => {
let target = null;
let direction = "";
@@ -43,7 +110,7 @@
target = ele.previousElementSibling;
break
case 3:
- const num = whichChildOfParent(ele);
+ const num = this.whichChildOfParent(ele);
const uncle = ele.parentElement.previousElementSibling;
if (uncle) {
target = uncle.querySelector(`td:nth-child(${num})`);
@@ -55,88 +122,22 @@
break
}
- direction = getDirection(target, ev);
+ direction = this.getDirection(target, ev);
if (target && direction) break
}
return {target, direction}
}
- const cleanStyle = (eleList, exclude, cleanStyle) => {
+ cleanStyle = (eleList, exclude, cleanStyle) => {
for (const td of eleList) {
if (td && td.style && td !== exclude) {
td.style[cleanStyle] = "";
}
}
}
+}
- document.querySelector("#write").addEventListener("mousedown", ev => {
- if (!global._pluginUtils.metaKeyPressed(ev)) return;
- ev.stopPropagation();
- ev.preventDefault();
-
- let closet = "thead";
- let self = "th";
- let ele = ev.target.closest(self);
- if (!ele) {
- closet = "tbody";
- self = "td";
- ele = ev.target.closest(self);
- }
-
- if (!ele) return;
-
- const {target, direction} = findTarget(ele, ev);
- if ((!target) || (direction !== "right" && direction !== "bottom")) return;
-
- const rect = target.getBoundingClientRect();
- const startWidth = rect.width;
- const startHeight = rect.height;
- const startX = ev.clientX;
- const startY = ev.clientY;
-
- target.style.width = startWidth + "px";
- target.style.height = startHeight + "px";
-
- if (direction === "right") {
- target.style.cursor = "w-resize";
- const num = whichChildOfParent(target);
- const eleList = target.closest(closet).querySelectorAll(`tr ${self}:nth-child(${num})`);
- cleanStyle(eleList, target, "width");
- } else if (direction === "bottom") {
- target.style.cursor = "s-resize";
- const tds = target.parentElement.children;
- cleanStyle(tds, target, "height");
- }
-
- const onMouseMove = ev => {
- ev.stopPropagation();
- ev.preventDefault();
-
- if (!global._pluginUtils.metaKeyPressed(ev)) return;
-
- requestAnimationFrame(() => {
- if (direction === "right") {
- target.style.width = startWidth + ev.clientX - startX + "px";
- } else if (direction === "bottom") {
- target.style.height = startHeight + ev.clientY - startY + "px";
- }
- });
- }
-
- document.addEventListener("mouseup", ev => {
- ev.stopPropagation();
- ev.preventDefault();
- target.style.cursor = "default";
- document.removeEventListener('mousemove', onMouseMove);
- target.onmouseup = null;
- }
- )
-
- document.addEventListener('mousemove', onMouseMove);
- })
-
- module.exports = {};
-
- console.log("resize_table.js had been injected");
-})()
\ No newline at end of file
+module.exports = {
+ plugin: resizeTablePlugin
+};
\ No newline at end of file
diff --git a/plugin/right_click_menu.js b/plugin/right_click_menu.js
index fe2a5dd9..3ca5e82c 100644
--- a/plugin/right_click_menu.js
+++ b/plugin/right_click_menu.js
@@ -1,14 +1,20 @@
-(() => {
- const config = global._pluginUtils.getPluginSetting("right_click_menu");
+class rightClickMenuPlugin extends global._basePlugin {
+ beforeProcess = () => {
+ this.utils.loopDetector(() => global._pluginsHadInjected, this.appendMenu, this.config.LOOP_DETECT_INTERVAL);
+ }
- const getPlugins = () => {
- const enable = global._plugins.filter(plugin => plugin.enable === true);
- const clickable = enable.filter(plugin => plugin.clickable === true);
- const nonClickable = enable.filter(plugin => plugin.clickable === false);
+ getPlugins = () => {
+ const enable = []
+ for (const fixed_name in global._plugins) {
+ const plugin = global._plugins[fixed_name];
+ enable.push(plugin);
+ }
+ const clickable = enable.filter(plugin => plugin.config.CLICKABLE === true);
+ const nonClickable = enable.filter(plugin => plugin.config.CLICKABLE === false);
return {clickable, nonClickable, enable}
}
- const appendFirst = () => {
+ appendFirst = () => {
const ul = document.querySelector(`#context-menu`);
const line = document.createElement("li");
line.classList.add("divider");
@@ -25,45 +31,45 @@
ul.insertAdjacentHTML('beforeend', li);
}
- const appendSecond = (clickablePlugins, nonClickablePlugins) => {
- const clickable = clickablePlugins.map(plugin => createSecondLi(plugin)).join("");
- const nonClickable = nonClickablePlugins.map(plugin => createSecondLi(plugin)).join("");
+ appendSecond = (clickablePlugins, nonClickablePlugins) => {
+ const clickable = clickablePlugins.map(plugin => this.createSecondLi(plugin)).join("");
+ const nonClickable = nonClickablePlugins.map(plugin => this.createSecondLi(plugin)).join("");
const divider = ``
- const secondUl = createUl();
+ const secondUl = this.createUl();
secondUl.id = "plugin-menu";
secondUl.innerHTML = clickable + divider + nonClickable;
document.querySelector("content").appendChild(secondUl);
}
- const appendThird = enablePlugins => {
+ appendThird = enablePlugins => {
enablePlugins.forEach(plugin => {
- if (!plugin.call_args && !plugin.dynamic_call_args_generator) return;
+ if (!plugin.callArgs && !plugin.dynamicCallArgsGenerator) return;
- const thirdUl = createUl();
+ const thirdUl = this.createUl();
thirdUl.classList.add("plugin-menu-third");
thirdUl.setAttribute("fixed_name", plugin.fixed_name);
- thirdUl.innerHTML = plugin.call_args ? plugin.call_args.map(arg => createThirdLi(arg)).join("") : "";
+ thirdUl.innerHTML = plugin.callArgs ? plugin.callArgs.map(arg => this.createThirdLi(arg)).join("") : "";
document.querySelector("content").appendChild(thirdUl);
})
}
- const createSecondLi = plugin => {
- const hasNotArgs = !plugin.call_args && !plugin.dynamic_call_args_generator;
- const style = (plugin.clickable) ? "" : `style="pointer-events: none;color: #c4c6cc;"`;
- const content = (hasNotArgs) ? plugin.name : `${plugin.name} `;
+ createSecondLi = plugin => {
+ const hasNotArgs = !plugin.callArgs && !plugin.dynamicCallArgsGenerator;
+ const style = (plugin.config.CLICKABLE) ? "" : `style="pointer-events: none;color: #c4c6cc;"`;
+ const content = (hasNotArgs) ? plugin.config.NAME : `${plugin.config.NAME} `;
const className = (hasNotArgs) ? "" : "plugin-has-args";
return ``
}
- const createThirdLi = (arg, dynamic) => {
+ createThirdLi = (arg, dynamic) => {
const disabled = (arg.arg_disabled) ? " disabled" : "";
const className = (dynamic) ? `class="plugin-dynamic-arg${disabled}"` : "";
return `${arg.arg_name}`
}
- const createUl = () => {
+ createUl = () => {
const secondUl = document.createElement("ul");
secondUl.classList.add("dropdown-menu");
secondUl.classList.add("context-menu");
@@ -72,7 +78,7 @@
return secondUl;
}
- const show = (second, first) => {
+ show = (second, first) => {
const next = second.addClass("show");
const rect = next[0].getBoundingClientRect();
@@ -94,38 +100,57 @@
return false;
}
- const generateDynamicCallArgs = fixedName => {
+ generateDynamicCallArgs = fixedName => {
if (!fixedName) return;
- const plugin = global._pluginUtils.getPlugin(fixedName);
- if (plugin && plugin.enable && plugin.dynamic_call_args_generator) {
+ const plugin = this.utils.getPlugin(fixedName);
+ if (plugin && plugin.dynamicCallArgsGenerator) {
const anchorNode = File.editor.getJQueryElem(window.getSelection().anchorNode);
if (anchorNode[0]) {
- return plugin.dynamic_call_args_generator(anchorNode[0]);
+ return plugin.dynamicCallArgsGenerator(anchorNode[0]);
}
}
}
- const appendThirdLi = (menu, dynamicCallArgs) => {
- const args = dynamicCallArgs.map(arg => createThirdLi(arg, true)).join("");
+ appendThirdLi = (menu, dynamicCallArgs) => {
+ const args = dynamicCallArgs.map(arg => this.createThirdLi(arg, true)).join("");
menu.append(args);
}
-
- const appendDummyThirdLi = menu => {
- appendThirdLi(menu, [{
+ appendDummyThirdLi = menu => {
+ this.appendThirdLi(menu, [{
arg_name: "光标于此位置不可用",
- arg_value: config.NOT_AVAILABLE_VALUE,
+ arg_value: this.config.NOT_AVAILABLE_VALUE,
arg_disabled: true,
}])
}
- const listen = enablePlugins => {
+ appendMenu = () => {
+ setTimeout(() => {
+ const {clickable, nonClickable, enable} = this.getPlugins();
+ // 一级菜单汇总所有插件
+ this.appendFirst();
+ // 二级菜单展示所有插件
+ this.appendSecond(clickable, nonClickable);
+ // 三级菜单展示插件的参数
+ this.appendThird(enable);
+ this.listen();
+ }, 500)
+ }
+
+ listen = () => {
+ const appendThirdLi = this.appendThirdLi;
+ const appendDummyThirdLi = this.appendDummyThirdLi;
+ const show = this.show;
+ const generateDynamicCallArgs = this.generateDynamicCallArgs;
+ const config = this.config;
+ const utils = this.utils
+
// 在二级菜单中调用插件
$("#plugin-menu").on("click", "[data-key]", function () {
- const fixed_name = this.getAttribute("data-key");
- const plugin = enablePlugins.filter(plugin => plugin.fixed_name === fixed_name)[0];
+ const fixedName = this.getAttribute("data-key");
+ const plugin = utils.getPlugin(fixedName);
// 拥有三级菜单的,不允许点击二级菜单
- if (plugin.call_args || plugin.dynamic_call_args_generator) {
+ if (plugin.callArgs || plugin.dynamicCallArgsGenerator) {
return false
}
if (plugin && plugin.call) {
@@ -170,7 +195,7 @@
$(".plugin-menu-third").on("click", "[data-key]", function () {
const fixedName = this.parentElement.getAttribute("fixed_name");
const argValue = this.getAttribute("arg_value");
- const plugin = enablePlugins.filter(plugin => plugin.fixed_name === fixedName)[0];
+ const plugin = utils.getPlugin(fixedName);
if (argValue !== config.NOT_AVAILABLE_VALUE && plugin && plugin.call) {
plugin.call(argValue);
}
@@ -180,36 +205,20 @@
})
}
- const appendMenu = () => {
- setTimeout(() => {
- const {clickable, nonClickable, enable} = getPlugins();
- // 一级菜单汇总所有插件
- appendFirst();
- // 二级菜单展示所有插件
- appendSecond(clickable, nonClickable);
- // 三级菜单展示插件的参数
- appendThird(enable);
- listen(enable);
- }, 500)
- }
-
- global._pluginUtils.loopDetector(() => global._pluginsHadInjected, appendMenu, config.LOOP_DETECT_INTERVAL);
-
- //////////////////////// 以下是声明式插件系统代码 ////////////////////////
- const call = type => {
+ call = type => {
if (type === "about") {
const url = "https://github.com/obgnail/typora_plugin"
const openUrl = File.editor.tryOpenUrl_ || File.editor.tryOpenUrl
openUrl(url, 1);
} else if (type === "do_not_hide") {
- config.DO_NOT_HIDE = !config.DO_NOT_HIDE;
+ this.config.DO_NOT_HIDE = !this.config.DO_NOT_HIDE;
} else if (type === "open_setting_folder") {
- const filepath = global._pluginUtils.joinPath("./plugin/global/settings/settings.toml");
+ const filepath = this.utils.joinPath("./plugin/global/settings/settings.toml");
JSBridge.showInFinder(filepath);
}
}
- const callArgs = [
+ callArgs = [
{
arg_name: "右键菜单点击后保持显示/隐藏",
arg_value: "do_not_hide"
@@ -222,12 +231,9 @@
arg_name: "关于/帮助",
arg_value: "about"
},
- ];
-
- module.exports = {
- call,
- callArgs,
- };
+ ]
+}
- console.log("right_click_menu.js had been injected");
-})()
\ No newline at end of file
+module.exports = {
+ plugin: rightClickMenuPlugin
+};
diff --git a/plugin/search_multi.js b/plugin/search_multi.js
index 03df379b..5cdc8cac 100644
--- a/plugin/search_multi.js
+++ b/plugin/search_multi.js
@@ -1,8 +1,7 @@
-(() => {
- const config = global._pluginUtils.getPluginSetting("search_multi");
-
- (() => {
- const modal_css = `
+class searchMultiKeywordPlugin extends global._basePlugin {
+ style = () => {
+ const textID = "plugin-search-multi-style";
+ const text = `
#typora-search-multi {
position: fixed;
top: 40px;
@@ -143,17 +142,19 @@
padding-left: 20px;
display: none;
}`
- global._pluginUtils.insertStyle("plugin-search-multi-style", modal_css);
+ return {textID, text}
+ }
+ html = () => {
const modal_div = `
@@ -179,55 +180,186 @@
searchModal.innerHTML = modal_div;
const quickOpenNode = document.getElementById("typora-quick-open");
quickOpenNode.parentNode.insertBefore(searchModal, quickOpenNode.nextSibling);
- })();
-
- const modal = {
- modal: document.getElementById('typora-search-multi'),
- input: document.querySelector("#typora-search-multi-input input"),
- result: document.querySelector(".typora-search-multi-result"),
- resultTitle: document.querySelector(".typora-search-multi-result .search-result-title"),
- resultList: document.querySelector(".typora-search-multi-result .search-result-list"),
- info: document.querySelector(".typora-search-multi-info-item"),
}
- const Package = global._pluginUtils.Package;
- const separator = File.isWin ? "\\" : "/";
- const openFileInThisWindow = filePath => File.editor.library.openFile(filePath);
- const openFileInNewWindow = (path, isFolder) => File.editor.library.openFileInNewWindow(path, isFolder);
+ hotkey = () => {
+ return [{
+ hotkey: this.config.HOTKEY,
+ callback: this.call
+ }]
+ }
+
+ process = () => {
+ this.modal = {
+ modal: document.getElementById('typora-search-multi'),
+ input: document.querySelector("#typora-search-multi-input input"),
+ result: document.querySelector(".typora-search-multi-result"),
+ resultTitle: document.querySelector(".typora-search-multi-result .search-result-title"),
+ resultList: document.querySelector(".typora-search-multi-result .search-result-list"),
+ info: document.querySelector(".typora-search-multi-info-item"),
+ }
+
+ if (this.config.REFOUCE_WHEN_OPEN_FILE) {
+ this.utils.decorateOpenFile(null, () => {
+ if (this.modal.modal.style.display === "block") {
+ setTimeout(() => this.modal.input.select(), 300);
+ }
+ })
+ }
+
+ if (this.config.ALLOW_DRAG) {
+ this.utils.dragFixedModal(this.modal.input, this.modal.modal);
+ }
+
+ let floor;
+
+ this.modal.input.addEventListener("keydown", ev => {
+ switch (ev.key) {
+ case "Enter":
+ if (this.utils.metaKeyPressed(ev)) {
+ const select = this.modal.resultList.querySelector(".typora-search-multi-item.active");
+ if (select) {
+ ev.preventDefault();
+ ev.stopPropagation();
+ const filepath = select.getAttribute("data-path");
+ if (ev.shiftKey) {
+ this.openFileInNewWindow(filepath, false);
+ } else {
+ this.openFileInThisWindow(filepath);
+ }
+ this.modal.input.focus();
+ return
+ }
+ }
+ this.modal.result.style.display = "none";
+ this.modal.info.style.display = "block";
+ this.modal.resultList.innerHTML = "";
+ const workspace = File.getMountFolder();
+ this.searchMulti(workspace, this.modal.input.value, () => this.modal.info.style.display = "none");
+ break
+ case "Escape":
+ ev.stopPropagation();
+ ev.preventDefault();
+ this.hide();
+ break
+ case "ArrowUp":
+ case "ArrowDown":
+ ev.stopPropagation();
+ ev.preventDefault();
+
+ if (!this.modal.resultList.childElementCount) return;
+
+ const activeItem = this.modal.resultList.querySelector(".typora-search-multi-item.active")
+ let nextItem;
+ if (ev.key === "ArrowDown") {
+ if (floor !== 7) floor++;
+
+ if (activeItem && activeItem.nextElementSibling) {
+ nextItem = activeItem.nextElementSibling;
+ } else {
+ nextItem = this.modal.resultList.firstElementChild;
+ floor = 1
+ }
+ } else {
+ if (floor !== 1) floor--;
+
+ if (activeItem && activeItem.previousElementSibling) {
+ nextItem = activeItem.previousElementSibling;
+ } else {
+ nextItem = this.modal.resultList.lastElementChild;
+ floor = 7
+ }
+ }
+
+ activeItem && activeItem.classList.toggle("active");
+ nextItem.classList.toggle("active");
+
+ let top;
+ if (floor === 1) {
+ top = nextItem.offsetTop - nextItem.offsetHeight;
+ } else if (floor === 7) {
+ top = nextItem.offsetTop - 6 * nextItem.offsetHeight;
+ } else if (Math.abs(this.modal.resultList.scrollTop - activeItem.offsetTop) > 7 * nextItem.offsetHeight) {
+ top = nextItem.offsetTop - 3 * nextItem.offsetHeight;
+ }
+ top && this.modal.resultList.scrollTo({top: top, behavior: "smooth"});
+ }
+ });
+
+ this.modal.resultList.addEventListener("click", ev => {
+ const target = ev.target.closest(".typora-search-multi-item");
+ if (!target) return;
+
+ ev.preventDefault();
+ ev.stopPropagation();
+
+ const filepath = target.getAttribute("data-path");
+ if (this.utils.metaKeyPressed(ev)) {
+ this.openFileInNewWindow(filepath, false);
+ } else {
+ this.openFileInThisWindow(filepath);
+ }
+ this.hideIfNeed();
+ });
+
+ this.modal.modal.addEventListener("click", ev => {
+ const caseButton = ev.target.closest("#typora-search-multi-input .case-option-btn");
+ const pathButton = ev.target.closest("#typora-search-multi-input .path-option-btn");
+
+ if (caseButton || pathButton) {
+ ev.preventDefault();
+ ev.stopPropagation();
+ }
+
+ if (caseButton) {
+ caseButton.classList.toggle("select");
+ this.config.CASE_SENSITIVE = !this.config.CASE_SENSITIVE;
+ } else if (pathButton) {
+ pathButton.classList.toggle("select");
+ this.config.INCLUDE_FILE_PATH = !this.config.INCLUDE_FILE_PATH;
+ }
+ })
+ }
+
+ separator = File.isWin ? "\\" : "/";
+ openFileInThisWindow = filePath => File.editor.library.openFile(filePath);
+ openFileInNewWindow = (path, isFolder) => File.editor.library.openFileInNewWindow(path, isFolder);
+
+ traverseDir = (dir, filter, callback, then) => {
+ const utils = this.utils;
- const traverseDir = (dir, filter, callback, then) => {
async function traverse(dir) {
- const files = await Package.Fs.promises.readdir(dir);
+ const files = await utils.Package.Fs.promises.readdir(dir);
for (const file of files) {
- const filePath = Package.Path.join(dir, file);
- const stats = await Package.Fs.promises.stat(filePath);
+ const filePath = utils.Package.Path.join(dir, file);
+ const stats = await utils.Package.Fs.promises.stat(filePath);
if (stats.isFile()) {
if (filter && !filter(filePath, stats)) {
continue
}
- Package.Fs.promises.readFile(filePath)
+ utils.Package.Fs.promises.readFile(filePath)
.then(buffer => callback(filePath, stats, buffer))
- .catch(error => console.log(error))
+ .catch(error => console.error(error))
} else if (stats.isDirectory()) {
await traverse(filePath);
}
}
}
- traverse(dir).then(then).catch(err => console.log(err));
+ traverse(dir).then(then).catch(err => console.error(err));
}
- const appendItemFunc = keyArr => {
+ appendItemFunc = keyArr => {
let index = 0;
let once = true;
const rootPath = File.getMountFolder();
return (filePath, stats, buffer) => {
let data = buffer.toString();
- if (config.INCLUDE_FILE_PATH) {
+ if (this.config.INCLUDE_FILE_PATH) {
data = data + filePath;
}
- if (!config.CASE_SENSITIVE) {
+ if (!this.config.CASE_SENSITIVE) {
data = data.toLowerCase();
}
for (const keyword of keyArr) {
@@ -235,15 +367,15 @@
}
index++;
- const parseUrl = Package.Path.parse(filePath);
- const dirPath = !config.RELATIVE_PATH ? parseUrl.dir : parseUrl.dir.replace(rootPath, ".");
+ const parseUrl = this.utils.Package.Path.parse(filePath);
+ const dirPath = !this.config.RELATIVE_PATH ? parseUrl.dir : parseUrl.dir.replace(rootPath, ".");
const item = document.createElement("div");
item.classList.add("typora-search-multi-item");
item.setAttribute("data-is-dir", "false");
item.setAttribute("data-path", filePath);
item.setAttribute("data-index", index + "");
- if (config.SHOW_MTIME) {
+ if (this.config.SHOW_MTIME) {
item.setAttribute("ty-hint", stats.mtime.toLocaleString('chinese', {hour12: false}));
}
const title = document.createElement("div");
@@ -251,191 +383,72 @@
title.innerText = parseUrl.base;
const path = document.createElement("div");
path.classList.add("typora-search-multi-item-path");
- path.innerText = dirPath + separator;
+ path.innerText = dirPath + this.separator;
item.appendChild(title);
item.appendChild(path);
- modal.resultList.appendChild(item);
+ this.modal.resultList.appendChild(item);
- modal.resultTitle.textContent = `匹配的文件:${index}`;
+ this.modal.resultTitle.textContent = `匹配的文件:${index}`;
if (index <= 8) {
- modal.resultList.style.height = 40 * index + "px";
+ this.modal.resultList.style.height = 40 * index + "px";
}
if (once) {
- modal.result.style.display = "block";
+ this.modal.result.style.display = "block";
once = false;
}
}
}
- const hideIfNeed = () => {
- if (config.AUTO_HIDE) {
- modal.modal.style.display = "none";
+ hideIfNeed = () => {
+ if (this.config.AUTO_HIDE) {
+ this.modal.modal.style.display = "none";
}
}
- const verifyExt = (filename) => {
+ verifyExt = filename => {
if (filename[0] === ".") {
return false
}
- const ext = Package.Path.extname(filename).replace(/^\./, '');
- if (~config.ALLOW_EXT.indexOf(ext.toLowerCase())) {
+ const ext = this.utils.Package.Path.extname(filename).replace(/^\./, '');
+ if (~this.config.ALLOW_EXT.indexOf(ext.toLowerCase())) {
return true
}
}
- const verifySize = (stat) => 0 > config.MAX_SIZE || stat.size < config.MAX_SIZE;
- const allowRead = (filepath, stat) => verifySize(stat) && verifyExt(filepath);
- const searchMulti = (rootPath, keys, then) => {
+ verifySize = stat => 0 > this.config.MAX_SIZE || stat.size < this.config.MAX_SIZE;
+
+ allowRead = (filepath, stat) => {
+ return this.verifySize(stat) && this.verifyExt(filepath);
+ }
+
+ searchMulti = (rootPath, keys, then) => {
if (!rootPath) return;
- let keyArr = keys.split(config.SEPARATOR).filter(Boolean);
+ let keyArr = keys.split(this.config.SEPARATOR).filter(Boolean);
if (!keyArr) return;
- if (!config.CASE_SENSITIVE) {
+ if (!this.config.CASE_SENSITIVE) {
keyArr = keyArr.map(ele => ele.toLowerCase());
}
- const appendItem = appendItemFunc(keyArr);
- traverseDir(rootPath, allowRead, appendItem, then);
+ const appendItem = this.appendItemFunc(keyArr);
+ this.traverseDir(rootPath, this.allowRead, appendItem, then);
}
- if (config.ALLOW_DRAG) {
- global._pluginUtils.dragFixedModal(modal.input, modal.modal);
+ hide = () => {
+ this.modal.modal.style.display = "none";
+ this.modal.info.style.display = "none";
}
- let floor;
-
- modal.input.addEventListener("keydown", ev => {
- switch (ev.key) {
- case "Enter":
- if (global._pluginUtils.metaKeyPressed(ev)) {
- const select = modal.resultList.querySelector(".typora-search-multi-item.active");
- if (select) {
- ev.preventDefault();
- ev.stopPropagation();
- const filepath = select.getAttribute("data-path");
- if (ev.shiftKey) {
- openFileInNewWindow(filepath, false);
- } else {
- openFileInThisWindow(filepath);
- }
- modal.input.focus();
- return
- }
- }
- modal.result.style.display = "none";
- modal.info.style.display = "block";
- modal.resultList.innerHTML = "";
- const workspace = File.getMountFolder();
- searchMulti(workspace, modal.input.value, () => modal.info.style.display = "none");
- break
- case "Escape":
- ev.stopPropagation();
- ev.preventDefault();
- hide();
- break
- case "ArrowUp":
- case "ArrowDown":
- ev.stopPropagation();
- ev.preventDefault();
-
- if (!modal.resultList.childElementCount) return;
-
- const activeItem = modal.resultList.querySelector(".typora-search-multi-item.active")
- let nextItem;
- if (ev.key === "ArrowDown") {
- if (floor !== 7) floor++;
-
- if (activeItem && activeItem.nextElementSibling) {
- nextItem = activeItem.nextElementSibling;
- } else {
- nextItem = modal.resultList.firstElementChild;
- floor = 1
- }
- } else {
- if (floor !== 1) floor--;
-
- if (activeItem && activeItem.previousElementSibling) {
- nextItem = activeItem.previousElementSibling;
- } else {
- nextItem = modal.resultList.lastElementChild;
- floor = 7
- }
- }
-
- activeItem && activeItem.classList.toggle("active");
- nextItem.classList.toggle("active");
-
- let top;
- if (floor === 1) {
- top = nextItem.offsetTop - nextItem.offsetHeight;
- } else if (floor === 7) {
- top = nextItem.offsetTop - 6 * nextItem.offsetHeight;
- } else if (Math.abs(modal.resultList.scrollTop - activeItem.offsetTop) > 7 * nextItem.offsetHeight) {
- top = nextItem.offsetTop - 3 * nextItem.offsetHeight;
- }
- top && modal.resultList.scrollTo({top: top, behavior: "smooth"});
- }
- });
-
- modal.resultList.addEventListener("click", ev => {
- const target = ev.target.closest(".typora-search-multi-item");
- if (!target) return;
-
- ev.preventDefault();
- ev.stopPropagation();
-
- const filepath = target.getAttribute("data-path");
- if (global._pluginUtils.metaKeyPressed(ev)) {
- openFileInNewWindow(filepath, false);
+ call = () => {
+ if (this.modal.modal.style.display === "block") {
+ this.hide();
} else {
- openFileInThisWindow(filepath);
+ this.modal.modal.style.display = "block";
+ this.modal.input.select();
}
- hideIfNeed();
- });
-
- const hide = () => {
- modal.modal.style.display = "none";
- modal.info.style.display = "none";
}
+}
- const call = () => {
- if (modal.modal.style.display === "block") {
- hide();
- } else {
- modal.modal.style.display = "block";
- modal.input.select();
- }
- }
-
- global._pluginUtils.registerWindowHotkey(config.HOTKEY, call);
-
- modal.modal.addEventListener("click", ev => {
- const caseButton = ev.target.closest("#typora-search-multi-input .case-option-btn");
- const pathButton = ev.target.closest("#typora-search-multi-input .path-option-btn");
-
- if (caseButton || pathButton) {
- ev.preventDefault();
- ev.stopPropagation();
- }
-
- if (caseButton) {
- caseButton.classList.toggle("select");
- config.CASE_SENSITIVE = !config.CASE_SENSITIVE;
- } else if (pathButton) {
- pathButton.classList.toggle("select");
- config.INCLUDE_FILE_PATH = !config.INCLUDE_FILE_PATH;
- }
- })
-
- if (config.REFOUCE_WHEN_OPEN_FILE) {
- global._pluginUtils.decorateOpenFile(null, () => {
- if (modal.modal.style.display === "block") {
- setTimeout(() => modal.input.select(), 300);
- }
- })
- }
-
- module.exports = {call};
-
- console.log("search_multi.js had been injected");
-})();
\ No newline at end of file
+module.exports = {
+ plugin: searchMultiKeywordPlugin
+};
diff --git a/plugin/test.js b/plugin/test.js
index c3f47367..205f890d 100644
--- a/plugin/test.js
+++ b/plugin/test.js
@@ -1,12 +1,17 @@
-(() => {
- // 打开新窗口后自动关闭
- global._pluginUtils.decorate(
- () => (File && File.editor && File.editor.library && File.editor.library.openFileInNewWindow),
- File.editor.library,
- "openFileInNewWindow",
- null,
- () => (!global._DO_NOT_CLOSE) && setTimeout(() => ClientCommand.close(), 3000)
- )
- JSBridge.invoke("window.toggleDevTools");
- console.log("test.js had been injected");
-})()
\ No newline at end of file
+class testPlugin extends global._basePlugin {
+ process() {
+ this.utils.decorate(
+ () => (File && File.editor && File.editor.library && File.editor.library.openFileInNewWindow),
+ File.editor.library,
+ "openFileInNewWindow",
+ null,
+ () => (!global._DO_NOT_CLOSE) && setTimeout(() => ClientCommand.close(), 3000)
+ )
+
+ JSBridge.invoke("window.toggleDevTools");
+ }
+}
+
+module.exports = {
+ plugin: testPlugin
+};
diff --git a/plugin/truncate_text.js b/plugin/truncate_text.js
index 021ed0d8..02e39839 100644
--- a/plugin/truncate_text.js
+++ b/plugin/truncate_text.js
@@ -1,12 +1,10 @@
-(() => {
- const config = global._pluginUtils.getPluginSetting("truncate_text");
-
- const callbackOtherPlugin = () => {
- const outlinePlugin = global._pluginUtils.getPlugin("outline");
- outlinePlugin && outlinePlugin.meta.refresh();
+class truncateTextPlugin extends global._basePlugin {
+ callbackOtherPlugin = () => {
+ const outlinePlugin = this.utils.getPlugin("outline");
+ outlinePlugin && outlinePlugin.refresh();
}
- const isInViewBox = el => {
+ isInViewBox = el => {
if (el.style.display) return false;
const totalHeight = window.innerHeight || document.documentElement.clientHeight;
const totalWidth = window.innerWidth || document.documentElement.clientWidth;
@@ -14,84 +12,84 @@
return (top >= 0 && left >= 0 && right <= totalWidth && bottom <= totalHeight);
}
- const hideFront = () => {
+ hideFront = () => {
const write = document.getElementById("write");
const length = write.children.length;
- if (length > config.REMAIN_LENGTH) {
- for (let i = 0; i <= length - config.REMAIN_LENGTH; i++) {
+ if (length > this.config.REMAIN_LENGTH) {
+ for (let i = 0; i <= length - this.config.REMAIN_LENGTH; i++) {
const ele = write.children[i];
- ele.classList.add(config.CLASS_NAME);
+ ele.classList.add(this.config.CLASS_NAME);
ele.style.display = "none";
}
}
}
- const showAll = () => {
+ showAll = () => {
const write = document.getElementById("write");
- write.getElementsByClassName(config.CLASS_NAME).forEach(el => el.classList.remove(config.CLASS_NAME));
+ write.getElementsByClassName(this.config.CLASS_NAME).forEach(el => el.classList.remove(this.config.CLASS_NAME));
write.children.forEach(el => el.style.display = "");
};
- const hideBaseView = () => {
+ hideBaseView = () => {
const write = document.getElementById("write");
let start = 0, end = 0;
write.children.forEach((ele, idx) => {
- if (isInViewBox(ele)) {
+ if (this.isInViewBox(ele)) {
if (!start) start = idx;
start = Math.min(start, idx);
end = Math.max(end, idx);
}
});
- const halfLength = config.REMAIN_LENGTH / 2;
+ const halfLength = this.config.REMAIN_LENGTH / 2;
start = Math.max(start - halfLength, 0);
end = Math.min(end + halfLength, write.children.length);
write.children.forEach((ele, idx) => {
if (idx < start || idx > end) {
- ele.classList.add(config.CLASS_NAME);
+ ele.classList.add(this.config.CLASS_NAME);
ele.style.display = "none";
} else {
- ele.classList.remove(config.CLASS_NAME);
+ ele.classList.remove(this.config.CLASS_NAME);
ele.style.display = "";
}
});
}
- // 已废弃
- const rollback2 = start => {
- if (document.querySelector(`#write > .${config.CLASS_NAME}`)) {
- let ele = start.closest("#write > [cid]");
- while (ele) {
- if (ele.classList.contains(config.CLASS_NAME)) {
- ele.classList.remove(config.CLASS_NAME);
- ele.style.display = "";
- }
- ele = ele.nextElementSibling;
- }
- }
- }
-
- const rollback = () => {
- if (document.querySelector(`#write > .${config.CLASS_NAME}`)) {
- showAll();
+ rollback = () => {
+ if (document.querySelector(`#write > .${this.config.CLASS_NAME}`)) {
+ this.showAll();
}
};
- const call = type => {
+ // // 已废弃
+ // rollback2 = start => {
+ // if (document.querySelector(`#write > .${this.config.CLASS_NAME}`)) {
+ // let ele = start.closest("#write > [cid]");
+ // while (ele) {
+ // if (ele.classList.contains(this.config.CLASS_NAME)) {
+ // ele.classList.remove(this.config.CLASS_NAME);
+ // ele.style.display = "";
+ // }
+ // ele = ele.nextElementSibling;
+ // }
+ // }
+ // }
+
+ call = type => {
if (type === "hide_front") {
- hideFront();
+ this.hideFront();
} else if (type === "show_all") {
- showAll();
+ this.showAll();
} else if (type === "hide_base_view") {
- hideBaseView();
+ this.hideBaseView();
}
- callbackOtherPlugin();
+ this.callbackOtherPlugin();
}
- const callArgs = [
+ callArgs = [
{
- arg_name: `只保留最后${config.REMAIN_LENGTH}段`,
+ arg_name: `只保留最后${this.config.REMAIN_LENGTH}段`,
arg_value: "hide_front"
},
{
@@ -103,13 +101,8 @@
arg_value: "hide_base_view"
}
];
+}
- module.exports = {
- call,
- callArgs,
- meta: {
- rollback,
- }
- };
- console.log("truncate_text.js had been injected");
-})()
+module.exports = {
+ plugin: truncateTextPlugin
+};
\ No newline at end of file
diff --git a/plugin/window_tab/window_tab.js b/plugin/window_tab/index.js
similarity index 64%
rename from plugin/window_tab/window_tab.js
rename to plugin/window_tab/index.js
index 731d694f..feb6ea9b 100644
--- a/plugin/window_tab/window_tab.js
+++ b/plugin/window_tab/index.js
@@ -1,13 +1,14 @@
-(() => {
- const config = global._pluginUtils.getPluginSetting("window_tab");
-
- if (window._options.framelessWindow && config.HIDE_WINDOW_TITLE_BAR) {
- document.querySelector("header").style.zIndex = "897";
- document.getElementById("top-titlebar").style.display = "none";
+class windowTabBarPlugin extends global._basePlugin {
+ beforeProcess = () => {
+ if (window._options.framelessWindow && this.config.HIDE_WINDOW_TITLE_BAR) {
+ document.querySelector("header").style.zIndex = "897";
+ document.getElementById("top-titlebar").style.display = "none";
+ }
}
- (() => {
- const css = `
+ style = () => {
+ const textID = "plugin-window-tab-style"
+ const text = `
#plugin-window-tab {
position: fixed;
top: 0;
@@ -15,7 +16,7 @@
height: 40px;
z-index: 898;
}
-
+
#plugin-window-tab .tab-bar {
background-color: var(--bg-color, white);
height: 100%;
@@ -25,28 +26,28 @@
width: calc(100vw - var(--sidebar-width, 0));
overflow-x: scroll
}
-
+
#plugin-window-tab .tab-bar::after {
content: "";
height: 100%;
width: 100vw;
border-bottom: solid 1px rgba(0, 0, 0, 0.07);
}
-
+
#plugin-window-tab .tab-bar:hover::-webkit-scrollbar-thumb {
visibility: visible;
}
-
+
#plugin-window-tab .tab-bar::-webkit-scrollbar {
height: 5px
}
-
+
#plugin-window-tab .tab-bar::-webkit-scrollbar-thumb {
height: 5px;
background-color: var(----active-file-bg-color, gray);
visibility: hidden
}
-
+
#plugin-window-tab .tab-container {
background-color: var(--side-bar-bg-color, gray);
height: 100%;
@@ -62,11 +63,11 @@
flex-shrink: 0;
cursor: pointer
}
-
+
#plugin-window-tab .tab-container.over {
background-color: var(--active-file-bg-color, lightgray);
}
-
+
#plugin-window-tab .name {
max-width: 350px;
padding-right: 15px;
@@ -76,7 +77,7 @@
text-overflow: ellipsis;
pointer-events: none
}
-
+
#plugin-window-tab .close-button {
padding: 4px;
display: flex;
@@ -84,11 +85,11 @@
justify-content: center;
border-radius: 5px
}
-
+
#plugin-window-tab .tab-container:hover > .close-button {
visibility: visible !important
}
-
+
#plugin-window-tab .close-icon {
position: relative;
width: 11px;
@@ -97,7 +98,7 @@
flex-direction: column;
justify-content: center;
}
-
+
#plugin-window-tab .close-icon::before,
#plugin-window-tab .close-icon::after {
content: "";
@@ -106,29 +107,29 @@
height: 2px;
background-color: var(--active-file-border-color, black)
}
-
+
#plugin-window-tab .close-icon::before {
transform: rotate(45deg)
}
-
+
#plugin-window-tab .close-icon::after {
transform: rotate(-45deg)
}
-
+
#plugin-window-tab .close-button:hover {
background-color: var(--active-file-bg-color, lightgray);
}
-
+
#plugin-window-tab .active {
border: solid 1px rgba(0, 0, 0, 0.07);
border-bottom: none;
background-color: var(--bg-color, white)
}
-
+
#plugin-window-tab .active .active-indicator {
display: block;
}
-
+
#plugin-window-tab .active-indicator {
position: absolute;
top: -1px;
@@ -138,13 +139,13 @@
background-color: var(--active-file-border-color, black);
display: none;
}
-
+
#plugin-window-tab [dragging] {
position: static !important;
box-sizing: border-box !important;
margin: 0 !important;
}
-
+
#plugin-window-tab .drag-obj {
position: fixed;
left: 0;
@@ -153,8 +154,10 @@
pointer-events: none;
}
`
- global._pluginUtils.insertStyle("plugin-window-tab-style", css);
+ return {textID, text}
+ }
+ html = () => {
const div = ``
const windowTab = document.createElement("div");
windowTab.id = "plugin-window-tab";
@@ -162,46 +165,135 @@
document.getElementById("write-style").parentElement
.insertBefore(windowTab, document.getElementById("write-style"));
- if (config.CHANGE_CONTENT_TOP) {
+ if (this.config.CHANGE_CONTENT_TOP) {
const {height} = document.querySelector("#plugin-window-tab").getBoundingClientRect();
document.querySelector("content").style.top = height + "px";
}
- if (config.CHANGE_NOTIFICATION_Z_INDEX) {
+ if (this.config.CHANGE_NOTIFICATION_Z_INDEX) {
const container = document.querySelector(".md-notification-container");
if (container) {
container.style.zIndex = "99999";
}
}
- })()
+ }
- const Package = global._pluginUtils.Package;
+ hotkey = () => {
+ return [
+ {
+ hotkey: this.config.SWITCH_NEXT_TAB_HOTKEY,
+ callback: this.nextTab
+ },
+ {
+ hotkey: this.config.SWITCH_PREVIOUS_TAB_HOTKEY,
+ callback: this.previousTab
+ },
+ {
+ hotkey: this.config.CLOSE_HOTKEY,
+ callback: this.closeActiveTab
+ },
+ ]
+ }
- const entities = {
- content: document.querySelector("content"),
- tabBar: document.querySelector("#plugin-window-tab .tab-bar"),
+ init = () => {
+ this.entities = {
+ content: document.querySelector("content"),
+ tabBar: document.querySelector("#plugin-window-tab .tab-bar"),
+ }
+ this.tabUtil = {tabs: [], activeIdx: 0,}
+ this.callMap = {
+ new_tab_open: () => this.config.LOCAL_OPEN = false,
+ local_open: () => this.config.LOCAL_OPEN = true,
+ save_tabs: this.saveTabs,
+ open_save_tabs: this.openSaveTabs,
+ }
}
- const tabUtil = {
- tabs: [],
- activeIdx: 0,
+ process = () => {
+ this.init();
+
+ this.utils.decorateOpenFile(null, (result, ...args) => {
+ const filePath = args[0];
+ filePath && this.openTab(filePath);
+ })
+
+ this.utils.loopDetector(() => !!File, () => {
+ const filePath = this.utils.getFilePath();
+ filePath && this.openTab(filePath);
+ });
+
+ if (this.config.DRAG_STYLE === 1) {
+ this.sort1();
+ } else {
+ this.sort2();
+ }
+
+ this.entities.tabBar.addEventListener("click", ev => {
+ const closeButton = ev.target.closest(".close-button");
+ const tabContainer = ev.target.closest(".tab-container");
+ if (!closeButton && !tabContainer) return;
+
+ ev.stopPropagation();
+ ev.preventDefault();
+
+ const tab = closeButton ? closeButton.closest(".tab-container") : tabContainer;
+ const idx = parseInt(tab.getAttribute("idx"));
+
+ if (this.utils.metaKeyPressed(ev)) {
+ this.openFileNewWindow(this.tabUtil.tabs[idx].path, false);
+ } else if (closeButton) {
+ this.closeTab(idx);
+ } else {
+ this.switchTab(idx);
+ }
+ })
+
+
+ this.entities.tabBar.addEventListener("wheel", ev => {
+ const target = ev.target.closest("#plugin-window-tab .tab-bar");
+ if (!target) return;
+
+ if (this.utils.metaKeyPressed(ev)) {
+ (ev.deltaY < 0) ? this.previousTab() : this.nextTab();
+ } else {
+ target.scrollLeft += ev.deltaY;
+ }
+ })
+
+ this.entities.content.addEventListener("scroll", () => {
+ this.tabUtil.tabs[this.tabUtil.activeIdx].scrollTop = this.entities.content.scrollTop;
+ })
+
+ document.querySelector(".typora-quick-open-list").addEventListener("mousedown", ev => {
+ const target = ev.target.closest(".typora-quick-open-item");
+ if (!target) return;
+
+ // 将原先的click行为改成ctrl+click
+ if (this.utils.metaKeyPressed(ev)) return;
+
+ ev.preventDefault();
+ ev.stopPropagation();
+ const filePath = target.getAttribute("data-path");
+ this.openFile(filePath);
+ }, true)
}
+
// 新窗口打开
- const openFileNewWindow = (path, isFolder) => File.editor.library.openFileInNewWindow(path, isFolder)
+ openFileNewWindow = (path, isFolder) => File.editor.library.openFileInNewWindow(path, isFolder)
// 新标签页打开
- const openFile = filePath => File.editor.library.openFile(filePath);
+ openFile = filePath => File.editor.library.openFile(filePath);
// 当前标签页打开
- const OpenFileLocal = filePath => {
- config.LOCAL_OPEN = true;
+ OpenFileLocal = filePath => {
+ this.config.LOCAL_OPEN = true;
File.editor.library.openFile(filePath);
- config.LOCAL_OPEN = false; // 自动还原
+ this.config.LOCAL_OPEN = false; // 自动还原
}
// 关闭窗口
- const closeWindow = () => JSBridge.invoke("window.close");
+ closeWindow = () => JSBridge.invoke("window.close");
- const getName = filePath => {
- let fileName = Package.Path.basename(filePath);
+ getName = filePath => {
+ let fileName = this.utils.Package.Path.basename(filePath);
const idx = fileName.lastIndexOf(".");
if (idx !== -1) {
fileName = fileName.substring(0, idx);
@@ -209,8 +301,8 @@
return fileName
}
- const newTabDiv = (filePath, idx, active = true) => {
- const fileName = getName(filePath);
+ newTabDiv = (filePath, idx, active = true) => {
+ const fileName = this.getName(filePath);
const _active = active ? "active" : "";
return `
@@ -220,23 +312,23 @@
}
// tabs->DOM的简单数据单向绑定
- const renderDOM = wantOpenPath => {
- let tabDiv = entities.tabBar.firstElementChild;
- tabUtil.tabs.forEach((tab, idx) => {
+ renderDOM = wantOpenPath => {
+ let tabDiv = this.entities.tabBar.firstElementChild;
+ this.tabUtil.tabs.forEach((tab, idx) => {
if (!tabDiv) {
- const _tabDiv = newTabDiv(tab.path, idx);
- entities.tabBar.insertAdjacentHTML('beforeend', _tabDiv);
- tabDiv = entities.tabBar.lastElementChild;
+ const _tabDiv = this.newTabDiv(tab.path, idx);
+ this.entities.tabBar.insertAdjacentHTML('beforeend', _tabDiv);
+ tabDiv = this.entities.tabBar.lastElementChild;
}
if (tab.path === wantOpenPath) {
tabDiv.classList.add("active");
tabDiv.scrollIntoViewIfNeeded();
- scrollContent(tab);
+ this.scrollContent(tab);
} else {
tabDiv.classList.remove("active");
}
tabDiv.setAttribute("idx", idx + "");
- tabDiv.querySelector(".name").innerText = getName(tab.path);
+ tabDiv.querySelector(".name").innerText = this.getName(tab.path);
tabDiv = tabDiv.nextElementSibling;
})
@@ -251,16 +343,16 @@
// 问题是我压根不知道content什么时候加载好
// 解决方法: 轮询设置scrollTop,当连续3次scrollTop不再改变,就判断content加载好了
// 这种方法很不环保,很ugly。但是我确实也想不到在不修改frame.js的前提下该怎么做了
- const scrollContent = activeTab => {
+ scrollContent = activeTab => {
if (!activeTab) return;
let count = 0;
const stopCount = 3;
const scrollTop = activeTab.scrollTop;
const _timer = setInterval(() => {
- const filePath = global._pluginUtils.getFilePath();
- if (filePath === activeTab.path && entities.content.scrollTop !== scrollTop) {
- entities.content.scrollTop = scrollTop;
+ const filePath = this.utils.getFilePath();
+ if (filePath === activeTab.path && this.entities.content.scrollTop !== scrollTop) {
+ this.entities.content.scrollTop = scrollTop;
count = 0;
} else {
count++;
@@ -268,134 +360,77 @@
if (count === stopCount) {
clearInterval(_timer);
}
- }, config.LOOP_DETECT_INTERVAL);
+ }, this.config.LOOP_DETECT_INTERVAL);
}
- const openTab = wantOpenPath => {
- const pathIdx = tabUtil.tabs.findIndex(tab => tab.path === wantOpenPath);
+ openTab = wantOpenPath => {
+ const pathIdx = this.tabUtil.tabs.findIndex(tab => tab.path === wantOpenPath);
// 原地打开并且不存在tab时,修改当前tab的文件路径
- if (config.LOCAL_OPEN && pathIdx === -1) {
- tabUtil.tabs[tabUtil.activeIdx].path = wantOpenPath;
+ if (this.config.LOCAL_OPEN && pathIdx === -1) {
+ this.tabUtil.tabs[this.tabUtil.activeIdx].path = wantOpenPath;
} else if (pathIdx === -1) {
- tabUtil.tabs.push({path: wantOpenPath, scrollTop: 0});
- tabUtil.activeIdx = tabUtil.tabs.length - 1;
+ this.tabUtil.tabs.push({path: wantOpenPath, scrollTop: 0});
+ this.tabUtil.activeIdx = this.tabUtil.tabs.length - 1;
} else if (pathIdx !== -1) {
- tabUtil.activeIdx = pathIdx;
+ this.tabUtil.activeIdx = pathIdx;
}
- renderDOM(wantOpenPath);
+ this.renderDOM(wantOpenPath);
}
- const switchTab = idx => {
- tabUtil.activeIdx = idx;
- openFile(tabUtil.tabs[tabUtil.activeIdx].path);
+ switchTab = idx => {
+ this.tabUtil.activeIdx = idx;
+ this.openFile(this.tabUtil.tabs[this.tabUtil.activeIdx].path);
}
- const switchTabByPath = path => {
- for (let idx = 0; idx < tabUtil.tabs.length; idx++) {
- if (tabUtil.tabs[idx].path === path) {
- switchTab(idx);
+ switchTabByPath = path => {
+ for (let idx = 0; idx < this.tabUtil.tabs.length; idx++) {
+ if (this.tabUtil.tabs[idx].path === path) {
+ this.switchTab(idx);
return
}
}
}
- const previousTab = () => {
- const idx = (tabUtil.activeIdx === 0) ? tabUtil.tabs.length - 1 : tabUtil.activeIdx - 1;
- switchTab(idx);
+ previousTab = () => {
+ const idx = (this.tabUtil.activeIdx === 0) ? this.tabUtil.tabs.length - 1 : this.tabUtil.activeIdx - 1;
+ this.switchTab(idx);
}
- const nextTab = () => {
- const idx = (tabUtil.activeIdx === tabUtil.tabs.length - 1) ? 0 : tabUtil.activeIdx + 1;
- switchTab(idx);
+ nextTab = () => {
+ const idx = (this.tabUtil.activeIdx === this.tabUtil.tabs.length - 1) ? 0 : this.tabUtil.activeIdx + 1;
+ this.switchTab(idx);
}
- const closeTab = idx => {
- tabUtil.tabs.splice(idx, 1);
- if (tabUtil.tabs.length === 0) {
- closeWindow();
+ closeTab = idx => {
+ this.tabUtil.tabs.splice(idx, 1);
+ if (this.tabUtil.tabs.length === 0) {
+ this.closeWindow();
return
}
- if (tabUtil.activeIdx !== 0 && idx <= tabUtil.activeIdx) {
- tabUtil.activeIdx--;
+ if (this.tabUtil.activeIdx !== 0 && idx <= this.tabUtil.activeIdx) {
+ this.tabUtil.activeIdx--;
}
- switchTab(tabUtil.activeIdx);
+ this.switchTab(this.tabUtil.activeIdx);
}
- const closeActiveTab = () => closeTab(tabUtil.activeIdx);
-
- global._pluginUtils.decorateOpenFile(null, (result, ...args) => {
- const filePath = args[0];
- filePath && openTab(filePath);
- })
-
- global._pluginUtils.loopDetector(() => !!File, () => {
- const filePath = global._pluginUtils.getFilePath();
- filePath && openTab(filePath);
- });
-
- global._pluginUtils.registerWindowHotkey(config.SWITCH_NEXT_TAB_HOTKEY, nextTab);
- global._pluginUtils.registerWindowHotkey(config.SWITCH_PREVIOUS_TAB_HOTKEY, previousTab);
- global._pluginUtils.registerWindowHotkey(config.CLOSE_HOTKEY, closeActiveTab);
+ closeActiveTab = () => this.closeTab(this.tabUtil.activeIdx);
- entities.tabBar.addEventListener("click", ev => {
- const closeButton = ev.target.closest(".close-button");
- const tabContainer = ev.target.closest(".tab-container");
- if (!closeButton && !tabContainer) return;
-
- ev.stopPropagation();
- ev.preventDefault();
-
- const tab = closeButton ? closeButton.closest(".tab-container") : tabContainer;
- const idx = parseInt(tab.getAttribute("idx"));
-
- if (global._pluginUtils.metaKeyPressed(ev)) {
- openFileNewWindow(tabUtil.tabs[idx].path, false);
- } else if (closeButton) {
- closeTab(idx);
- } else {
- switchTab(idx);
- }
- })
-
- entities.tabBar.addEventListener("wheel", ev => {
- const target = ev.target.closest("#plugin-window-tab .tab-bar");
- if (!target) return;
-
- if (global._pluginUtils.metaKeyPressed(ev)) {
- (ev.deltaY < 0) ? previousTab() : nextTab();
- } else {
- target.scrollLeft += ev.deltaY;
- }
- })
-
- entities.content.addEventListener("scroll", () => {
- tabUtil.tabs[tabUtil.activeIdx].scrollTop = entities.content.scrollTop;
- })
-
- document.querySelector(".typora-quick-open-list").addEventListener("mousedown", ev => {
- const target = ev.target.closest(".typora-quick-open-item");
- if (!target) return;
-
- // 将原先的click行为改成ctrl+click
- if (global._pluginUtils.metaKeyPressed(ev)) return;
-
- ev.preventDefault();
- ev.stopPropagation();
- const filePath = target.getAttribute("data-path");
- openFile(filePath);
- }, true)
-
- const newWindowIfNeed = (offsetY, tab) => {
+ newWindowIfNeed = (offsetY, tab) => {
offsetY = Math.abs(offsetY);
- const height = entities.tabBar.getBoundingClientRect().height;
- if (offsetY > height * config.HEIGHT_SCALE) {
+ const height = this.entities.tabBar.getBoundingClientRect().height;
+ if (offsetY > height * this.config.HEIGHT_SCALE) {
const idx = parseInt(tab.getAttribute("idx"));
- const _path = tabUtil.tabs[idx].path;
- openFileNewWindow(_path, false);
+ const _path = this.tabUtil.tabs[idx].path;
+ this.openFileNewWindow(_path, false);
}
}
- if (config.DRAG_STYLE === 1) {
+ sort1 = () => {
+ const newWindowIfNeed = this.newWindowIfNeed;
+ const tabUtil = this.tabUtil;
+ const openTab = this.openTab;
+ const entities = this.entities;
+
const resetTabBar = () => {
const tabs = document.querySelectorAll("#plugin-window-tab .tab-container");
const activeIdx = parseInt(entities.tabBar.querySelector(".tab-container.active").getAttribute("idx"));
@@ -416,13 +451,13 @@
tabBar.on("dragstart", ".tab-container", function (ev) {
_offsetX = ev.offsetX;
currentDragItem = this;
- }).on("dragend", ".tab-container", function (ev) {
+ }).on("dragend", ".tab-container", function () {
currentDragItem = null;
}).on("dragover", ".tab-container", function (ev) {
ev.preventDefault();
if (!currentDragItem) return;
this[ev.offsetX > _offsetX ? 'after' : 'before'](currentDragItem);
- }).on("dragenter", function (ev) {
+ }).on("dragenter", function () {
return false
})
@@ -516,7 +551,12 @@
})
}
- if (config.DRAG_STYLE === 2) {
+ sort2 = () => {
+ const newWindowIfNeed = this.newWindowIfNeed;
+ const tabUtil = this.tabUtil;
+ const openTab = this.openTab;
+ const entities = this.entities;
+
const toggleOver = (target, f) => {
if (f === "add") {
target.classList.add("over");
@@ -556,35 +596,34 @@
})
}
- //////////////////////// 以下是声明式插件系统代码 ////////////////////////
- const getTabFile = () => global._pluginUtils.joinPath("./plugin/window_tab/save_tabs.json");
+ getTabFile = () => this.utils.joinPath("./plugin/window_tab/save_tabs.json");
- const exitTabFile = () => {
- const filepath = getTabFile();
+ exitTabFile = () => {
+ const filepath = this.getTabFile();
try {
- Package.Fs.accessSync(filepath, Package.Fs.constants.F_OK);
+ this.utils.Package.Fs.accessSync(filepath, this.utils.Package.Fs.constants.F_OK);
return true
} catch (err) {
}
}
- const saveTabs = () => {
- const dataset = tabUtil.tabs.map((tab, idx) => {
+ saveTabs = () => {
+ const dataset = this.tabUtil.tabs.map((tab, idx) => {
return {
idx: idx,
path: tab.path,
- active: idx === tabUtil.activeIdx,
+ active: idx === this.tabUtil.activeIdx,
scrollTop: tab.scrollTop,
}
})
- const filepath = getTabFile();
+ const filepath = this.getTabFile();
const str = JSON.stringify({"save_tabs": dataset}, null, "\t");
- Package.Fs.writeFileSync(filepath, str);
+ this.utils.Package.Fs.writeFileSync(filepath, str);
}
- const openSaveTabs = () => {
- const filepath = getTabFile();
- Package.Fs.readFile(filepath, 'utf8', (error, data) => {
+ openSaveTabs = () => {
+ const filepath = this.getTabFile();
+ this.utils.Package.Fs.readFile(filepath, 'utf8', (error, data) => {
if (error) {
window.alert(error);
return;
@@ -594,9 +633,9 @@
let activePath;
tabs.forEach(tab => {
- const existTab = tabUtil.tabs.filter(t => t.path === tab.path)[0];
+ const existTab = this.tabUtil.tabs.filter(t => t.path === tab.path)[0];
if (!existTab) {
- tabUtil.tabs.push({path: tab.path, scrollTop: tab.scrollTop});
+ this.tabUtil.tabs.push({path: tab.path, scrollTop: tab.scrollTop});
} else {
existTab.scrollTop = tab.scrollTop;
}
@@ -606,60 +645,38 @@
}
})
if (activePath) {
- switchTabByPath(activePath);
+ this.switchTabByPath(activePath);
} else {
- switchTab(tabUtil.activeIdx);
+ this.switchTab(this.tabUtil.activeIdx);
}
})
}
- const dynamicCallArgsGenerator = () => {
+ dynamicCallArgsGenerator = () => {
let args = [];
- if (!exitTabFile()) {
+ if (!this.exitTabFile()) {
args.push({arg_name: "保存所有的标签页", arg_value: "save_tabs"});
} else {
args.push({arg_name: "覆盖保存的标签页", arg_value: "save_tabs"});
args.push({arg_name: "打开保存的标签页", arg_value: "open_save_tabs"});
}
- if (config.LOCAL_OPEN) {
+ if (this.config.LOCAL_OPEN) {
args.push({arg_name: "在新标签打开文件", arg_value: "new_tab_open"});
// 空白标签不允许当前标签打开
- } else if (global._pluginUtils.getFilePath()) {
+ } else if (this.utils.getFilePath()) {
args.push({arg_name: "在当前标签打开文件", arg_value: "local_open"});
}
return args
}
- const callMap = {
- new_tab_open: () => config.LOCAL_OPEN = false,
- local_open: () => config.LOCAL_OPEN = true,
- save_tabs: saveTabs,
- open_save_tabs: openSaveTabs,
- }
- const call = type => {
- const func = callMap[type];
+ call = type => {
+ const func = this.callMap[type];
func && func();
}
+}
- module.exports = {
- call,
- dynamicCallArgsGenerator,
- meta: {
- call,
- openTab,
- switchTab,
- switchTabByPath,
- previousTab,
- nextTab,
- closeTab,
- closeActiveTab,
- openFileNewWindow,
- openFile,
- OpenFileLocal,
- closeWindow,
- }
- };
+module.exports = {
+ plugin: windowTabBarPlugin
+};
- console.log("window_tab.js had been injected");
-})()
\ No newline at end of file