This commit is contained in:
parent
c259355f99
commit
06ff21f991
4 changed files with 77 additions and 53 deletions
|
@ -686,7 +686,7 @@ export const linkMenu = (protyle: IProtyle, linkElement: HTMLElement, focusText
|
|||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
if (linkElement.textContent === "" || linkElement.textContent === Constants.ZWSP) {
|
||||
removeLink(linkElement, protyle.toolbar.range)
|
||||
removeLink(linkElement, protyle.toolbar.range);
|
||||
} else {
|
||||
protyle.toolbar.range.selectNodeContents(linkElement);
|
||||
protyle.toolbar.range.collapse(false);
|
||||
|
@ -729,7 +729,7 @@ export const linkMenu = (protyle: IProtyle, linkElement: HTMLElement, focusText
|
|||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
if (!inputElement.value) {
|
||||
removeLink(linkElement, protyle.toolbar.range)
|
||||
removeLink(linkElement, protyle.toolbar.range);
|
||||
} else {
|
||||
protyle.toolbar.range.selectNodeContents(linkElement);
|
||||
protyle.toolbar.range.collapse(false);
|
||||
|
@ -769,7 +769,7 @@ export const linkMenu = (protyle: IProtyle, linkElement: HTMLElement, focusText
|
|||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
if (linkElement.textContent === "" || linkElement.textContent === Constants.ZWSP) {
|
||||
removeLink(linkElement, protyle.toolbar.range)
|
||||
removeLink(linkElement, protyle.toolbar.range);
|
||||
} else {
|
||||
protyle.toolbar.range.selectNodeContents(linkElement);
|
||||
protyle.toolbar.range.collapse(false);
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import {getEventName, updateHotkeyTip} from "../util/compatibility";
|
||||
import {ToolbarItem} from "./ToolbarItem";
|
||||
import {hasClosestBlock, hasClosestByMatchTag} from "../util/hasClosest";
|
||||
import {updateTransaction} from "../wysiwyg/transaction";
|
||||
import {setPosition} from "../../util/setPosition";
|
||||
import {getSelectionPosition, focusByRange} from "../util/selection";
|
||||
import {getSelectionPosition} from "../util/selection";
|
||||
import {Constants} from "../../constants";
|
||||
|
||||
export class Font extends ToolbarItem {
|
||||
|
@ -141,17 +139,17 @@ export const setFontStyle = (textElement:HTMLElement, textOption:ITextOption) =>
|
|||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const hasSameTextStyle = (currentElement: HTMLElement, sideElement: HTMLElement, textObj: ITextOption) => {
|
||||
if (!textObj) {
|
||||
return true;
|
||||
}
|
||||
let color = "";
|
||||
let webkitTextFillColor = ""
|
||||
let webkitTextStroke = ""
|
||||
let textShadow = ""
|
||||
let backgroundColor = ""
|
||||
let webkitTextFillColor = "";
|
||||
let webkitTextStroke = "";
|
||||
let textShadow = "";
|
||||
let backgroundColor = "";
|
||||
if (currentElement.nodeType !== 3) {
|
||||
color = currentElement.style.color;
|
||||
webkitTextFillColor = currentElement.style.webkitTextFillColor;
|
||||
|
@ -164,27 +162,27 @@ export const hasSameTextStyle = (currentElement: HTMLElement, sideElement: HTMLE
|
|||
webkitTextFillColor === sideElement.style.webkitTextFillColor &&
|
||||
webkitTextStroke === sideElement.style.webkitTextStroke &&
|
||||
textShadow === sideElement.style.textShadow &&
|
||||
backgroundColor === sideElement.style.backgroundColor
|
||||
backgroundColor === sideElement.style.backgroundColor;
|
||||
}
|
||||
if (textObj.type === "backgroundColor") {
|
||||
return color === sideElement.style.color &&
|
||||
webkitTextFillColor === sideElement.style.webkitTextFillColor &&
|
||||
webkitTextStroke === sideElement.style.webkitTextStroke &&
|
||||
textShadow === sideElement.style.textShadow &&
|
||||
textObj.color === sideElement.style.backgroundColor
|
||||
textObj.color === sideElement.style.backgroundColor;
|
||||
}
|
||||
if (textObj.type === "style2") {
|
||||
return color === sideElement.style.color &&
|
||||
"transparent" === sideElement.style.webkitTextFillColor &&
|
||||
"0.2px var(--b3-theme-on-background)" === sideElement.style.webkitTextStroke &&
|
||||
textShadow === sideElement.style.textShadow &&
|
||||
backgroundColor === sideElement.style.backgroundColor
|
||||
backgroundColor === sideElement.style.backgroundColor;
|
||||
}
|
||||
if (textObj.type === "style4") {
|
||||
return color === sideElement.style.color &&
|
||||
webkitTextFillColor === sideElement.style.webkitTextFillColor &&
|
||||
webkitTextStroke === sideElement.style.webkitTextStroke &&
|
||||
"1px 1px var(--b3-border-color), 2px 2px var(--b3-border-color), 3px 3px var(--b3-border-color), 4px 4px var(--b3-border-color)" === sideElement.style.textShadow &&
|
||||
backgroundColor === sideElement.style.backgroundColor
|
||||
backgroundColor === sideElement.style.backgroundColor;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -17,12 +17,12 @@ export class Link extends ToolbarItem {
|
|||
protyle.toolbar.element.classList.add("fn__none");
|
||||
event.stopPropagation();
|
||||
|
||||
const range = protyle.toolbar.range
|
||||
const range = protyle.toolbar.range;
|
||||
const nodeElement = hasClosestBlock(range.startContainer);
|
||||
if (!nodeElement) {
|
||||
return;
|
||||
}
|
||||
const aElement = hasClosestByAttribute(range.startContainer, "data-type", "a")
|
||||
const aElement = hasClosestByAttribute(range.startContainer, "data-type", "a");
|
||||
if (aElement) {
|
||||
linkMenu(protyle, aElement);
|
||||
return;
|
||||
|
@ -38,9 +38,9 @@ export class Link extends ToolbarItem {
|
|||
range.insertNode(wbrElement);
|
||||
const html = nodeElement.outerHTML;
|
||||
|
||||
const newElement = document.createElement("span")
|
||||
newElement.setAttribute("data-type", "a")
|
||||
const rangeString = range.toString()
|
||||
const newElement = document.createElement("span");
|
||||
newElement.setAttribute("data-type", "a");
|
||||
const rangeString = range.toString();
|
||||
newElement.textContent = rangeString;
|
||||
range.extractContents();
|
||||
range.insertNode(newElement);
|
||||
|
@ -73,9 +73,9 @@ export class Link extends ToolbarItem {
|
|||
}
|
||||
|
||||
export const removeLink = (linkElement: HTMLElement, range: Range) => {
|
||||
const types = linkElement.getAttribute("data-type").split(" ")
|
||||
const types = linkElement.getAttribute("data-type").split(" ");
|
||||
if (types.length === 1) {
|
||||
const linkParentElement = linkElement.parentElement
|
||||
const linkParentElement = linkElement.parentElement;
|
||||
linkElement.outerHTML = linkElement.innerHTML + "<wbr>";
|
||||
focusByWbr(linkParentElement, range);
|
||||
} else {
|
||||
|
@ -86,9 +86,9 @@ export const removeLink = (linkElement: HTMLElement, range: Range) => {
|
|||
}
|
||||
});
|
||||
linkElement.setAttribute("data-type", types.join(" "));
|
||||
linkElement.removeAttribute("data-href")
|
||||
linkElement.removeAttribute("data-href");
|
||||
range.selectNodeContents(linkElement);
|
||||
range.collapse(false);
|
||||
focusByRange(range);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -23,7 +23,7 @@ import {highlightRender} from "../markdown/highlightRender";
|
|||
import {getContenteditableElement, hasNextSibling, hasPreviousSibling} from "../wysiwyg/getBlock";
|
||||
import {processRender} from "../util/processCode";
|
||||
import {BlockRef} from "./BlockRef";
|
||||
import {hintMoveBlock, hintRef, hintRenderAssets, hintRenderTemplate, hintRenderWidget} from "../hint/extend";
|
||||
import {hintMoveBlock, hintRenderAssets, hintRenderTemplate, hintRenderWidget} from "../hint/extend";
|
||||
import {blockRender} from "../markdown/blockRender";
|
||||
/// #if !BROWSER
|
||||
import {clipboard, nativeImage, NativeImage} from "electron";
|
||||
|
@ -37,7 +37,6 @@ import {matchHotKey} from "../util/hotKey";
|
|||
import {unicode2Emoji} from "../../emoji";
|
||||
import {escapeHtml} from "../../util/escape";
|
||||
import {hideElements} from "../ui/hideElements";
|
||||
import {linkMenu} from "../../menus/protyle";
|
||||
import {renderAssetsPreview} from "../../asset/renderAssets";
|
||||
import {electronUndo} from "../undo";
|
||||
import {previewTemplate} from "./util";
|
||||
|
@ -145,7 +144,11 @@ export class Toolbar {
|
|||
return [];
|
||||
}
|
||||
if (!["DIV", "TD", "TH"].includes(startElement.tagName)) {
|
||||
types = (startElement.getAttribute("data-type") || "").split(" ");
|
||||
if (range.startContainer.textContent.length === range.startOffset && !hasNextSibling(range.startContainer)) {
|
||||
// 光标在 span 结尾不算 type,否则如在粗体后 ctrl+b 就无法继续使用粗体了
|
||||
} else {
|
||||
types = (startElement.getAttribute("data-type") || "").split(" ");
|
||||
}
|
||||
}
|
||||
let endElement = range.endContainer as HTMLElement;
|
||||
if (endElement.nodeType === 3) {
|
||||
|
@ -156,20 +159,20 @@ export class Toolbar {
|
|||
if (!endElement || endElement.nodeType === 3) {
|
||||
return [];
|
||||
}
|
||||
if (!["DIV", "TD", "TH"].includes(endElement.tagName)) {
|
||||
if (!["DIV", "TD", "TH"].includes(endElement.tagName) && !startElement.isSameNode(endElement)) {
|
||||
types = types.concat((endElement.getAttribute("data-type") || "").split(" "));
|
||||
}
|
||||
if (range.startOffset === range.startContainer.textContent.length) {
|
||||
const nextSibling = hasNextSibling(range.startContainer) as Element;
|
||||
if (nextSibling && nextSibling.nodeType !== 3) {
|
||||
types = types.concat((nextSibling.getAttribute("data-type") || "").split(" "));
|
||||
}
|
||||
} else if (range.endOffset === 0) {
|
||||
const previousSibling = hasPreviousSibling(range.startContainer) as Element;
|
||||
if (previousSibling && previousSibling.nodeType !== 3) {
|
||||
types = types.concat((previousSibling.getAttribute("data-type") || "").split(" "));
|
||||
}
|
||||
}
|
||||
// if (range.startOffset === range.startContainer.textContent.length) {
|
||||
// const nextSibling = hasNextSibling(range.startContainer) as Element;
|
||||
// if (nextSibling && nextSibling.nodeType !== 3) {
|
||||
// types = types.concat((nextSibling.getAttribute("data-type") || "").split(" "));
|
||||
// }
|
||||
// } else if (range.endOffset === 0) {
|
||||
// const previousSibling = hasPreviousSibling(range.startContainer) as Element;
|
||||
// if (previousSibling && previousSibling.nodeType !== 3) {
|
||||
// types = types.concat((previousSibling.getAttribute("data-type") || "").split(" "));
|
||||
// }
|
||||
// }
|
||||
range.cloneContents().childNodes.forEach((item: HTMLElement) => {
|
||||
if (item.nodeType !== 3) {
|
||||
types = types.concat(item.getAttribute("data-type").split(" "));
|
||||
|
@ -260,14 +263,6 @@ export class Toolbar {
|
|||
}
|
||||
const rangeTypes = this.getCurrentType();
|
||||
const selectText = this.range.toString();
|
||||
// 没选中时,相同 type 的文字中不进行操作
|
||||
if (selectText === "" && rangeTypes.includes(type) && this.range.startContainer.nodeType === 3) {
|
||||
const currentNode = hasNextSibling(this.range.startContainer) as Element;
|
||||
if (this.range.startOffset !== 0 && this.range.startContainer.parentElement.tagName === "SPAN" &&
|
||||
(currentNode || (!currentNode && this.range.startOffset < this.range.startContainer.textContent.length))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
let previousElement: HTMLElement;
|
||||
let nextElement: HTMLElement;
|
||||
let previousIndex: number;
|
||||
|
@ -303,14 +298,29 @@ export class Toolbar {
|
|||
this.mergeNode(contents.childNodes);
|
||||
const actionBtn = action === "toolbar" ? this.element.querySelector(`[data-type="${type}"]`) : undefined;
|
||||
let newNodes: Node[] = [];
|
||||
if (selectText !== "" && (
|
||||
actionBtn?.classList.contains("protyle-toolbar__item--current") ||
|
||||
(action === "range" && rangeTypes.length > 0 && rangeTypes.includes(type) && (!textObj || textObj.type === "remove"))
|
||||
if (actionBtn?.classList.contains("protyle-toolbar__item--current") || (
|
||||
action === "range" && rangeTypes.length > 0 && rangeTypes.includes(type) && (!textObj || textObj.type === "remove")
|
||||
)) {
|
||||
// 移除
|
||||
if (actionBtn) {
|
||||
actionBtn.classList.remove("protyle-toolbar__item--current");
|
||||
}
|
||||
if (contents.childNodes.length === 0) {
|
||||
rangeTypes.find((itemType, index) => {
|
||||
if (type === itemType) {
|
||||
rangeTypes.splice(index, 1);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if (rangeTypes.length === 0) {
|
||||
newNodes.push(document.createTextNode(Constants.ZWSP));
|
||||
} else {
|
||||
const inlineElement = document.createElement("span");
|
||||
inlineElement.setAttribute("data-type", rangeTypes.join(" "));
|
||||
inlineElement.textContent = Constants.ZWSP;
|
||||
newNodes.push(inlineElement);
|
||||
}
|
||||
}
|
||||
contents.childNodes.forEach((item: HTMLElement, index) => {
|
||||
if (item.nodeType !== 3) {
|
||||
const types = item.getAttribute("data-type").split(" ");
|
||||
|
@ -356,9 +366,10 @@ export class Toolbar {
|
|||
}
|
||||
if (selectText === "") {
|
||||
const inlineElement = document.createElement("span");
|
||||
inlineElement.setAttribute("data-type", type);
|
||||
rangeTypes.push(type)
|
||||
inlineElement.setAttribute("data-type", [...new Set(rangeTypes)].join(" "));
|
||||
inlineElement.textContent = Constants.ZWSP;
|
||||
newNodes = [inlineElement];
|
||||
newNodes.push(inlineElement);
|
||||
} else {
|
||||
contents.childNodes.forEach((item: HTMLElement, index) => {
|
||||
if (item.nodeType === 3) {
|
||||
|
@ -402,6 +413,21 @@ export class Toolbar {
|
|||
});
|
||||
}
|
||||
}
|
||||
if (this.range.startContainer.nodeType !== 3 && (this.range.startContainer as HTMLElement).tagName === "SPAN" &&
|
||||
this.range.startContainer.isSameNode(this.range.endContainer)) {
|
||||
// 切割元素
|
||||
const startContainer = this.range.startContainer as HTMLElement;
|
||||
const afterElement = document.createElement("span");
|
||||
const dataset = startContainer.dataset;
|
||||
Object.keys(dataset).forEach(key => {
|
||||
afterElement.setAttribute("data-" + key, dataset[key]);
|
||||
});
|
||||
this.range.setEnd(startContainer.lastChild, startContainer.lastChild.textContent.length);
|
||||
afterElement.append(this.range.extractContents());
|
||||
startContainer.after(afterElement);
|
||||
this.range.setStartBefore(afterElement);
|
||||
this.range.collapse(true);
|
||||
}
|
||||
newNodes.forEach((item) => {
|
||||
this.range.insertNode(item);
|
||||
this.range.collapse(false);
|
||||
|
|
Loading…
Add table
Reference in a new issue