Skip to content

Commit

Permalink
🎨 Vanessa219#27 task
Browse files Browse the repository at this point in the history
  • Loading branch information
Vanessa219 authored and stevapple committed Apr 8, 2020
1 parent c401e1d commit 403c889
Show file tree
Hide file tree
Showing 8 changed files with 141 additions and 122 deletions.
7 changes: 2 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,11 @@

* [open issues](https://github.com/Vanessa219/vditor/issues)

### v3.0.5 / undefined
### v3.0.5 / 2020-03-26

* [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) 支持直接传入元素进行初始化 `引入特性`

### v3.0.4 / 2020-03-25

* [232](https://github.com/Vanessa219/vditor/issues/232) 【IR&WYSIWYG】围栏代码块 info 部分自动完成 `引入特性`
* [230](https://github.com/Vanessa219/vditor/pull/230) 切换 IR 模式后依然展示工具栏 `改进功能`
* [27](https://github.com/Vanessa219/vditor/issues/27) 支持类似 Typora 的及时渲染模式 `引入特性`
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "vditor",
"version": "3.0.4",
"version": "3.0.5",
"description": "♏ 一款浏览器端的 Markdown 编辑器。",
"author": "Vanessa <v@b3log.org> (http://vanessa.b3log.org)",
"homepage": "https://hacpai.com/tag/vditor",
Expand Down
4 changes: 2 additions & 2 deletions src/js/lute/lute.min.js

Large diffs are not rendered by default.

8 changes: 7 additions & 1 deletion src/ts/ir/processKeydown.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {Constants} from "../constants";
import {isCtrl} from "../util/compatibility";
import {scrollCenter} from "../util/editorCommenEvent";
import {fixBlockquote, fixCodeBlock, fixList, fixMarkdown, fixTab, fixTable} from "../util/fixBrowserBehavior";
import {fixBlockquote, fixCodeBlock, fixList, fixMarkdown, fixTab, fixTable, fixTask} from "../util/fixBrowserBehavior";
import {hasClosestByAttribute, hasClosestByClassName, hasClosestByMatchTag} from "../util/hasClosest";
import {getSelectPosition, setRangeByWbr} from "../util/selection";

Expand Down Expand Up @@ -122,6 +122,12 @@ export const processKeydown = (vditor: IVditor, event: KeyboardEvent) => {
return true;
}

// task list
if (fixTask(vditor, range, event)) {
return true;
}

// tab
if (fixTab(vditor, range, event)) {
return true;
}
Expand Down
120 changes: 119 additions & 1 deletion src/ts/util/fixBrowserBehavior.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ import {highlightToolbar} from "../wysiwyg/highlightToolbar";
import {processCodeRender} from "../wysiwyg/processCodeRender";
import {isCtrl} from "./compatibility";
import {scrollCenter} from "./editorCommenEvent";
import {getTopList, hasClosestBlock, hasClosestByAttribute, hasClosestByMatchTag} from "./hasClosest";
import {
getTopList,
hasClosestBlock,
hasClosestByAttribute,
hasClosestByClassName,
hasClosestByMatchTag,
} from "./hasClosest";
import {getLastNode} from "./hasClosest";
import {matchHotKey} from "./hotKey";
import {getSelectPosition, setRangeByWbr} from "./selection";
Expand Down Expand Up @@ -740,3 +746,115 @@ export const fixBlockquote = (vditor: IVditor, range: Range, event: KeyboardEven
}
return false;
};

export const fixTask = (vditor: IVditor, range: Range, event: KeyboardEvent) => {
const startContainer = range.startContainer;
const taskItemElement = hasClosestByClassName(startContainer, "vditor-task");
if (taskItemElement) {
if (matchHotKey("⌘-⇧-J", event)) {
// ctrl + shift: toggle checked
const inputElement = taskItemElement.firstElementChild as HTMLInputElement;
if (inputElement.checked) {
inputElement.removeAttribute("checked");
} else {
inputElement.setAttribute("checked", "checked");
}
execAfterRender(vditor);
event.preventDefault();
return true;
}

// Backspace: 在选择框前进行删除
if (event.key === "Backspace" && !isCtrl(event) && !event.shiftKey && !event.altKey && range.toString() === ""
&& range.startOffset === 1
&& ((startContainer.nodeType === 3 && startContainer.previousSibling &&
(startContainer.previousSibling as HTMLElement).tagName === "INPUT")
|| startContainer.nodeType !== 3)) {
const previousElement = taskItemElement.previousElementSibling;
taskItemElement.querySelector("input").remove();
if (previousElement) {
const lastNode = getLastNode(previousElement);
lastNode.parentElement.insertAdjacentHTML("beforeend", "<wbr>" + taskItemElement.innerHTML.trim());
taskItemElement.remove();
} else {
taskItemElement.parentElement.insertAdjacentHTML("beforebegin",
`<p data-block="0"><wbr>${taskItemElement.innerHTML.trim() || "\n"}</p>`);
if (taskItemElement.nextElementSibling) {
taskItemElement.remove();
} else {
taskItemElement.parentElement.remove();
}
}
setRangeByWbr(vditor[vditor.currentMode].element, range);
execAfterRender(vditor);
event.preventDefault();
return true;
}

if (event.key === "Enter" && !isCtrl(event) && !event.shiftKey && !event.altKey) {
if (taskItemElement.textContent.trim() === "") {
// 当前任务列表无文字
if (hasClosestByClassName(taskItemElement.parentElement, "vditor-task")) {
// 为子元素时,需进行反向缩进
const topListElement = getTopList(startContainer);
if (topListElement) {
listOutdent(vditor, taskItemElement, range, topListElement);
}
} else {
// 仅有一级任务列表
if (taskItemElement.nextElementSibling) {
// 任务列表下方还有元素,需要使用用段落隔断
let afterHTML = "";
let beforeHTML = "";
let isAfter = false;
Array.from(taskItemElement.parentElement.children).forEach((taskItem) => {
if (taskItemElement.isEqualNode(taskItem)) {
isAfter = true;
} else {
if (isAfter) {
afterHTML += taskItem.outerHTML;
} else {
beforeHTML += taskItem.outerHTML;
}
}
});
const parentTagName = taskItemElement.parentElement.tagName;
const dataMarker = taskItemElement.parentElement.tagName === "OL" ? "" : ` data-marker="${taskItemElement.parentElement.getAttribute("data-marker")}"`;
let startAttribute = "";
if (beforeHTML) {
startAttribute = taskItemElement.parentElement.tagName === "UL" ? "" : ` start="1"`;
beforeHTML = `<${parentTagName} data-tight="true"${dataMarker} data-block="0">${beforeHTML}</${parentTagName}>`;
}
taskItemElement.parentElement.outerHTML = `${beforeHTML}<p data-block="0">\n<wbr></p><${parentTagName}
data-tight="true"${dataMarker} data-block="0"${startAttribute}>${afterHTML}</${parentTagName}>`;
} else {
// 任务列表下方无任务列表元素
taskItemElement.parentElement.insertAdjacentHTML("afterend", `<p data-block="0">\n<wbr></p>`);
if (taskItemElement.parentElement.querySelectorAll("li").length === 1) {
// 任务列表仅有一项时,使用 p 元素替换
taskItemElement.parentElement.remove();
} else {
// 任务列表有多项时,当前任务列表位于最后一项,移除该任务列表
taskItemElement.remove();
}
}
}
} else if (startContainer.nodeType !== 3 && range.startOffset === 0 &&
(startContainer.firstChild as HTMLElement).tagName === "INPUT") {
// 光标位于 input 之前
range.setStart(startContainer.childNodes[1], 1);
} else {
// 当前任务列表有文字,光标后的文字需添加到新任务列表中
range.setEndAfter(taskItemElement.lastChild);
taskItemElement.insertAdjacentHTML("afterend", `<li class="vditor-task" data-marker="${taskItemElement.getAttribute("data-marker")}"><input type="checkbox"> <wbr></li>`);
document.querySelector("wbr").after(range.extractContents());
}
setRangeByWbr(vditor[vditor.currentMode].element, range);
execAfterRender(vditor);
scrollCenter(vditor[vditor.currentMode].element);
event.preventDefault();
return true;
}
}
return false;
};
116 changes: 6 additions & 110 deletions src/ts/wysiwyg/processKeydown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@ import {
fixMarkdown,
fixTab,
fixTable,
listOutdent,
fixTask,
} from "../util/fixBrowserBehavior";
import {
getLastNode,
getTopList, hasClosestBlock, hasClosestByAttribute,
hasClosestBlock,
hasClosestByAttribute,
hasClosestByClassName,
hasClosestByMatchTag, hasClosestByTag,
hasTopClosestByTag,
} from "../util/hasClosest";
import {matchHotKey} from "../util/hotKey";
import {getSelectPosition, setRangeByWbr, setSelectionFocus} from "../util/selection";
import {getSelectPosition, setSelectionFocus} from "../util/selection";
import {afterRenderEvent} from "./afterRenderEvent";
import {nextIsCode} from "./inlineTag";
import {showCode} from "./processCodeRender";
Expand Down Expand Up @@ -171,112 +171,8 @@ export const processKeydown = (vditor: IVditor, event: KeyboardEvent) => {
}

// task list
const taskItemElement = hasClosestByClassName(startContainer, "vditor-task");
if (taskItemElement) {
if (matchHotKey("⌘-⇧-J", event)) {
// ctrl + shift: toggle checked
const inputElement = taskItemElement.firstElementChild as HTMLInputElement;
if (inputElement.checked) {
inputElement.removeAttribute("checked");
} else {
inputElement.setAttribute("checked", "checked");
}
afterRenderEvent(vditor);
event.preventDefault();
return true;
}

// Backspace: 在选择框前进行删除
if (event.key === "Backspace" && !isCtrl(event) && !event.shiftKey && !event.altKey && range.toString() === ""
&& range.startOffset === 1
&& ((startContainer.nodeType === 3 && startContainer.previousSibling &&
(startContainer.previousSibling as HTMLElement).tagName === "INPUT")
|| startContainer.nodeType !== 3)) {
const previousElement = taskItemElement.previousElementSibling;
taskItemElement.querySelector("input").remove();
if (previousElement) {
const lastNode = getLastNode(previousElement);
lastNode.parentElement.insertAdjacentHTML("beforeend", "<wbr>" + taskItemElement.innerHTML.trim());
taskItemElement.remove();
} else {
taskItemElement.parentElement.insertAdjacentHTML("beforebegin",
`<p data-block="0"><wbr>${taskItemElement.innerHTML.trim() || "\n"}</p>`);
if (taskItemElement.nextElementSibling) {
taskItemElement.remove();
} else {
taskItemElement.parentElement.remove();
}
}
setRangeByWbr(vditor.wysiwyg.element, range);
afterRenderEvent(vditor);
event.preventDefault();
return true;
}

if (event.key === "Enter" && !isCtrl(event) && !event.shiftKey && !event.altKey) {
if (taskItemElement.textContent.trim() === "") {
// 当前任务列表无文字
if (hasClosestByClassName(taskItemElement.parentElement, "vditor-task")) {
// 为子元素时,需进行反向缩进
const topListElement = getTopList(startContainer);
if (topListElement) {
listOutdent(vditor, taskItemElement, range, topListElement);
}
} else {
// 仅有一级任务列表
if (taskItemElement.nextElementSibling) {
// 任务列表下方还有元素,需要使用用段落隔断
let afterHTML = "";
let beforeHTML = "";
let isAfter = false;
Array.from(taskItemElement.parentElement.children).forEach((taskItem) => {
if (taskItemElement.isEqualNode(taskItem)) {
isAfter = true;
} else {
if (isAfter) {
afterHTML += taskItem.outerHTML;
} else {
beforeHTML += taskItem.outerHTML;
}
}
});
const parentTagName = taskItemElement.parentElement.tagName;
const dataMarker = taskItemElement.parentElement.tagName === "OL" ? "" : ` data-marker="${taskItemElement.parentElement.getAttribute("data-marker")}"`;
let startAttribute = "";
if (beforeHTML) {
startAttribute = taskItemElement.parentElement.tagName === "UL" ? "" : ` start="1"`;
beforeHTML = `<${parentTagName} data-tight="true"${dataMarker} data-block="0">${beforeHTML}</${parentTagName}>`;
}
taskItemElement.parentElement.outerHTML = `${beforeHTML}<p data-block="0">\n<wbr></p><${parentTagName}
data-tight="true"${dataMarker} data-block="0"${startAttribute}>${afterHTML}</${parentTagName}>`;
} else {
// 任务列表下方无任务列表元素
taskItemElement.parentElement.insertAdjacentHTML("afterend", `<p data-block="0">\n<wbr></p>`);
if (taskItemElement.parentElement.querySelectorAll("li").length === 1) {
// 任务列表仅有一项时,使用 p 元素替换
taskItemElement.parentElement.remove();
} else {
// 任务列表有多项时,当前任务列表位于最后一项,移除该任务列表
taskItemElement.remove();
}
}
}
} else if (startContainer.nodeType !== 3 && range.startOffset === 0 &&
(startContainer.firstChild as HTMLElement).tagName === "INPUT") {
// 光标位于 input 之前
range.setStart(startContainer.childNodes[1], 1);
} else {
// 当前任务列表有文字,光标后的文字需添加到新任务列表中
range.setEndAfter(taskItemElement.lastChild);
taskItemElement.insertAdjacentHTML("afterend", `<li class="vditor-task" data-marker="${taskItemElement.getAttribute("data-marker")}"><input type="checkbox"> <wbr></li>`);
document.querySelector("wbr").after(range.extractContents());
}
setRangeByWbr(vditor.wysiwyg.element, range);
afterRenderEvent(vditor);
scrollCenter(vditor.wysiwyg.element);
event.preventDefault();
return true;
}
if (fixTask(vditor, range, event)) {
return true;
}

// alt+enter
Expand Down
4 changes: 3 additions & 1 deletion src/ts/wysiwyg/toolbarEvent.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import {Constants} from "../constants";
import {setCurrentToolbar} from "../toolbar/setToolbar";
import {removeCurrentToolbar, setCurrentToolbar} from "../toolbar/setToolbar";
import {listToggle} from "../util/fixBrowserBehavior";
import {hasClosestBlock, hasClosestByAttribute, hasClosestByMatchTag} from "../util/hasClosest";
import {getEditorRange, setRangeByWbr, setSelectionFocus} from "../util/selection";
import {afterRenderEvent} from "./afterRenderEvent";
import {genAPopover, highlightToolbar} from "./highlightToolbar";
import {getNextHTML, getPreviousHTML, splitElement} from "./inlineTag";
import {processCodeRender} from "./processCodeRender";

const cancelBES = (range: Range, vditor: IVditor, commandName: string) => {
let element = range.startContainer.parentElement;
let jump = false;
Expand Down Expand Up @@ -166,6 +167,7 @@ export const toolbarEvent = (vditor: IVditor, actionBtn: Element) => {
listToggle(vditor, range, commandName, false);
setRangeByWbr(vditor.wysiwyg.element, range);
useHighlight = false;
removeCurrentToolbar(vditor.toolbar.elements, ["check", "list", "ordered-list"]);
actionBtn.classList.add("vditor-menu--current");
} else if (commandName === "inline-code") {
if (range.toString() === "") {
Expand Down

0 comments on commit 403c889

Please sign in to comment.