diff --git a/app/src/assets/scss/_protyle.scss b/app/src/assets/scss/_protyle.scss
index e016cdcce..5763328f6 100644
--- a/app/src/assets/scss/_protyle.scss
+++ b/app/src/assets/scss/_protyle.scss
@@ -5,12 +5,53 @@
.protyle-scroll {
position: absolute;
- right: -80px;
- top: 50%;
- transform: rotate(90deg);
+ right: 0;
+ height: 100%;
+ top: 0;
+ width: 24px;
+ svg {
+ height: 16px;
+ width: 16px;
+ }
- .b3-slider {
- width: 200px;
+ &__down,
+ &__up {
+ transition: var(--b3-transition);
+ position: absolute;
+ opacity: 0;
+ cursor: pointer;
+ color: var(--b3-border-color);
+
+ &:hover {
+ color: var(--b3-theme-on-surface);
+ }
+ }
+
+ &__up {
+ top: calc(50% - 114px);
+ }
+
+ &__down {
+ bottom: calc(50% - 135px);
+ }
+
+ &:hover {
+ .protyle-scroll__down,
+ .protyle-scroll__up {
+ opacity: 1;
+ }
+ }
+
+ &__bar {
+ position: absolute;
+ right: -89px;
+ top: 50%;
+ transform: rotate(90deg);
+ z-index: 1;
+
+ .b3-slider {
+ width: 200px;
+ }
}
}
@@ -110,6 +151,7 @@
flex-shrink: 0;
box-sizing: border-box;
min-height: 30px;
+ z-index: 1;
&__space {
flex: 1;
diff --git a/app/src/mobile/editor.ts b/app/src/mobile/editor.ts
index af5e077c7..2e5240406 100644
--- a/app/src/mobile/editor.ts
+++ b/app/src/mobile/editor.ts
@@ -59,6 +59,7 @@ export const openMobileFileById = (id: string, action = [Constants.CB_GET_HL]) =
blockId: id,
action,
render: {
+ scroll: true,
background: true,
gutter: true,
},
diff --git a/app/src/protyle/index.ts b/app/src/protyle/index.ts
index 9fd849d5e..a24efd788 100644
--- a/app/src/protyle/index.ts
+++ b/app/src/protyle/index.ts
@@ -72,7 +72,7 @@ export class Protyle {
this.protyle.undo = new Undo();
this.protyle.wysiwyg = new WYSIWYG(this.protyle);
this.protyle.toolbar = new Toolbar(this.protyle);
- this.protyle.scroll = new Scroll(this.protyle);
+ this.protyle.scroll = new Scroll(this.protyle); // 不能使用 render.scroll 来判读是否初始化,除非重构后面用到的相关变量
if (this.protyle.options.render.gutter) {
this.protyle.gutter = new Gutter(this.protyle);
}
diff --git a/app/src/protyle/scroll/index.ts b/app/src/protyle/scroll/index.ts
index 3c3539091..2e8674498 100644
--- a/app/src/protyle/scroll/index.ts
+++ b/app/src/protyle/scroll/index.ts
@@ -1,25 +1,37 @@
import {Constants} from "../../constants";
import {onGet} from "../util/onGet";
import {fetchPost} from "../../util/fetch";
+import {updateHotkeyTip} from "../util/compatibility";
+import {hasClosestByClassName} from "../util/hasClosest";
+import {goEnd, goHome} from "../wysiwyg/commonHotkey";
export class Scroll {
public element: HTMLElement;
+ private parentElement: HTMLElement;
private inputElement: HTMLInputElement;
public lastScrollTop: number;
public keepLazyLoad: boolean;
constructor(protyle: IProtyle) {
- const divElement = document.createElement("div");
- divElement.innerHTML = "";
- divElement.className = "fn__none protyle-scroll b3-tooltips b3-tooltips__s";
- divElement.setAttribute("aria-label", "Blocks 1/1");
- this.element = divElement;
- this.keepLazyLoad = false;
+ this.parentElement = document.createElement("div");
+ this.parentElement.classList.add("protyle-scroll");
+ this.parentElement.innerHTML = `
+
+
+
+
+
+
+
+
`
+
+ this.element = this.parentElement.querySelector(".protyle-scroll__bar");
+ this.keepLazyLoad = false;
if (!protyle.options.render.scroll) {
- this.element.classList.add("fn__none");
+ this.parentElement.classList.add("fn__none");
}
this.lastScrollTop = 0;
- this.inputElement = divElement.firstElementChild as HTMLInputElement;
+ this.inputElement = this.element.firstElementChild as HTMLInputElement;
this.inputElement.addEventListener("input", () => {
this.element.setAttribute("aria-label", `Blocks ${this.inputElement.value}/${protyle.block.blockCount}`);
});
@@ -31,13 +43,20 @@ export class Scroll {
this.setIndex(protyle);
});
/// #endif
- this.inputElement.addEventListener("click", () => {
- this.setIndex(protyle);
+ this.parentElement.addEventListener("click", (event) => {
+ const target = event.target as HTMLElement
+ if (hasClosestByClassName(target, "protyle-scroll__up")) {
+ goHome(protyle)
+ } else if (hasClosestByClassName(target, "protyle-scroll__down")) {
+ goEnd(protyle)
+ } else if (target.classList.contains("b3-slider")) {
+ this.setIndex(protyle);
+ }
});
}
private setIndex(protyle: IProtyle) {
- if (protyle.wysiwyg.element.getAttribute("data-top") || !protyle.model) {
+ if (protyle.wysiwyg.element.getAttribute("data-top")) {
return;
}
protyle.wysiwyg.element.setAttribute("data-top", protyle.wysiwyg.element.scrollTop.toString());
diff --git a/app/src/protyle/ui/initUI.ts b/app/src/protyle/ui/initUI.ts
index ef53a271a..25fb8aa30 100644
--- a/app/src/protyle/ui/initUI.ts
+++ b/app/src/protyle/ui/initUI.ts
@@ -28,8 +28,8 @@ export const initUI = (protyle: IProtyle) => {
if (protyle.upload) {
protyle.element.appendChild(protyle.upload.element);
}
- if (protyle.scroll) {
- protyle.element.appendChild(protyle.scroll.element);
+ if (protyle.options.render) {
+ protyle.element.appendChild(protyle.scroll.element.parentElement);
}
if (protyle.gutter) {
protyle.element.appendChild(protyle.gutter.element);
diff --git a/app/src/protyle/wysiwyg/commonHotkey.ts b/app/src/protyle/wysiwyg/commonHotkey.ts
index 02541f4b5..1b79b436a 100644
--- a/app/src/protyle/wysiwyg/commonHotkey.ts
+++ b/app/src/protyle/wysiwyg/commonHotkey.ts
@@ -19,6 +19,8 @@ import {hideElements} from "../ui/hideElements";
import {countBlockWord} from "../../layout/status";
import {scrollCenter} from "../../util/highlightById";
import {transaction} from "./transaction";
+import {onGet} from "../util/onGet";
+import {Constants} from "../../constants";
export const commonHotkey = (protyle: IProtyle, event: KeyboardEvent) => {
const target = event.target as HTMLElement;
@@ -215,3 +217,38 @@ export const duplicateBlock = (nodeElements: Element[], protyle: IProtyle) => {
focusBlock(focusElement);
scrollCenter(protyle);
};
+
+export const goHome = (protyle:IProtyle) => {
+ if (protyle.wysiwyg.element.firstElementChild.getAttribute("data-node-index") === "0" ||
+ protyle.wysiwyg.element.firstElementChild.getAttribute("data-eof") === "true" ||
+ protyle.options.backlinkData) {
+ focusBlock(protyle.wysiwyg.element.firstElementChild);
+ protyle.contentElement.scrollTop = 0;
+ protyle.scroll.lastScrollTop = 1;
+ } else {
+ fetchPost("/api/filetree/getDoc", {
+ id: protyle.block.rootID,
+ mode: 0,
+ size: window.siyuan.config.editor.dynamicLoadBlocks,
+ }, getResponse => {
+ onGet(getResponse, protyle, [Constants.CB_GET_FOCUS]);
+ });
+ }
+}
+
+export const goEnd = (protyle:IProtyle) => {
+ if (!protyle.scroll.element.classList.contains("fn__none") &&
+ protyle.wysiwyg.element.lastElementChild.getAttribute("data-eof") !== "true") {
+ fetchPost("/api/filetree/getDoc", {
+ id: protyle.block.rootID,
+ mode: 4,
+ size: window.siyuan.config.editor.dynamicLoadBlocks,
+ }, getResponse => {
+ onGet(getResponse, protyle, [Constants.CB_GET_FOCUS]);
+ });
+ } else {
+ protyle.contentElement.scrollTop = protyle.contentElement.scrollHeight;
+ protyle.scroll.lastScrollTop = protyle.contentElement.scrollTop;
+ focusBlock(protyle.wysiwyg.element.lastElementChild, undefined, false);
+ }
+}
diff --git a/app/src/protyle/wysiwyg/keydown.ts b/app/src/protyle/wysiwyg/keydown.ts
index eb98269a0..b3b42168e 100644
--- a/app/src/protyle/wysiwyg/keydown.ts
+++ b/app/src/protyle/wysiwyg/keydown.ts
@@ -42,14 +42,13 @@ import {isLocalPath} from "../../util/pathName";
/// #if !MOBILE
import {openBy, openFileById} from "../../editor/util";
/// #endif
-import {commonHotkey, downSelect, duplicateBlock, getStartEndElement, upSelect} from "./commonHotkey";
+import {commonHotkey, downSelect, duplicateBlock, getStartEndElement, goEnd, goHome, upSelect} from "./commonHotkey";
import {linkMenu, refMenu, setFold, zoomOut} from "../../menus/protyle";
import {removeEmbed} from "./removeEmbed";
import {openAttr} from "../../menus/commonMenuItem";
import {Constants} from "../../constants";
import {bindMenuKeydown} from "../../menus/Menu";
import {fetchPost} from "../../util/fetch";
-import {onGet} from "../util/onGet";
import {scrollCenter} from "../../util/highlightById";
import {BlockPanel} from "../../block/Panel";
import * as dayjs from "dayjs";
@@ -452,41 +451,14 @@ export const keydown = (protyle: IProtyle, editorElement: HTMLElement) => {
}
// ctrl+home 光标移动到顶
if (!event.altKey && !event.shiftKey && isCtrl(event) && event.key === "Home") {
- if (protyle.wysiwyg.element.firstElementChild.getAttribute("data-node-index") === "0" ||
- protyle.wysiwyg.element.firstElementChild.getAttribute("data-eof") === "true" ||
- protyle.options.backlinkData) {
- focusBlock(protyle.wysiwyg.element.firstElementChild);
- protyle.contentElement.scrollTop = 0;
- protyle.scroll.lastScrollTop = 1;
- } else {
- fetchPost("/api/filetree/getDoc", {
- id: protyle.block.rootID,
- mode: 0,
- size: window.siyuan.config.editor.dynamicLoadBlocks,
- }, getResponse => {
- onGet(getResponse, protyle, [Constants.CB_GET_FOCUS]);
- });
- }
+ goHome(protyle);
event.stopPropagation();
event.preventDefault();
return;
}
// ctrl+end 光标移动到尾
if (!event.altKey && !event.shiftKey && isCtrl(event) && event.key === "End") {
- if (!protyle.scroll.element.classList.contains("fn__none") &&
- protyle.wysiwyg.element.lastElementChild.getAttribute("data-eof") !== "true") {
- fetchPost("/api/filetree/getDoc", {
- id: protyle.block.rootID,
- mode: 4,
- size: window.siyuan.config.editor.dynamicLoadBlocks,
- }, getResponse => {
- onGet(getResponse, protyle, [Constants.CB_GET_FOCUS]);
- });
- } else {
- protyle.contentElement.scrollTop = protyle.contentElement.scrollHeight;
- protyle.scroll.lastScrollTop = protyle.contentElement.scrollTop;
- focusBlock(protyle.wysiwyg.element.lastElementChild, undefined, false);
- }
+ goEnd(protyle);
event.stopPropagation();
event.preventDefault();
return;
diff --git a/app/src/util/history.ts b/app/src/util/history.ts
index 50dde67b7..c5dfa77c3 100644
--- a/app/src/util/history.ts
+++ b/app/src/util/history.ts
@@ -311,7 +311,6 @@ export const openHistory = () => {
background: false,
title: false,
gutter: false,
- scroll: false,
breadcrumb: false,
breadcrumbDocName: false,
breadcrumbContext: false,