diff --git a/src/ts/ir/processKeydown.ts b/src/ts/ir/processKeydown.ts
index d7f7a863c..e1e4d708a 100644
--- a/src/ts/ir/processKeydown.ts
+++ b/src/ts/ir/processKeydown.ts
@@ -1,10 +1,9 @@
import {Constants} from "../constants";
import {isCtrl} from "../util/compatibility";
import {scrollCenter} from "../util/editorCommenEvent";
-import {fixList, fixMarkdown, fixTab, fixTable} from "../util/fixBrowserBehavior";
+import {fixBlockquote, fixCodeBlock, fixList, fixMarkdown, fixTab, fixTable} from "../util/fixBrowserBehavior";
import {hasClosestByAttribute, hasClosestByClassName, hasClosestByMatchTag} from "../util/hasClosest";
import {getSelectPosition, setRangeByWbr} from "../util/selection";
-import {processAfterRender} from "./process";
export const processKeydown = (vditor: IVditor, event: KeyboardEvent) => {
vditor.ir.composingLock = event.isComposing;
@@ -52,6 +51,10 @@ export const processKeydown = (vditor: IVditor, event: KeyboardEvent) => {
if (fixList(range, vditor, pElement, event)) {
return true;
}
+ // blockquote
+ if (fixBlockquote(vditor, range, event, pElement)) {
+ return true;
+ }
}
// 代码块
@@ -59,44 +62,6 @@ export const processKeydown = (vditor: IVditor, event: KeyboardEvent) => {
if (preRenderElement && preRenderElement.tagName === "PRE") {
const codeRenderElement = preRenderElement.firstChild as HTMLElement;
const codePosition = getSelectPosition(codeRenderElement, range);
- // 换行
- if (!isCtrl(event) && !event.altKey && event.key === "Enter") {
- if (!codeRenderElement.textContent.endsWith("\n")) {
- codeRenderElement.insertAdjacentText("beforeend", "\n");
- }
- range.insertNode(document.createTextNode("\n"));
- range.collapse(false);
- processAfterRender(vditor);
- scrollCenter(vditor.ir.element);
- event.preventDefault();
- return true;
- }
-
- // tab
- if (vditor.options.tab && event.key === "Tab" && !event.shiftKey && range.toString() === "") {
- range.insertNode(document.createTextNode(vditor.options.tab));
- range.collapse(false);
- processAfterRender(vditor);
- event.preventDefault();
- return true;
- }
-
- // TODO shift + tab, shift and 选中文字
-
- if (event.key === "Backspace" && !isCtrl(event) && !event.shiftKey && !event.altKey) {
- if ((codePosition.start === 0 ||
- (codePosition.start === 1 && codeRenderElement.innerText === "\n")) // 空代码块,光标在 \n 后
- && range.toString() === "") {
- // Backspace: 光标位于第零个字符,仅删除代码块标签
- preRenderElement.parentElement.outerHTML =
- `
${codeRenderElement.innerHTML}
`;
- setRangeByWbr(vditor.ir.element, range);
- processAfterRender(vditor);
- event.preventDefault();
- return true;
- }
- }
-
// 数学公式上无元素,按上或左将添加新块
if ((event.key === "ArrowUp" || event.key === "ArrowLeft") &&
codeRenderElement.getAttribute("data-type") === "math-block"
@@ -123,7 +88,10 @@ export const processKeydown = (vditor: IVditor, event: KeyboardEvent) => {
}
event.preventDefault();
return true;
+ }
+ if (fixCodeBlock(vditor, event, preRenderElement, range)) {
+ return true;
}
}
// 代码块语言
@@ -156,45 +124,6 @@ export const processKeydown = (vditor: IVditor, event: KeyboardEvent) => {
return true;
}
- // blockquote
- const blockquoteElement = hasClosestByMatchTag(startContainer, "BLOCKQUOTE");
- if (blockquoteElement && range.toString() === "") {
- if (event.key === "Backspace" && !isCtrl(event) && !event.shiftKey && !event.altKey &&
- getSelectPosition(blockquoteElement, range).start === 0) {
- // Backspace: 光标位于引用中的第零个字符,仅删除引用标签
- range.insertNode(document.createElement("wbr"));
- blockquoteElement.outerHTML = blockquoteElement.innerHTML;
- setRangeByWbr(vditor.ir.element, range);
- processAfterRender(vditor);
- event.preventDefault();
- return true;
- }
-
- if (pElement && event.key === "Enter" && !isCtrl(event) && !event.shiftKey && !event.altKey
- && pElement.parentElement.tagName === "BLOCKQUOTE") {
- // Enter: 空行回车应逐层跳出
- let isEmpty = false;
- if (pElement.innerHTML.replace(Constants.ZWSP, "") === "\n") {
- // 空 P
- isEmpty = true;
- pElement.remove();
- } else if (pElement.innerHTML.endsWith("\n\n") &&
- getSelectPosition(pElement, range).start === pElement.textContent.length - 1) {
- // 软换行
- pElement.innerHTML = pElement.innerHTML.substr(0, pElement.innerHTML.length - 2);
- isEmpty = true;
- }
- if (isEmpty) {
- // 需添加零宽字符,否则的话无法记录 undo
- blockquoteElement.insertAdjacentHTML("afterend", `${Constants.ZWSP}\n
`);
- setRangeByWbr(vditor.ir.element, range);
- processAfterRender(vditor);
- event.preventDefault();
- return true;
- }
- }
- }
-
if (fixTab(vditor, range, event)) {
return true;
}
diff --git a/src/ts/util/fixBrowserBehavior.ts b/src/ts/util/fixBrowserBehavior.ts
index a908f5628..dd6a4e434 100644
--- a/src/ts/util/fixBrowserBehavior.ts
+++ b/src/ts/util/fixBrowserBehavior.ts
@@ -2,10 +2,11 @@ import {processAfterRender} from "../ir/process";
import {afterRenderEvent} from "../wysiwyg/afterRenderEvent";
import {isCtrl} from "./compatibility";
import {scrollCenter} from "./editorCommenEvent";
-import {hasClosestByMatchTag} from "./hasClosest";
+import {hasClosestBlock, hasClosestByMatchTag} from "./hasClosest";
import {getLastNode} from "./hasClosest";
import {matchHotKey} from "./hotKey";
import {getSelectPosition, setRangeByWbr} from "./selection";
+import {Constants} from "../constants";
// 光标设置到前一个表格中
const goPreviousCell = (cellElement: HTMLElement, range: Range, isSelected = true) => {
@@ -127,9 +128,8 @@ export const fixList = (range: Range, vditor: IVditor, pElement: HTMLElement, ev
const liElement = hasClosestByMatchTag(startContainer, "LI");
if (liElement) {
if (!isCtrl(event) && !event.altKey && event.key === "Enter" &&
- (event.shiftKey // 软换行
- // fix li 中有多个 P 时,在第一个 P 中换行会在下方生成新的 li
- || (!event.shiftKey && pElement && liElement.contains(pElement) && pElement.nextElementSibling))) {
+ // fix li 中有多个 P 时,在第一个 P 中换行会在下方生成新的 li
+ (!event.shiftKey && pElement && liElement.contains(pElement) && pElement.nextElementSibling)) {
if (liElement && !liElement.textContent.endsWith("\n")) {
// li 结尾需 \n
liElement.insertAdjacentText("beforeend", "\n");
@@ -479,3 +479,109 @@ export const fixTable = (vditor: IVditor, event: KeyboardEvent, range: Range) =>
}
return false;
};
+
+export const fixCodeBlock = (vditor: IVditor, event: KeyboardEvent, codeRenderElement: HTMLElement, range: Range) => {
+ // 行级代码块中 command + a,近对当前代码块进行全选
+ if (codeRenderElement.tagName === "PRE" && matchHotKey("⌘-A", event)) {
+ range.selectNodeContents(codeRenderElement.firstElementChild);
+ event.preventDefault();
+ return true;
+ }
+
+ // tab
+ // TODO shift + tab, shift and 选中文字
+ if (vditor.options.tab && event.key === "Tab" && !event.shiftKey && range.toString() === "") {
+ range.insertNode(document.createTextNode(vditor.options.tab));
+ range.collapse(false);
+ execAfterRender(vditor);
+ event.preventDefault();
+ return true;
+ }
+
+ // Backspace: 光标位于第零个字符,仅删除代码块标签
+ if (event.key === "Backspace" && !isCtrl(event) && !event.shiftKey && !event.altKey) {
+ const codePosition = getSelectPosition(codeRenderElement, range);
+ if ((codePosition.start === 0 ||
+ (codePosition.start === 1 && codeRenderElement.innerText === "\n")) // 空代码块,光标在 \n 后
+ && range.toString() === "") {
+ codeRenderElement.parentElement.outerHTML =
+ `${codeRenderElement.firstElementChild.innerHTML}
`;
+ setRangeByWbr(vditor[vditor.currentMode].element, range);
+ execAfterRender(vditor);
+ event.preventDefault();
+ return true;
+ }
+ }
+
+ // 换行
+ if (!isCtrl(event) && !event.altKey && event.key === "Enter") {
+ if (!codeRenderElement.firstElementChild.textContent.endsWith("\n")) {
+ codeRenderElement.firstElementChild.insertAdjacentText("beforeend", "\n");
+ }
+ range.insertNode(document.createTextNode("\n"));
+ range.collapse(false);
+ execAfterRender(vditor);
+ scrollCenter(vditor[vditor.currentMode].element);
+ event.preventDefault();
+ return true;
+ }
+ return false
+}
+
+export const fixBlockquote = (vditor: IVditor, range: Range, event: KeyboardEvent, pElement: HTMLElement) => {
+ const startContainer = range.startContainer
+ const blockquoteElement = hasClosestByMatchTag(startContainer, "BLOCKQUOTE");
+ if (blockquoteElement && range.toString() === "") {
+ if (event.key === "Backspace" && !isCtrl(event) && !event.shiftKey && !event.altKey &&
+ getSelectPosition(blockquoteElement, range).start === 0) {
+ // Backspace: 光标位于引用中的第零个字符,仅删除引用标签
+ range.insertNode(document.createElement("wbr"));
+ blockquoteElement.outerHTML = blockquoteElement.innerHTML;
+ setRangeByWbr(vditor[vditor.currentMode].element, range);
+ execAfterRender(vditor);
+ event.preventDefault();
+ return true;
+ }
+
+ if (pElement && event.key === "Enter" && !isCtrl(event) && !event.shiftKey && !event.altKey
+ && pElement.parentElement.tagName === "BLOCKQUOTE") {
+ // Enter: 空行回车应逐层跳出
+ let isEmpty = false;
+ if (pElement.innerHTML.replace(Constants.ZWSP, "") === "\n") {
+ // 空 P
+ isEmpty = true;
+ pElement.remove();
+ } else if (pElement.innerHTML.endsWith("\n\n") &&
+ getSelectPosition(pElement, range).start === pElement.textContent.length - 1) {
+ // 软换行
+ pElement.innerHTML = pElement.innerHTML.substr(0, pElement.innerHTML.length - 2);
+ isEmpty = true;
+ }
+ if (isEmpty) {
+ if (vditor.currentMode === "wysiwyg") {
+ (vditor.wysiwyg.popover.querySelector('[data-type="insert-after"]') as HTMLElement).click();
+ event.preventDefault();
+ return true;
+ } else {
+ // 需添加零宽字符,否则的话无法记录 undo
+ blockquoteElement.insertAdjacentHTML("afterend", `${Constants.ZWSP}\n
`);
+ setRangeByWbr(vditor[vditor.currentMode].element, range);
+ processAfterRender(vditor);
+ event.preventDefault();
+ return true;
+ }
+ }
+ }
+ const blockElement = hasClosestBlock(startContainer);
+ if (vditor.currentMode === "wysiwyg" && blockElement && matchHotKey("⌘-⇧-:", event)) {
+ // 插入 blockquote
+ range.insertNode(document.createElement("wbr"));
+ blockElement.outerHTML = `${blockElement.outerHTML}
`;
+ setRangeByWbr(vditor.wysiwyg.element, range);
+ afterRenderEvent(vditor);
+ event.preventDefault();
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/src/ts/wysiwyg/processKeydown.ts b/src/ts/wysiwyg/processKeydown.ts
index 9896aecfb..5e578abb7 100644
--- a/src/ts/wysiwyg/processKeydown.ts
+++ b/src/ts/wysiwyg/processKeydown.ts
@@ -1,7 +1,7 @@
import {Constants} from "../constants";
import {isCtrl} from "../util/compatibility";
import {scrollCenter} from "../util/editorCommenEvent";
-import {fixList, fixMarkdown, fixTab, fixTable} from "../util/fixBrowserBehavior";
+import {fixBlockquote, fixCodeBlock, fixList, fixMarkdown, fixTab, fixTable} from "../util/fixBrowserBehavior";
import {
getLastNode,
getTopList, hasClosestBlock, hasClosestByAttribute,
@@ -14,7 +14,7 @@ import {getSelectPosition, setRangeByWbr, setSelectionFocus} from "../util/selec
import {afterRenderEvent} from "./afterRenderEvent";
import {listOutdent} from "./highlightToolbar";
import {nextIsCode} from "./inlineTag";
-import {processCodeRender, showCode} from "./processCodeRender";
+import {showCode} from "./processCodeRender";
import {removeHeading, setHeading} from "./setHeading";
export const processKeydown = (vditor: IVditor, event: KeyboardEvent) => {
@@ -50,6 +50,10 @@ export const processKeydown = (vditor: IVditor, event: KeyboardEvent) => {
if (fixList(range, vditor, pElement, event)) {
return true;
}
+ // blockquote
+ if (fixBlockquote(vditor, range, event, pElement)) {
+ return true;
+ }
}
// table
@@ -68,6 +72,7 @@ export const processKeydown = (vditor: IVditor, event: KeyboardEvent) => {
event.preventDefault();
return true;
}
+
// alt+enter: 代码块切换到语言 https://github.com/Vanessa219/vditor/issues/54
if (!isCtrl(event) && !event.shiftKey && event.altKey && event.key === "Enter" &&
codeRenderElement.getAttribute("data-type") === "code-block") {
@@ -78,56 +83,10 @@ export const processKeydown = (vditor: IVditor, event: KeyboardEvent) => {
return true;
}
- // 行级代码块中 command + a,近对当前代码块进行全选
- if (codeRenderElement.getAttribute("data-block") === "0" && matchHotKey("⌘-A", event)) {
- range.selectNodeContents(codeRenderElement.firstElementChild.firstElementChild);
- event.preventDefault();
+ if (codeRenderElement.getAttribute("data-block") === "0" &&
+ fixCodeBlock(vditor, event, codeRenderElement.firstElementChild as HTMLElement, range)) {
return true;
}
-
- // 换行
- if (!isCtrl(event) && !event.altKey && event.key === "Enter" &&
- codeRenderElement.getAttribute("data-block") === "0") {
- if (!codeRenderElement.firstElementChild.firstElementChild.textContent.endsWith("\n")) {
- codeRenderElement.firstElementChild.firstElementChild.insertAdjacentText("beforeend", "\n");
- }
- range.insertNode(document.createTextNode("\n"));
- range.collapse(false);
- afterRenderEvent(vditor);
- processCodeRender(codeRenderElement, vditor);
- scrollCenter(vditor.wysiwyg.element);
- event.preventDefault();
- return true;
- }
-
- // tab
- if (vditor.options.tab && event.key === "Tab" && !event.shiftKey && range.toString() === "" &&
- codeRenderElement.getAttribute("data-block") === "0") {
- range.insertNode(document.createTextNode(vditor.options.tab));
- range.collapse(false);
- afterRenderEvent(vditor);
- processCodeRender(codeRenderElement, vditor);
- event.preventDefault();
- return true;
- }
-
- // TODO shift + tab, shift and 选中文字
-
- if (event.key === "Backspace" && !isCtrl(event) && !event.shiftKey && !event.altKey
- && codeRenderElement.getAttribute("data-block") === "0") {
- const codePosition = getSelectPosition(codeRenderElement, range);
- if ((codePosition.start === 0 ||
- (codePosition.start === 1 && codeRenderElement.innerText === "\n")) // 空代码块,光标在 \n 后
- && range.toString() === "") {
- // Backspace: 光标位于第零个字符,仅删除代码块标签
- codeRenderElement.outerHTML =
- `${codeRenderElement.firstElementChild.firstElementChild.innerHTML}
`;
- setRangeByWbr(vditor.wysiwyg.element, range);
- afterRenderEvent(vditor);
- event.preventDefault();
- return true;
- }
- }
}
// 顶层 blockquote
@@ -155,52 +114,6 @@ export const processKeydown = (vditor: IVditor, event: KeyboardEvent) => {
}
}
- // blockquote
- const blockquoteElement = hasClosestByMatchTag(startContainer, "BLOCKQUOTE");
- if (blockquoteElement && range.toString() === "") {
- if (event.key === "Backspace" && !isCtrl(event) && !event.shiftKey && !event.altKey &&
- getSelectPosition(blockquoteElement, range).start === 0) {
- // Backspace: 光标位于引用中的第零个字符,仅删除引用标签
- range.insertNode(document.createElement("wbr"));
- blockquoteElement.outerHTML = blockquoteElement.innerHTML;
- setRangeByWbr(vditor.wysiwyg.element, range);
- afterRenderEvent(vditor);
- event.preventDefault();
- return true;
- }
-
- if (pElement && event.key === "Enter" && !isCtrl(event) && !event.shiftKey && !event.altKey
- && pElement.parentElement.tagName === "BLOCKQUOTE") {
- // Enter: 空行回车应逐层跳出
- let isEmpty = false;
- if (pElement.innerHTML.replace(Constants.ZWSP, "") === "\n") {
- // 空 P
- isEmpty = true;
- pElement.remove();
- } else if (pElement.innerHTML.endsWith("\n\n") &&
- getSelectPosition(pElement, range).start === pElement.textContent.length - 1) {
- // 软换行
- pElement.innerHTML = pElement.innerHTML.substr(0, pElement.innerHTML.length - 2);
- isEmpty = true;
- }
- if (isEmpty) {
- (vditor.wysiwyg.popover.querySelector('[data-type="insert-after"]') as HTMLElement).click();
- event.preventDefault();
- return true;
- }
- }
-
- if (blockElement && matchHotKey("⌘-⇧-:", event)) {
- // 插入 blockquote
- range.insertNode(document.createElement("wbr"));
- blockElement.outerHTML = `${blockElement.outerHTML}
`;
- setRangeByWbr(vditor.wysiwyg.element, range);
- afterRenderEvent(vditor);
- event.preventDefault();
- return true;
- }
- }
-
// h1-h6
const headingElement = hasClosestByTag(startContainer, "H");
if (headingElement && headingElement.tagName.length === 2) {
@@ -429,7 +342,7 @@ export const processKeydown = (vditor: IVditor, event: KeyboardEvent) => {
return true;
}
- // shift+enter:软换行,但 table/hr/heading 处理、cell 内换行、block render 换行、li 软换行处理单独写在上面
+ // shift+enter:软换行,但 table/hr/heading 处理、cell 内换行、block render 换行处理单独写在上面
if (!isCtrl(event) && event.shiftKey && !event.altKey && event.key === "Enter") {
if (["STRONG", "S", "STRONG", "I", "EM", "B"].includes(startContainer.parentElement.tagName)) {
// 行内元素软换行需继续 https://github.com/Vanessa219/vditor/issues/170