This commit is contained in:
Vanessa 2022-09-15 11:57:33 +08:00
parent 01af1ca85f
commit 8af738ab06
9 changed files with 195 additions and 114 deletions

View file

@ -203,7 +203,7 @@
transition: var(--b3-transition);
}
span[data-type="a"] {
span[data-type~="a"] {
color: var(--b3-protyle-inline-link-color);
cursor: pointer;
transition: var(--b3-transition);

View file

@ -25,7 +25,7 @@ export const initBlockPopover = () => {
tip += " " + title;
}
}
if (tip && !tip.startsWith("siyuan://blocks")) {
if (tip && !tip.startsWith("siyuan://blocks") && !aElement.classList.contains("b3-tooltips")) {
showTooltip(tip, aElement);
event.stopPropagation();
return;
@ -141,7 +141,7 @@ export const initBlockPopover = () => {
});
ids = postResponse.data;
}
} else if (popoverTargetElement.getAttribute("data-type") === "a") {
} else if (popoverTargetElement.getAttribute("data-type").split(" ").includes("a")) {
// 以思源协议开头的链接
ids = [popoverTargetElement.getAttribute("data-href").substr(16, 22)];
} else {

View file

@ -41,6 +41,7 @@ import {hasNextSibling} from "../protyle/wysiwyg/getBlock";
import {electronUndo} from "../protyle/undo";
import {pushBack} from "../mobile/util/MobileBackFoward";
import {exportAsset} from "./util";
import {removeLink} from "../protyle/toolbar/Link";
export const refMenu = (protyle: IProtyle, element: HTMLElement) => {
const nodeElement = hasClosestBlock(element);
@ -685,7 +686,7 @@ export const linkMenu = (protyle: IProtyle, linkElement: HTMLElement, focusText
event.preventDefault();
event.stopPropagation();
if (linkElement.textContent === "" || linkElement.textContent === Constants.ZWSP) {
protyle.toolbar.setInlineMark(protyle, "link", "remove");
removeLink(linkElement, protyle.toolbar.range)
} else {
protyle.toolbar.range.selectNodeContents(linkElement);
protyle.toolbar.range.collapse(false);
@ -728,7 +729,7 @@ export const linkMenu = (protyle: IProtyle, linkElement: HTMLElement, focusText
event.preventDefault();
event.stopPropagation();
if (!inputElement.value) {
protyle.toolbar.setInlineMark(protyle, "link", "remove");
removeLink(linkElement, protyle.toolbar.range)
} else {
protyle.toolbar.range.selectNodeContents(linkElement);
protyle.toolbar.range.collapse(false);
@ -768,7 +769,7 @@ export const linkMenu = (protyle: IProtyle, linkElement: HTMLElement, focusText
event.preventDefault();
event.stopPropagation();
if (linkElement.textContent === "" || linkElement.textContent === Constants.ZWSP) {
protyle.toolbar.setInlineMark(protyle, "link", "remove");
removeLink(linkElement, protyle.toolbar.range)
} else {
protyle.toolbar.range.selectNodeContents(linkElement);
protyle.toolbar.range.collapse(false);
@ -813,7 +814,7 @@ export const linkMenu = (protyle: IProtyle, linkElement: HTMLElement, focusText
label: `${window.siyuan.languages.turnInto} <b>${window.siyuan.languages.text}</b>`,
icon: "iconRefresh",
click() {
protyle.toolbar.setInlineMark(protyle, "link", "remove");
removeLink(linkElement, protyle.toolbar.range);
}
}).element);
if (linkAddress?.startsWith("assets/")) {

View file

@ -109,7 +109,7 @@ export const hintSlash = (key: string, protyle: IProtyle) => {
value: "emoji",
html: `<div class="b3-list-item__first"><svg class="b3-list-item__graphic"><use xlink:href="#iconEmoji"></use></svg><span class="b3-list-item__text">${window.siyuan.languages.emoji}</span><span class="b3-menu__accelerator">:</span></div>`,
}, {
filter: ["链接", "lianjie", "lj", "link"],
filter: ["链接", "lianjie", "lj", "link", "a"],
value: "a",
html: `<div class="b3-list-item__first"><svg class="b3-list-item__graphic"><use xlink:href="#iconLink"></use></svg><span class="b3-list-item__text">${window.siyuan.languages.link}</span><span class="b3-menu__accelerator">${updateHotkeyTip((window.siyuan.config.keymap.editor.insert.link.custom))}</span></div>`,
}, {

View file

@ -528,7 +528,8 @@ ${unicode2Emoji(emoji.unicode, true)}</button>`;
range.deleteContents();
focusByRange(range);
protyle.toolbar.range = range;
protyle.toolbar.setInlineMark(protyle, value, "add");
// TODO
// protyle.toolbar.setInlineMark(protyle, value, "hint");
return;
} else if (value === "emoji") {
range.deleteContents();

View file

@ -1,4 +1,11 @@
import {ToolbarItem} from "./ToolbarItem";
import {linkMenu} from "../../menus/protyle";
import {Constants} from "../../constants";
import * as dayjs from "dayjs";
import {updateTransaction} from "../wysiwyg/transaction";
import {hasClosestBlock, hasClosestByAttribute} from "../util/hasClosest";
import {hasNextSibling, hasPreviousSibling} from "../wysiwyg/getBlock";
import {focusByRange, focusByWbr} from "../util/selection";
export class Link extends ToolbarItem {
public element: HTMLElement;
@ -6,10 +13,82 @@ export class Link extends ToolbarItem {
constructor(protyle: IProtyle, menuItem: IMenuItem) {
super(protyle, menuItem);
// 不能用 getEventName否则会导致光标位置变动到点击的文档中
this.element.addEventListener("click", (event: MouseEvent & { changedTouches: MouseEvent[] }) => {
protyle.toolbar.setInlineMark(protyle, "link", "add");
this.element.addEventListener("click", async (event: MouseEvent & { changedTouches: MouseEvent[] }) => {
protyle.toolbar.element.classList.add("fn__none");
event.stopPropagation();
const range = protyle.toolbar.range
const nodeElement = hasClosestBlock(range.startContainer);
if (!nodeElement) {
return;
}
const aElement = hasClosestByAttribute(range.startContainer, "data-type", "a")
if (aElement) {
linkMenu(protyle, aElement);
return;
}
if (!["DIV", "TD", "TH"].includes(range.startContainer.parentElement.tagName) && range.startOffset === 0 && !hasPreviousSibling(range.startContainer)) {
range.setStartBefore(range.startContainer.parentElement);
}
if (!["DIV", "TD", "TH"].includes(range.endContainer.parentElement.tagName) && range.endOffset === range.endContainer.textContent.length && !hasNextSibling(range.endContainer)) {
range.setEndAfter(range.endContainer.parentElement);
}
const wbrElement = document.createElement("wbr");
range.insertNode(wbrElement);
const html = nodeElement.outerHTML;
const newElement = document.createElement("span")
newElement.setAttribute("data-type", "a")
const rangeString = range.toString()
newElement.textContent = rangeString;
range.extractContents();
range.insertNode(newElement);
let needShowLink = true;
let focusText = false;
try {
const clipText = await navigator.clipboard.readText();
// 选中链接时需忽略剪切板内容 https://ld246.com/article/1643035329737
if (protyle.lute.IsValidLinkDest(rangeString.trim())) {
(newElement as HTMLElement).setAttribute("data-href", rangeString.trim());
needShowLink = false;
} else if (protyle.lute.IsValidLinkDest(clipText)) {
(newElement as HTMLElement).setAttribute("data-href", clipText);
if (newElement.textContent.replace(Constants.ZWSP, "") !== "") {
needShowLink = false;
}
focusText = true;
}
} catch (e) {
console.log(e);
}
if (needShowLink) {
linkMenu(protyle, newElement as HTMLElement, focusText);
}
nodeElement.setAttribute("updated", dayjs().format("YYYYMMDDHHmmss"));
updateTransaction(protyle, nodeElement.getAttribute("data-node-id"), nodeElement.outerHTML, html);
wbrElement.remove();
});
}
}
export const removeLink = (linkElement: HTMLElement, range: Range) => {
const types = linkElement.getAttribute("data-type").split(" ")
if (types.length === 1) {
const linkParentElement = linkElement.parentElement
linkElement.outerHTML = linkElement.innerHTML + "<wbr>";
focusByWbr(linkParentElement, range);
} else {
types.find((itemType, index) => {
if ("a" === itemType) {
types.splice(index, 1);
return true;
}
});
linkElement.setAttribute("data-type", types.join(" "));
linkElement.removeAttribute("data-href")
range.selectNodeContents(linkElement);
range.collapse(false);
focusByRange(range);
}
}

View file

@ -12,7 +12,7 @@ export class ToolbarItem {
this.element.setAttribute("data-type", menuItem.name);
this.element.setAttribute("aria-label", tip + hotkey);
this.element.innerHTML = `<svg><use xlink:href="#${menuItem.icon}"></use></svg>`;
if (menuItem.name === "text" || menuItem.name === "block-ref" || menuItem.name === "a") {
if (["text", "a", "block-ref"].includes(menuItem.name)) {
return;
}
this.element.addEventListener(getEventName(), (event) => {

View file

@ -126,7 +126,7 @@ export class Toolbar {
});
const types = this.getCurrentType();
types.forEach(item => {
if (item === "block-ref" || item === "text" || item === "file-annotation-ref") {
if (["a", "block-ref", "text", "file-annotation-ref"].includes(item)) {
return;
}
this.element.querySelector(`[data-type="${item}"]`).classList.add("protyle-toolbar__item--current");
@ -253,7 +253,7 @@ export class Toolbar {
}
}
public setInlineMark(protyle: IProtyle, type: string, action: "remove" | "add" | "range" | "toolbar", textObj?: ITextOption) {
public setInlineMark(protyle: IProtyle, type: string, action: "range" | "toolbar", textObj?: ITextOption) {
const nodeElement = hasClosestBlock(this.range.startContainer);
if (!nodeElement) {
return;
@ -294,7 +294,7 @@ export class Toolbar {
this.mergeNode(contents.childNodes);
const actionBtn = action === "toolbar" ? this.element.querySelector(`[data-type="${type}"]`) : undefined;
const newNodes: Node[] = [];
if (action === "remove" || actionBtn?.classList.contains("protyle-toolbar__item--current") ||
if (actionBtn?.classList.contains("protyle-toolbar__item--current") ||
(action === "range" && rangeTypes.length > 0 && rangeTypes.includes(type) && (!textObj || textObj.type === "remove"))) {
// 移除
if (actionBtn) {
@ -431,13 +431,13 @@ export class Toolbar {
return;
}
const types = this.getCurrentType();
if (action === "add" && types.length > 0 && types.includes(type) && !focusAdd) {
if (type === "link") {
this.element.classList.add("fn__none");
linkMenu(protyle, this.range.startContainer.parentElement);
}
return;
}
// if (action === "add" && types.length > 0 && types.includes(type) && !focusAdd) {
// if (type === "link") {
// this.element.classList.add("fn__none");
// linkMenu(protyle, this.range.startContainer.parentElement);
// }
// return;
// }
// 对已有字体样式的文字再次添加字体样式
// if (focusAdd && action === "add" && types.includes("text") && this.range.startContainer.nodeType === 3 &&
// this.range.startContainer.parentNode.isSameNode(this.range.endContainer.parentNode)) {
@ -492,11 +492,11 @@ export class Toolbar {
return;
}
}
if (types.length > 0 && types.includes("link") && action === "range") {
// 链接快捷键不应取消,应该显示链接信息
linkMenu(protyle, this.range.startContainer.parentElement);
return;
}
// if (types.length > 0 && types.includes("link") && action === "range") {
// // 链接快捷键不应取消,应该显示链接信息
// linkMenu(protyle, this.range.startContainer.parentElement);
// return;
// }
const wbrElement = document.createElement("wbr");
this.range.insertNode(wbrElement);
this.range.setStartAfter(wbrElement);
@ -540,22 +540,22 @@ export class Toolbar {
this.range.insertNode(textNode);
this.range.selectNodeContents(textNode);
} else {
newNodes.forEach((item, index) => {
this.range.insertNode(item);
if (index !== newNodes.length - 1) {
this.range.collapse(false);
} else {
this.range.setEnd(item, item.textContent.length);
}
});
if (newNodes.length > 0) {
this.range.setStart(newNodes[0], 0);
}
// newNodes.forEach((item, index) => {
// this.range.insertNode(item);
// if (index !== newNodes.length - 1) {
// this.range.collapse(false);
// } else {
// this.range.setEnd(item, item.textContent.length);
// }
// });
// if (newNodes.length > 0) {
// this.range.setStart(newNodes[0], 0);
// }
}
focusByRange(this.range);
this.element.querySelectorAll(".protyle-toolbar__item--current").forEach(item => {
item.classList.remove("protyle-toolbar__item--current");
});
// focusByRange(this.range);
// this.element.querySelectorAll(".protyle-toolbar__item--current").forEach(item => {
// item.classList.remove("protyle-toolbar__item--current");
// });
} else {
if (newNodes.length === 0) {
newNodes.push(document.createTextNode(Constants.ZWSP));
@ -565,41 +565,41 @@ export class Toolbar {
const refText = startText + selectContents.textContent + endText;
const refNode = document.createTextNode(refText);
switch (type) {
case "bold":
newElement = document.createElement("strong");
break;
case "underline":
newElement = document.createElement("u");
break;
case "italic":
newElement = document.createElement("em");
break;
case "strike":
newElement = document.createElement("s");
break;
case "inline-code":
newElement = document.createElement("code");
break;
case "mark":
newElement = document.createElement("mark");
break;
case "sup":
newElement = document.createElement("sup");
break;
case "sub":
newElement = document.createElement("sub");
break;
case "kbd":
newElement = document.createElement("kbd");
break;
case "tag":
newElement = document.createElement("span");
newElement.setAttribute("data-type", "tag");
break;
case "link":
newElement = document.createElement("span");
newElement.setAttribute("data-type", "a");
break;
// case "bold":
// newElement = document.createElement("strong");
// break;
// case "underline":
// newElement = document.createElement("u");
// break;
// case "italic":
// newElement = document.createElement("em");
// break;
// case "strike":
// newElement = document.createElement("s");
// break;
// case "inline-code":
// newElement = document.createElement("code");
// break;
// case "mark":
// newElement = document.createElement("mark");
// break;
// case "sup":
// newElement = document.createElement("sup");
// break;
// case "sub":
// newElement = document.createElement("sub");
// break;
// case "kbd":
// newElement = document.createElement("kbd");
// break;
// case "tag":
// newElement = document.createElement("span");
// newElement.setAttribute("data-type", "tag");
// break;
// case "link":
// newElement = document.createElement("span");
// newElement.setAttribute("data-type", "a");
// break;
// case "blockRef":
// if (refText === "") {
// wbrElement.remove();
@ -619,9 +619,9 @@ export class Toolbar {
mathRender(newElement);
break;
}
if (newElement) {
this.range.insertNode(newElement);
}
// if (newElement) {
// this.range.insertNode(newElement);
// }
if (type === "inline-math") {
this.range.setStartAfter(newElement);
this.range.collapse(true);
@ -653,40 +653,40 @@ export class Toolbar {
this.range.setEnd(newElement.lastChild, newElement.lastChild.textContent.length);
focusByRange(this.range);
}
if (type === "link") {
let needShowLink = true;
let focusText = false;
try {
const clipText = await navigator.clipboard.readText();
// 选中链接时需忽略剪切板内容 https://ld246.com/article/1643035329737
if (protyle.lute.IsValidLinkDest(this.range.toString().trim())) {
(newElement as HTMLElement).setAttribute("data-href", this.range.toString().trim());
needShowLink = false;
} else if (protyle.lute.IsValidLinkDest(clipText)) {
(newElement as HTMLElement).setAttribute("data-href", clipText);
if (newElement.textContent.replace(Constants.ZWSP, "") !== "") {
needShowLink = false;
}
focusText = true;
}
} catch (e) {
console.log(e);
}
if (needShowLink) {
linkMenu(protyle, newElement as HTMLElement, focusText);
}
}
}
if (actionBtn) {
this.element.querySelectorAll(".protyle-toolbar__item--current").forEach(item => {
item.classList.remove("protyle-toolbar__item--current");
});
actionBtn.classList.add("protyle-toolbar__item--current");
// if (type === "link") {
// let needShowLink = true;
// let focusText = false;
// try {
// const clipText = await navigator.clipboard.readText();
// // 选中链接时需忽略剪切板内容 https://ld246.com/article/1643035329737
// if (protyle.lute.IsValidLinkDest(this.range.toString().trim())) {
// (newElement as HTMLElement).setAttribute("data-href", this.range.toString().trim());
// needShowLink = false;
// } else if (protyle.lute.IsValidLinkDest(clipText)) {
// (newElement as HTMLElement).setAttribute("data-href", clipText);
// if (newElement.textContent.replace(Constants.ZWSP, "") !== "") {
// needShowLink = false;
// }
// focusText = true;
// }
// } catch (e) {
// console.log(e);
// }
// if (needShowLink) {
// linkMenu(protyle, newElement as HTMLElement, focusText);
// }
// }
}
// if (actionBtn) {
// this.element.querySelectorAll(".protyle-toolbar__item--current").forEach(item => {
// item.classList.remove("protyle-toolbar__item--current");
// });
// actionBtn.classList.add("protyle-toolbar__item--current");
// }
}
nodeElement.setAttribute("updated", dayjs().format("YYYYMMDDHHmmss"));
updateTransaction(protyle, nodeElement.getAttribute("data-node-id"), nodeElement.outerHTML, html);
wbrElement.remove();
// nodeElement.setAttribute("updated", dayjs().format("YYYYMMDDHHmmss"));
// updateTransaction(protyle, nodeElement.getAttribute("data-node-id"), nodeElement.outerHTML, html);
// wbrElement.remove();
}
public showFileAnnotationRef(protyle: IProtyle, refElement: HTMLElement) {

View file

@ -1185,8 +1185,8 @@ export const keydown = (protyle: IProtyle, editorElement: HTMLElement) => {
}
if (matchHotKey(menuItem.hotkey, event)) {
protyle.toolbar.range = getEditorRange(protyle.wysiwyg.element);
if (menuItem.name === "text" || menuItem.name === "block-ref") {
protyle.toolbar.element.querySelector(`[data-type="${menuItem.name}"]`).dispatchEvent(new CustomEvent(getEventName()));
if (["text", "a", "block-ref"].includes(menuItem.name)) {
protyle.toolbar.element.querySelector(`[data-type="${menuItem.name}"]`).dispatchEvent(new CustomEvent("block-ref" === menuItem.name ? getEventName() : "click"));
} else {
protyle.toolbar.setInlineMark(protyle, menuItem.name, "range");
}