Vanessa 2022-09-15 22:22:33 +08:00
parent c259355f99
commit 06ff21f991
4 changed files with 77 additions and 53 deletions

View file

@ -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);

View file

@ -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;
}
}
};

View file

@ -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);
}
}
};

View file

@ -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);