mirror of
https://github.com/siyuan-note/siyuan.git
synced 2025-05-19 02:21:38 +08:00
This commit is contained in:
parent
0dd00d2138
commit
ad6fe1cd6e
@ -115,6 +115,15 @@
|
|||||||
min-height: 30px;
|
min-height: 30px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
|
||||||
|
.block__icon {
|
||||||
|
opacity: 1;
|
||||||
|
margin-left: 8px;
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
opacity: .38;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&__space {
|
&__space {
|
||||||
min-width: 8px;
|
min-width: 8px;
|
||||||
transition: var(--b3-transition);
|
transition: var(--b3-transition);
|
||||||
@ -153,7 +162,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&__icon {
|
&__icon {
|
||||||
margin-right: 8px;
|
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
border: 0;
|
border: 0;
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
|
@ -503,7 +503,7 @@
|
|||||||
|
|
||||||
[data-node-id][fold="1"]:not(.li):not([data-type="NodeHeading"]) {
|
[data-node-id][fold="1"]:not(.li):not([data-type="NodeHeading"]) {
|
||||||
@include text-clamp(1);
|
@include text-clamp(1);
|
||||||
opacity: 0.54;
|
opacity: 0.38;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
height: 26px;
|
height: 26px;
|
||||||
line-height: 26px;
|
line-height: 26px;
|
||||||
|
@ -28,8 +28,9 @@ import {Menu} from "../../plugin/Menu";
|
|||||||
import {getNoContainerElement} from "../wysiwyg/getBlock";
|
import {getNoContainerElement} from "../wysiwyg/getBlock";
|
||||||
import {openTitleMenu} from "../header/openTitleMenu";
|
import {openTitleMenu} from "../header/openTitleMenu";
|
||||||
import {emitOpenMenu} from "../../plugin/EventBus";
|
import {emitOpenMenu} from "../../plugin/EventBus";
|
||||||
import {isInAndroid, isMac, updateHotkeyTip} from "../util/compatibility";
|
import {isInAndroid, isIPad, isMac, updateHotkeyTip} from "../util/compatibility";
|
||||||
import {resize} from "../util/resize";
|
import {resize} from "../util/resize";
|
||||||
|
import {listIndent, listOutdent} from "../wysiwyg/list";
|
||||||
|
|
||||||
export class Breadcrumb {
|
export class Breadcrumb {
|
||||||
public element: HTMLElement;
|
public element: HTMLElement;
|
||||||
@ -40,18 +41,25 @@ export class Breadcrumb {
|
|||||||
constructor(protyle: IProtyle) {
|
constructor(protyle: IProtyle) {
|
||||||
const element = document.createElement("div");
|
const element = document.createElement("div");
|
||||||
element.className = "protyle-breadcrumb";
|
element.className = "protyle-breadcrumb";
|
||||||
|
let padHTML = ""
|
||||||
|
/// #if BROWSER
|
||||||
|
if (isIPad() || isInAndroid()) {
|
||||||
|
padHTML = `<button class="block__icon fn__flex-center ariaLabel" disabled aria-label="${window.siyuan.languages.undo}" data-type="undo"><svg><use xlink:href="#iconUndo"></use></svg></button>
|
||||||
|
<button class="block__icon fn__flex-center ariaLabel" disabled aria-label="${window.siyuan.languages.redo}" data-type="redo"><svg><use xlink:href="#iconRedo"></use></svg></button>
|
||||||
|
<button class="block__icon fn__flex-center ariaLabel" disabled aria-label="${window.siyuan.languages.outdent}" data-type="outdent"><svg><use xlink:href="#iconOutdent"></use></svg></button>
|
||||||
|
<button class="block__icon fn__flex-center ariaLabel" disabled aria-label="${window.siyuan.languages.indent}" data-type="indent"><svg><use xlink:href="#iconIndent"></use></svg></button>`;
|
||||||
|
}
|
||||||
|
/// #endif
|
||||||
element.innerHTML = `${isMobile() ?
|
element.innerHTML = `${isMobile() ?
|
||||||
`<button class="protyle-breadcrumb__icon" data-type="mobile-menu">${window.siyuan.languages.breadcrumb}</button>` :
|
`<button class="protyle-breadcrumb__icon" data-type="mobile-menu">${window.siyuan.languages.breadcrumb}</button>` :
|
||||||
'<div class="protyle-breadcrumb__bar"></div>'}
|
'<div class="protyle-breadcrumb__bar"></div>'}
|
||||||
<span class="protyle-breadcrumb__space"></span>
|
<span class="protyle-breadcrumb__space"></span>
|
||||||
<button class="protyle-breadcrumb__icon fn__none ariaLabel" aria-label="${updateHotkeyTip(window.siyuan.config.keymap.editor.general.exitFocus.custom)}" data-type="exit-focus">${window.siyuan.languages.exitFocus}</button>
|
<button class="protyle-breadcrumb__icon fn__none ariaLabel" aria-label="${updateHotkeyTip(window.siyuan.config.keymap.editor.general.exitFocus.custom)}" data-type="exit-focus">${window.siyuan.languages.exitFocus}</button>
|
||||||
<button class="block__icon block__icon--show fn__flex-center ariaLabel${window.siyuan.config.readonly ? " fn__none" : ""}" aria-label="${window.siyuan.languages.lockEdit}" data-type="readonly"><svg><use xlink:href="#iconUnlock"></use></svg></button>
|
${padHTML}
|
||||||
<span class="fn__space${window.siyuan.config.readonly ? " fn__none" : ""}"></span>
|
<button class="block__icon fn__flex-center ariaLabel${window.siyuan.config.readonly ? " fn__none" : ""}" aria-label="${window.siyuan.languages.lockEdit}" data-type="readonly"><svg><use xlink:href="#iconUnlock"></use></svg></button>
|
||||||
<button class="block__icon block__icon--show fn__flex-center ariaLabel" data-type="doc" aria-label="${isMac() ? window.siyuan.languages.gutterTip2 : window.siyuan.languages.gutterTip2.replace("⇧", "Shift+")}"><svg><use xlink:href="#iconFile"></use></svg></button>
|
<button class="block__icon fn__flex-center ariaLabel" data-type="doc" aria-label="${isMac() ? window.siyuan.languages.gutterTip2 : window.siyuan.languages.gutterTip2.replace("⇧", "Shift+")}"><svg><use xlink:href="#iconFile"></use></svg></button>
|
||||||
<span class="fn__space"></span>
|
<button class="block__icon fn__flex-center ariaLabel" data-type="more" aria-label="${window.siyuan.languages.more}"><svg><use xlink:href="#iconMore"></use></svg></button>
|
||||||
<button class="block__icon block__icon--show fn__flex-center ariaLabel" data-type="more" aria-label="${window.siyuan.languages.more}"><svg><use xlink:href="#iconMore"></use></svg></button>
|
<button class="block__icon fn__flex-center fn__none ariaLabel" data-type="context" aria-label="${window.siyuan.languages.context}"><svg><use xlink:href="#iconAlignCenter"></use></svg></button>`;
|
||||||
<button class="block__icon block__icon--show fn__flex-center fn__none ariaLabel" style="margin-left: 8px" data-type="context" aria-label="${window.siyuan.languages.context}"><svg><use xlink:href="#iconAlignCenter"></use></svg></button>`;
|
|
||||||
|
|
||||||
this.element = element.firstElementChild as HTMLElement;
|
this.element = element.firstElementChild as HTMLElement;
|
||||||
element.addEventListener("click", (event) => {
|
element.addEventListener("click", (event) => {
|
||||||
/// #if !MOBILE
|
/// #if !MOBILE
|
||||||
@ -133,6 +141,36 @@ export class Breadcrumb {
|
|||||||
target.classList.add("block__icon--active");
|
target.classList.add("block__icon--active");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
} else if (type === "undo") {
|
||||||
|
protyle.undo.undo(protyle);
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
break;
|
||||||
|
} else if (type === "redo") {
|
||||||
|
protyle.undo.redo(protyle);
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
break;
|
||||||
|
} else if (type === "outdent") {
|
||||||
|
if (protyle.toolbar.range) {
|
||||||
|
const blockElement = hasClosestBlock(protyle.toolbar.range.startContainer);
|
||||||
|
if (blockElement) {
|
||||||
|
listOutdent(protyle, [blockElement.parentElement], protyle.toolbar.range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
break;
|
||||||
|
} else if (type === "indent") {
|
||||||
|
if (protyle.toolbar.range) {
|
||||||
|
const blockElement = hasClosestBlock(protyle.toolbar.range.startContainer);
|
||||||
|
if (blockElement) {
|
||||||
|
listIndent(protyle, [blockElement.parentElement], protyle.toolbar.range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
target = target.parentElement;
|
target = target.parentElement;
|
||||||
}
|
}
|
||||||
@ -528,9 +566,7 @@ export class Breadcrumb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public render(protyle: IProtyle, update = false) {
|
public render(protyle: IProtyle, update = false) {
|
||||||
if (isMobile()) {
|
/// #if !MOBILE
|
||||||
return;
|
|
||||||
}
|
|
||||||
let range: Range;
|
let range: Range;
|
||||||
let blockElement: Element;
|
let blockElement: Element;
|
||||||
if (getSelection().rangeCount > 0) {
|
if (getSelection().rangeCount > 0) {
|
||||||
@ -614,6 +650,7 @@ export class Breadcrumb {
|
|||||||
this.element.scrollLeft = (this.element.lastElementChild as HTMLElement).offsetLeft - this.element.clientWidth + 14;
|
this.element.scrollLeft = (this.element.lastElementChild as HTMLElement).offsetLeft - this.element.clientWidth + 14;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
/// #endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public hide() {
|
public hide() {
|
||||||
|
@ -442,7 +442,7 @@ export class Gutter {
|
|||||||
}], [{
|
}], [{
|
||||||
action: "foldHeading",
|
action: "foldHeading",
|
||||||
id: itemId
|
id: itemId
|
||||||
}]);
|
}], options.protyle);
|
||||||
item.insertAdjacentHTML("afterend", response.data[0].doOperations[0].retData);
|
item.insertAdjacentHTML("afterend", response.data[0].doOperations[0].retData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import {Constants} from "../../constants";
|
|||||||
import {hideElements} from "../ui/hideElements";
|
import {hideElements} from "../ui/hideElements";
|
||||||
import {scrollCenter} from "../../util/highlightById";
|
import {scrollCenter} from "../../util/highlightById";
|
||||||
import {matchHotKey} from "../util/hotKey";
|
import {matchHotKey} from "../util/hotKey";
|
||||||
import { ipcRenderer } from "electron";
|
import {ipcRenderer} from "electron";
|
||||||
|
|
||||||
interface IOperations {
|
interface IOperations {
|
||||||
doOperations: IOperation[],
|
doOperations: IOperation[],
|
||||||
@ -32,9 +32,17 @@ export class Undo {
|
|||||||
this.render(protyle, state, false);
|
this.render(protyle, state, false);
|
||||||
this.hasUndo = true;
|
this.hasUndo = true;
|
||||||
this.redoStack.push(state);
|
this.redoStack.push(state);
|
||||||
|
if (protyle.breadcrumb) {
|
||||||
|
const undoElement = protyle.breadcrumb.element.parentElement.querySelector('[data-type="undo"]')
|
||||||
|
if (undoElement) {
|
||||||
|
if (this.undoStack.length === 0) {
|
||||||
|
undoElement.setAttribute("disabled", "true");
|
||||||
|
}
|
||||||
|
protyle.breadcrumb.element.parentElement.querySelector('[data-type="redo"]').removeAttribute("disabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public redo(protyle: IProtyle) {
|
public redo(protyle: IProtyle) {
|
||||||
if (protyle.disabled) {
|
if (protyle.disabled) {
|
||||||
return;
|
return;
|
||||||
@ -45,6 +53,15 @@ export class Undo {
|
|||||||
const state = this.redoStack.pop();
|
const state = this.redoStack.pop();
|
||||||
this.render(protyle, state, true);
|
this.render(protyle, state, true);
|
||||||
this.undoStack.push(state);
|
this.undoStack.push(state);
|
||||||
|
if (protyle.breadcrumb) {
|
||||||
|
const redoElement = protyle.breadcrumb.element.parentElement.querySelector('[data-type="redo"]')
|
||||||
|
if (redoElement) {
|
||||||
|
protyle.breadcrumb.element.parentElement.querySelector('[data-type="undo"]').removeAttribute("disabled");
|
||||||
|
if (this.redoStack.length === 0) {
|
||||||
|
redoElement.setAttribute("disabled", "true");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private render(protyle: IProtyle, state: IOperations, redo: boolean) {
|
private render(protyle: IProtyle, state: IOperations, redo: boolean) {
|
||||||
@ -52,7 +69,7 @@ export class Undo {
|
|||||||
protyle.wysiwyg.lastHTMLs = {};
|
protyle.wysiwyg.lastHTMLs = {};
|
||||||
if (!redo) {
|
if (!redo) {
|
||||||
state.undoOperations.forEach(item => {
|
state.undoOperations.forEach(item => {
|
||||||
onTransaction(protyle, item, true);
|
onTransaction(protyle, item, true);
|
||||||
});
|
});
|
||||||
transaction(protyle, state.undoOperations);
|
transaction(protyle, state.undoOperations);
|
||||||
} else {
|
} else {
|
||||||
@ -65,19 +82,25 @@ export class Undo {
|
|||||||
scrollCenter(protyle);
|
scrollCenter(protyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public replace(doOperations: IOperation[]) {
|
public replace(doOperations: IOperation[], protyle: IProtyle) {
|
||||||
// undo 引发 replace 导致 stack 错误 https://github.com/siyuan-note/siyuan/issues/9178
|
// undo 引发 replace 导致 stack 错误 https://github.com/siyuan-note/siyuan/issues/9178
|
||||||
if (this.hasUndo && this.redoStack.length > 0) {
|
if (this.hasUndo && this.redoStack.length > 0) {
|
||||||
this.undoStack.push(this.redoStack.pop());
|
this.undoStack.push(this.redoStack.pop());
|
||||||
this.redoStack = [];
|
this.redoStack = [];
|
||||||
this.hasUndo = false;
|
this.hasUndo = false;
|
||||||
|
if (protyle.breadcrumb) {
|
||||||
|
const redoElement = protyle.breadcrumb.element.parentElement.querySelector('[data-type="redo"]')
|
||||||
|
if (redoElement) {
|
||||||
|
redoElement.setAttribute("disabled", "true");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (this.undoStack.length > 0) {
|
if (this.undoStack.length > 0) {
|
||||||
this.undoStack[this.undoStack.length - 1].doOperations = doOperations;
|
this.undoStack[this.undoStack.length - 1].doOperations = doOperations;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public add( doOperations: IOperation[], undoOperations: IOperation[]) {
|
public add(doOperations: IOperation[], undoOperations: IOperation[], protyle: IProtyle) {
|
||||||
this.undoStack.push({undoOperations, doOperations});
|
this.undoStack.push({undoOperations, doOperations});
|
||||||
if (this.undoStack.length > Constants.SIZE_UNDO) {
|
if (this.undoStack.length > Constants.SIZE_UNDO) {
|
||||||
this.undoStack.shift();
|
this.undoStack.shift();
|
||||||
@ -86,6 +109,12 @@ export class Undo {
|
|||||||
this.redoStack = [];
|
this.redoStack = [];
|
||||||
this.hasUndo = false;
|
this.hasUndo = false;
|
||||||
}
|
}
|
||||||
|
if (protyle.breadcrumb) {
|
||||||
|
const undoElement = protyle.breadcrumb.element.parentElement.querySelector('[data-type="undo"]')
|
||||||
|
if (undoElement) {
|
||||||
|
undoElement.removeAttribute("disabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public clear() {
|
public clear() {
|
||||||
|
@ -314,6 +314,13 @@ export const disabledProtyle = (protyle: IProtyle) => {
|
|||||||
if (protyle.breadcrumb) {
|
if (protyle.breadcrumb) {
|
||||||
protyle.breadcrumb.element.parentElement.querySelector('[data-type="readonly"] use').setAttribute("xlink:href", "#iconLock");
|
protyle.breadcrumb.element.parentElement.querySelector('[data-type="readonly"] use').setAttribute("xlink:href", "#iconLock");
|
||||||
protyle.breadcrumb.element.parentElement.querySelector('[data-type="readonly"]').setAttribute("aria-label", window.siyuan.config.editor.readOnly ? window.siyuan.languages.tempUnlock : window.siyuan.languages.unlockEdit);
|
protyle.breadcrumb.element.parentElement.querySelector('[data-type="readonly"]').setAttribute("aria-label", window.siyuan.config.editor.readOnly ? window.siyuan.languages.tempUnlock : window.siyuan.languages.unlockEdit);
|
||||||
|
const undoElement = protyle.breadcrumb.element.parentElement.querySelector('[data-type="undo"]')
|
||||||
|
if (undoElement && !undoElement.classList.contains("fn__none")) {
|
||||||
|
undoElement.classList.add("fn__none")
|
||||||
|
protyle.breadcrumb.element.parentElement.querySelector('[data-type="redo"]').classList.add("fn__none")
|
||||||
|
protyle.breadcrumb.element.parentElement.querySelector('[data-type="indent"]').classList.add("fn__none")
|
||||||
|
protyle.breadcrumb.element.parentElement.querySelector('[data-type="outdent"]').classList.add("fn__none")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
hideTooltip();
|
hideTooltip();
|
||||||
};
|
};
|
||||||
@ -357,6 +364,13 @@ export const enableProtyle = (protyle: IProtyle) => {
|
|||||||
if (protyle.breadcrumb) {
|
if (protyle.breadcrumb) {
|
||||||
protyle.breadcrumb.element.parentElement.querySelector('[data-type="readonly"] use').setAttribute("xlink:href", "#iconUnlock");
|
protyle.breadcrumb.element.parentElement.querySelector('[data-type="readonly"] use').setAttribute("xlink:href", "#iconUnlock");
|
||||||
protyle.breadcrumb.element.parentElement.querySelector('[data-type="readonly"]').setAttribute("aria-label", window.siyuan.config.editor.readOnly ? window.siyuan.languages.cancelTempUnlock : window.siyuan.languages.lockEdit);
|
protyle.breadcrumb.element.parentElement.querySelector('[data-type="readonly"]').setAttribute("aria-label", window.siyuan.config.editor.readOnly ? window.siyuan.languages.cancelTempUnlock : window.siyuan.languages.lockEdit);
|
||||||
|
const undoElement = protyle.breadcrumb.element.parentElement.querySelector('[data-type="undo"]')
|
||||||
|
if (undoElement && undoElement.classList.contains("fn__none")) {
|
||||||
|
undoElement.classList.remove("fn__none")
|
||||||
|
protyle.breadcrumb.element.parentElement.querySelector('[data-type="redo"]').classList.remove("fn__none")
|
||||||
|
protyle.breadcrumb.element.parentElement.querySelector('[data-type="indent"]').classList.remove("fn__none")
|
||||||
|
protyle.breadcrumb.element.parentElement.querySelector('[data-type="outdent"]').classList.remove("fn__none")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
hideTooltip();
|
hideTooltip();
|
||||||
};
|
};
|
||||||
|
@ -1823,6 +1823,19 @@ export class WYSIWYG {
|
|||||||
if (range.toString() === "") {
|
if (range.toString() === "") {
|
||||||
countSelectWord(range, protyle.block.rootID);
|
countSelectWord(range, protyle.block.rootID);
|
||||||
}
|
}
|
||||||
|
if (protyle.breadcrumb) {
|
||||||
|
const indentElement = protyle.breadcrumb.element.parentElement.querySelector('[data-type="indent"]')
|
||||||
|
if (indentElement) {
|
||||||
|
const outdentElement = protyle.breadcrumb.element.parentElement.querySelector('[data-type="outdent"]');
|
||||||
|
if (nodeElement.parentElement.classList.contains("li")) {
|
||||||
|
indentElement.removeAttribute("disabled");
|
||||||
|
outdentElement.removeAttribute("disabled");
|
||||||
|
} else {
|
||||||
|
indentElement.setAttribute("disabled", "true");
|
||||||
|
outdentElement.setAttribute("disabled", "true");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
}
|
}
|
||||||
@ -2351,6 +2364,20 @@ export class WYSIWYG {
|
|||||||
/// #if !MOBILE
|
/// #if !MOBILE
|
||||||
pushBack(protyle, newRange);
|
pushBack(protyle, newRange);
|
||||||
/// #endif
|
/// #endif
|
||||||
|
if (protyle.breadcrumb) {
|
||||||
|
const indentElement = protyle.breadcrumb.element.parentElement.querySelector('[data-type="indent"]')
|
||||||
|
const blockElement = hasClosestBlock(newRange.startContainer);
|
||||||
|
if (indentElement && blockElement) {
|
||||||
|
const outdentElement = protyle.breadcrumb.element.parentElement.querySelector('[data-type="outdent"]');
|
||||||
|
if (blockElement.parentElement.classList.contains("li")) {
|
||||||
|
indentElement.removeAttribute("disabled");
|
||||||
|
outdentElement.removeAttribute("disabled");
|
||||||
|
} else {
|
||||||
|
indentElement.setAttribute("disabled", "true");
|
||||||
|
outdentElement.setAttribute("disabled", "true");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}, (isMobile() || isInIOS()) ? 520 : 0); // Android/iPad 双击慢了出不来
|
}, (isMobile() || isInIOS()) ? 520 : 0); // Android/iPad 双击慢了出不来
|
||||||
protyle.hint.enableExtend = false;
|
protyle.hint.enableExtend = false;
|
||||||
if (event.shiftKey) {
|
if (event.shiftKey) {
|
||||||
|
@ -1027,9 +1027,9 @@ export const transaction = (protyle: IProtyle, doOperations: IOperation[], undoO
|
|||||||
protyle.updated = true;
|
protyle.updated = true;
|
||||||
|
|
||||||
if (needDebounce) {
|
if (needDebounce) {
|
||||||
protyle.undo.replace(doOperations);
|
protyle.undo.replace(doOperations, protyle);
|
||||||
} else {
|
} else {
|
||||||
protyle.undo.add(doOperations, undoOperations);
|
protyle.undo.add(doOperations, undoOperations, protyle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (needDebounce) {
|
if (needDebounce) {
|
||||||
|
Loading…
Reference in New Issue
Block a user