Skip to content

Commit

Permalink
♻️ Vanessa219#27
Browse files Browse the repository at this point in the history
  • Loading branch information
Vanessa219 authored and stevapple committed Apr 8, 2020
1 parent f0873ff commit 5a1d7d3
Show file tree
Hide file tree
Showing 11 changed files with 245 additions and 256 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@

### v3.0.5 / undefined

* [235](https://github.com/Vanessa219/vditor/pull/235) 修复父元素自定义行高时工具栏垂直不居中 `修复缺陷`
* [210](https://github.com/Vanessa219/vditor/issues/210) inks with korean character(windows chrome & firefox) `修复缺陷`
* [231](https://github.com/Vanessa219/vditor/issues/231) 支持直接传入元素进行初始化 `引入特性`

Expand Down
2 changes: 1 addition & 1 deletion src/ts/ir/input.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {isHeadingMD, isHrMD} from "../util/fixBrowserBehavior";
import {getTopList, hasClosestBlock, hasClosestByClassName, hasClosestByTag} from "../util/hasClosest";
import {log} from "../util/log";
import {isHeadingMD, isHrMD} from "../util/processMD";
import {getSelectPosition, setRangeByWbr} from "../util/selection";
import {processAfterRender, processCodeRender} from "./process";

Expand Down
12 changes: 5 additions & 7 deletions src/ts/ir/processKeydown.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import {Constants} from "../constants";
import {isCtrl} from "../util/compatibility";
import {scrollCenter} from "../util/editorCommenEvent";
import {fixList, fixMarkdown, fixTab, fixTable} from "../util/fixBrowserBehavior";
import {hasClosestByAttribute, hasClosestByClassName, hasClosestByMatchTag} from "../util/hasClosest";
import {processList} from "../util/processList";
import {mdKeydown, processTab} from "../util/processMD";
import {tableHotkey} from "../util/processTable";
import {getSelectPosition, setRangeByWbr} from "../util/selection";
import {processAfterRender} from "./process";

Expand Down Expand Up @@ -47,11 +45,11 @@ export const processKeydown = (vditor: IVditor, event: KeyboardEvent) => {
const pElement = hasClosestByMatchTag(startContainer, "P");
if (pElement) {
// md 处理
if (mdKeydown(event, vditor, pElement, range)) {
if (fixMarkdown(event, vditor, pElement, range)) {
return true;
}
// li
if (processList(range, vditor, pElement, event)) {
if (fixList(range, vditor, pElement, event)) {
return true;
}
}
Expand Down Expand Up @@ -154,7 +152,7 @@ export const processKeydown = (vditor: IVditor, event: KeyboardEvent) => {
}

// table
if (tableHotkey(vditor, event, range)) {
if (fixTable(vditor, event, range)) {
return true;
}

Expand Down Expand Up @@ -197,7 +195,7 @@ export const processKeydown = (vditor: IVditor, event: KeyboardEvent) => {
}
}

if (processTab(vditor, range, event)) {
if (fixTab(vditor, range, event)) {
return true;
}

Expand Down
232 changes: 229 additions & 3 deletions src/ts/util/processTable.ts → src/ts/util/fixBrowserBehavior.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import {processAfterRender} from "../ir/process";
import {afterRenderEvent} from "../wysiwyg/afterRenderEvent";
import {isCtrl} from "./compatibility";
import {scrollCenter} from "./editorCommenEvent";
import {hasClosestByMatchTag} from "./hasClosest";
import {getLastNode} from "./hasClosest";
import {matchHotKey} from "./hotKey";
import {execAfterRender} from "./processMD";
import {setRangeByWbr} from "./selection";
import {getSelectPosition, setRangeByWbr} from "./selection";

// 光标设置到前一个表格中
const goPreviousCell = (cellElement: HTMLElement, range: Range, isSelected = true) => {
Expand Down Expand Up @@ -47,7 +49,231 @@ export const setTableAlign = (tableElement: HTMLTableElement, type: string) => {
}
};

export const tableHotkey = (vditor: IVditor, event: KeyboardEvent, range: Range) => {
export const isHrMD = (text: string) => {
// - _ *
const marker = text.trimRight().split("\n").pop();
if (marker === "") {
return false;
}
if (marker.replace(/ |-/g, "") === ""
|| marker.replace(/ |_/g, "") === ""
|| marker.replace(/ |\*/g, "") === "") {
if (marker.replace(/ /g, "").length > 2) {
if (marker.indexOf("-") > -1 && marker.trimLeft().indexOf(" ") === -1
&& text.trimRight().split("\n").length > 1) {
// 满足 heading
return false;
}
if (marker.indexOf(" ") === 0 || marker.indexOf("\t") === 0) {
// 代码块
return false;
}
return true;
}
return false;
}
return false;
};

export const isHeadingMD = (text: string) => {
// - =
const textArray = text.trimRight().split("\n");
text = textArray.pop();

if (text.indexOf(" ") === 0 || text.indexOf("\t") === 0) {
return false;
}

text = text.trimLeft();
if (text === "" || textArray.length === 0) {
return false;
}
if (text.replace(/-/g, "") === ""
|| text.replace(/=/g, "") === "") {
return true;
}
return false;
};

export const isToC = (text: string) => {
return text.trim().toLowerCase() === "[toc]";
};

export const renderToc = (editorElement: HTMLPreElement) => {
const tocElement = editorElement.querySelector('[data-type="toc-block"]');
if (!tocElement) {
return;
}
let tocHTML = "";
Array.from(editorElement.children).forEach((item: HTMLElement) => {
if (item.tagName.indexOf("H") === 0 && item.tagName.length === 2 && item.textContent.trim() !== "") {
const space = new Array((parseInt(item.tagName.substring(1), 10) - 1) * 2).fill(" ").join("");
tocHTML += `${space}<span data-type="toc-h">${item.textContent.trim()}</span><br>`;
}
});
tocElement.innerHTML = tocHTML || "[ToC]";
};

export const execAfterRender = (vditor: IVditor) => {
if (vditor.currentMode === "wysiwyg") {
afterRenderEvent(vditor);
} else if (vditor.currentMode === "ir") {
processAfterRender(vditor);
}
};

export const fixList = (range: Range, vditor: IVditor, pElement: HTMLElement, event: KeyboardEvent) => {
const startContainer = range.startContainer;
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))) {
if (liElement && !liElement.textContent.endsWith("\n")) {
// li 结尾需 \n
liElement.insertAdjacentText("beforeend", "\n");
}
range.insertNode(document.createTextNode("\n"));
range.collapse(false);
execAfterRender(vditor);
event.preventDefault();
return true;
}

if (!isCtrl(event) && !event.shiftKey && !event.altKey && event.key === "Backspace" &&
!liElement.previousElementSibling && range.toString() === "" &&
getSelectPosition(liElement, range).start === 0) {
// 光标位于点和第一个字符中间时,无法删除 li 元素
if (liElement.nextElementSibling) {
liElement.parentElement.insertAdjacentHTML("beforebegin",
`<p data-block="0"><wbr>${liElement.innerHTML}</p>`);
liElement.remove();
} else {
liElement.parentElement.outerHTML = `<p data-block="0"><wbr>${liElement.innerHTML}</p>`;
}
setRangeByWbr(vditor[vditor.currentMode].element, range);
execAfterRender(vditor);
event.preventDefault();
return true;
}

if (!isCtrl(event) && !event.altKey && event.key === "Tab") {
// 光标位于第一/零字符时,tab 用于列表的缩进
let isFirst = false;
if (range.startOffset === 0
&& ((startContainer.nodeType === 3 && !startContainer.previousSibling)
|| (startContainer.nodeType !== 3 && startContainer.nodeName === "LI"))) {
// 有序/无序列表
isFirst = true;
} else if (liElement.classList.contains("vditor-task") && range.startOffset === 1
&& startContainer.previousSibling.nodeType !== 3
&& (startContainer.previousSibling as HTMLElement).tagName === "INPUT") {
// 任务列表
isFirst = true;
}

// TODO
if (isFirst) {
if (event.shiftKey) {
vditor.wysiwyg.popover.querySelector('button[data-type="outdent"]').dispatchEvent(new CustomEvent("click"));
} else {
vditor.wysiwyg.popover.querySelector('button[data-type="indent"]').dispatchEvent(new CustomEvent("click"));
}
event.preventDefault();
return true;
}
}
}
return false;
};

// tab 处理: block code render, table, 列表第一个字符中的 tab 处理单独写在上面
export const fixTab = (vditor: IVditor, range: Range, event: KeyboardEvent) => {
if (vditor.options.tab && event.key === "Tab") {
if (event.shiftKey) {
// TODO shift+tab
} else {
if (range.toString() === "") {
range.insertNode(document.createTextNode(vditor.options.tab));
range.collapse(false);
} else {
range.extractContents();
range.insertNode(document.createTextNode(vditor.options.tab));
range.collapse(false);
}
}
execAfterRender(vditor);
event.preventDefault();
return true;
}
};

export const fixMarkdown = (event: KeyboardEvent, vditor: IVditor, pElement: HTMLElement, range: Range) => {
if (!isCtrl(event) && !event.altKey && event.key === "Enter") {
const pText = String.raw`${pElement.textContent}`.replace(/\\\|/g, "").trim();
const pTextList = pText.split("|");
if (pText.startsWith("|") && pText.endsWith("|") && pTextList.length > 3) {
// table 自动完成
let tableHeaderMD = pTextList.map(() => "---").join("|");
tableHeaderMD =
pElement.textContent + tableHeaderMD.substring(3, tableHeaderMD.length - 3) + "\n|<wbr>";
pElement.outerHTML = vditor.lute.SpinVditorDOM(tableHeaderMD);
setRangeByWbr(vditor[vditor.currentMode].element, range);
execAfterRender(vditor);
scrollCenter(vditor[vditor.currentMode].element);
event.preventDefault();
return true;
}

// hr 渲染
if (isHrMD(pElement.innerHTML)) {
// 软换行后 hr 前有内容
let pInnerHTML = "";
const innerHTMLList = pElement.innerHTML.trimRight().split("\n");
if (innerHTMLList.length > 1) {
innerHTMLList.pop();
pInnerHTML = `<p data-block="0">${innerHTMLList.join("\n")}</p>`;
}

pElement.insertAdjacentHTML("afterend",
`${pInnerHTML}<hr data-block="0"><p data-block="0">\n<wbr></p>`);
pElement.remove();
setRangeByWbr(vditor[vditor.currentMode].element, range);
execAfterRender(vditor);
scrollCenter(vditor[vditor.currentMode].element);
event.preventDefault();
return true;
}

if (isHeadingMD(pElement.innerHTML)) {
// heading 渲染
pElement.outerHTML = vditor.lute.SpinVditorDOM(pElement.innerHTML + '<p data-block="0">\n<wbr></p>');
setRangeByWbr(vditor[vditor.currentMode].element, range);
execAfterRender(vditor);
scrollCenter(vditor[vditor.currentMode].element);
event.preventDefault();
return true;
}
}

// 软换行会被切割 https://github.com/Vanessa219/vditor/issues/220
if (pElement.previousElementSibling && event.key === "Backspace" && !isCtrl(event) && !event.altKey &&
!event.shiftKey && pElement.textContent.trimRight().split("\n").length > 1 &&
getSelectPosition(pElement, range).start === 0) {
const lastElement = getLastNode(pElement.previousElementSibling) as HTMLElement;
if (!lastElement.textContent.endsWith("\n")) {
lastElement.textContent = lastElement.textContent + "\n";
}
lastElement.parentElement.insertAdjacentHTML("beforeend", `<wbr>${pElement.innerHTML}`);
pElement.remove();
setRangeByWbr(vditor[vditor.currentMode].element, range);
return false;
}
return false;
};

export const fixTable = (vditor: IVditor, event: KeyboardEvent, range: Range) => {
const startContainer = range.startContainer;
const cellElement = hasClosestByMatchTag(startContainer, "TD") ||
hasClosestByMatchTag(startContainer, "TH");
Expand Down
70 changes: 0 additions & 70 deletions src/ts/util/processList.ts

This file was deleted.

Loading

0 comments on commit 5a1d7d3

Please sign in to comment.