diff --git a/app/src/card/newCardTab.ts b/app/src/card/newCardTab.ts index 24f75754a..1c034c09f 100644 --- a/app/src/card/newCardTab.ts +++ b/app/src/card/newCardTab.ts @@ -3,13 +3,15 @@ import {getInstanceById, getWndByLayout} from "../layout/util"; import {Tab} from "../layout/Tab"; import {Custom} from "../layout/dock/Custom"; import {Dialog} from "../dialog"; -import {genCardHTML} from "./openCard"; +import {bindCardEvent, genCardHTML} from "./openCard"; import {fetchPost} from "../util/fetch"; +import {Protyle} from "../protyle"; export const newCardTab = (options: { - type: TCardType, + cardType: TCardType, id: string, - dialog: Dialog + dialog: Dialog, + title?: string }) => { let wnd: Wnd; const element = document.querySelector(".layout__wnd--active"); @@ -19,6 +21,7 @@ export const newCardTab = (options: { if (!wnd) { wnd = getWndByLayout(window.siyuan.layout.centerLayout); } + let editor: Protyle const tab = new Tab({ icon: "iconRiffCard", title: window.siyuan.languages.spaceRepetition, @@ -27,23 +30,39 @@ export const newCardTab = (options: { type: "card", tab, data: { - type: options.type, + title: options.title, + cardType: options.cardType, id: options.id }, init(element) { - fetchPost(options.type === "all" ? "/api/riff/getRiffDueCards" : - (options.type === "doc" ? "/api/riff/getTreeRiffDueCards" : "/api/riff/getNotebookRiffDueCards"), { + fetchPost(options.cardType === "all" ? "/api/riff/getRiffDueCards" : + (options.cardType === "doc" ? "/api/riff/getTreeRiffDueCards" : "/api/riff/getNotebookRiffDueCards"), { rootID: options.id, deckID: options.id, notebook: options.id, }, (response) => { element.innerHTML = genCardHTML({ id: options.id, - cardType: options.type, - blocks: response.data, + cardType: options.cardType, + blocks: response.data.cards, isTab: true, }); + + editor = bindCardEvent({ + element, + id: options.id, + title: options.title, + cardType: options.cardType, + blocks: response.data.cards, + dialog: options.dialog, + }) }); + }, + destroy() { + editor.destroy(); + }, + resize(){ + editor.resize(); } }); tab.addModel(custom); diff --git a/app/src/card/openCard.ts b/app/src/card/openCard.ts index ba8cccd7e..94c32114c 100644 --- a/app/src/card/openCard.ts +++ b/app/src/card/openCard.ts @@ -33,8 +33,8 @@ export const genCardHTML = (options: { ` : `
-
-
+
+
`} @@ -54,35 +54,35 @@ export const genCardHTML = (options: {
${window.siyuan.languages.nextRound} -
-
-
-
- @@ -91,44 +91,16 @@ export const genCardHTML = (options: {
`; }; -export const openCard = () => { - fetchPost("/api/riff/getRiffDueCards", {deckID: ""}, (cardsResponse) => { - openCardByData(cardsResponse.data, "all"); - }); -}; - -export const openCardByData = (cardsData: { - cards: ICard[], - unreviewedCount: number -}, cardType: TCardType, id?: string, title?: string) => { - const exit = window.siyuan.dialogs.find(item => { - if (item.element.getAttribute("data-key") === window.siyuan.config.keymap.general.riffCard.custom) { - item.destroy(); - return true; - } - }); - if (exit) { - return; - } - - let blocks = cardsData.cards; +export const bindCardEvent = (options: { + element: Element, + title?: string, + blocks: ICard[], + cardType: TCardType, + id?: string, + dialog: Dialog, +}) => { let index = 0; - const dialog = new Dialog({ - content: genCardHTML({id, cardType, blocks, isTab: false}), - width: isMobile() ? "100vw" : "80vw", - height: isMobile() ? "100vh" : "70vh", - destroyCallback() { - if (editor) { - editor.destroy(); - if (window.siyuan.mobile) { - window.siyuan.mobile.popEditor = null; - } - } - } - }); - (dialog.element.querySelector(".b3-dialog__scrim") as HTMLElement).style.backgroundColor = "var(--b3-theme-background)"; - (dialog.element.querySelector(".b3-dialog__container") as HTMLElement).style.maxWidth = "1024px"; - const editor = new Protyle(dialog.element.querySelector("[data-type='render']") as HTMLElement, { + const editor = new Protyle(options.element.querySelector("[data-type='render']") as HTMLElement, { blockId: "", action: [Constants.CB_GET_ALL], render: { @@ -145,20 +117,20 @@ export const openCardByData = (cardsData: { if (window.siyuan.config.editor.readOnly) { disabledProtyle(editor.protyle); } - if (blocks.length > 0) { + if (options.blocks.length > 0) { fetchPost("/api/filetree/getDoc", { - id: blocks[index].blockID, + id: options.blocks[index].blockID, mode: 0, size: Constants.SIZE_GET_MAX }, (response) => { onGet(response, editor.protyle, [Constants.CB_GET_ALL, Constants.CB_GET_HTML]); }); } - (dialog.element.firstElementChild as HTMLElement).style.zIndex = "200"; - dialog.element.setAttribute("data-key", window.siyuan.config.keymap.general.riffCard.custom); - const countElement = dialog.element.querySelector('[data-type="count"]'); - const actionElements = dialog.element.querySelectorAll(".card__action"); - const filterElement = dialog.element.querySelector('[data-type="filter"]'); + (options.element.firstElementChild as HTMLElement).style.zIndex = "200"; + options.element.setAttribute("data-key", window.siyuan.config.keymap.general.riffCard.custom); + const countElement = options.element.querySelector('[data-type="count"]'); + const actionElements = options.element.querySelectorAll(".card__action"); + const filterElement = options.element.querySelector('[data-type="filter"]'); const fetchNewRound = () => { const currentCardType = filterElement.getAttribute("data-cardtype"); fetchPost(currentCardType === "all" ? "/api/riff/getRiffDueCards" : @@ -168,14 +140,14 @@ export const openCardByData = (cardsData: { notebook: filterElement.getAttribute("data-id"), }, (treeCards) => { index = 0; - blocks = treeCards.data.cards; - if (blocks.length > 0) { + options.blocks = treeCards.data.cards; + if (options.blocks.length > 0) { nextCard({ countElement, editor, actionElements, index, - blocks + blocks: options.blocks }); } else { allDone(countElement, editor, actionElements); @@ -183,7 +155,7 @@ export const openCardByData = (cardsData: { }); }; - dialog.element.addEventListener("click", (event) => { + options.element.addEventListener("click", (event: MouseEvent) => { const target = event.target as HTMLElement; let type = ""; if (typeof event.detail === "string") { @@ -205,8 +177,8 @@ export const openCardByData = (cardsData: { } else { const fullscreenElement = hasClosestByAttribute(target, "data-type", "fullscreen"); if (fullscreenElement) { - fullscreen(dialog.element.querySelector(".card__main"), - dialog.element.querySelector('[data-type="fullscreen"]')); + fullscreen(options.element.querySelector(".card__main"), + options.element.querySelector('[data-type="fullscreen"]')); event.stopPropagation(); event.preventDefault(); return; @@ -214,9 +186,10 @@ export const openCardByData = (cardsData: { const sticktabElement = hasClosestByAttribute(target, "data-type", "sticktab"); if (sticktabElement) { newCardTab({ - type: filterElement.getAttribute("data-cardtype") as TCardType, + cardType: filterElement.getAttribute("data-cardtype") as TCardType, id: filterElement.getAttribute("data-id"), - dialog, + dialog: options.dialog, + title: options.title }); event.stopPropagation(); event.preventDefault(); @@ -224,7 +197,7 @@ export const openCardByData = (cardsData: { } const closeElement = hasClosestByAttribute(target, "data-type", "close"); if (closeElement) { - dialog.destroy(); + options.dialog.destroy(); event.stopPropagation(); event.preventDefault(); return; @@ -253,16 +226,16 @@ export const openCardByData = (cardsData: { }, [], undefined, window.siyuan.languages.specifyPath, true); } }).element); - if (title || response.data.length > 0) { + if (options.title || response.data.length > 0) { window.siyuan.menus.menu.append(new MenuItem({type: "separator"}).element); } - if (title) { + if (options.title) { window.siyuan.menus.menu.append(new MenuItem({ iconHTML: Constants.ZWSP, - label: escapeHtml(title), + label: escapeHtml(options.title), click() { - filterElement.setAttribute("data-id", id); - filterElement.setAttribute("data-cardtype", cardType); + filterElement.setAttribute("data-id", options.id); + filterElement.setAttribute("data-cardtype", options.cardType); fetchNewRound(); }, }).element); @@ -301,7 +274,7 @@ export const openCardByData = (cardsData: { type = buttonElement.getAttribute("data-type"); } } - if (!type || !blocks[index]) { + if (!type || !options.blocks[index]) { return; } event.preventDefault(); @@ -315,7 +288,7 @@ export const openCardByData = (cardsData: { actionElements[0].classList.add("fn__none"); actionElements[1].querySelectorAll(".b3-button").forEach((element, btnIndex) => { if (btnIndex !== 0) { - element.previousElementSibling.textContent = blocks[index].nextDues[btnIndex - 1]; + element.previousElementSibling.textContent = options.blocks[index].nextDues[btnIndex - 1]; } }); actionElements[1].classList.remove("fn__none"); @@ -332,17 +305,17 @@ export const openCardByData = (cardsData: { editor, actionElements, index, - blocks + blocks: options.blocks }); } return; } if (["0", "1", "2", "3", "-3"].includes(type) && actionElements[0].classList.contains("fn__none")) { fetchPost(type === "-3" ? "/api/riff/skipReviewRiffCard" : "/api/riff/reviewRiffCard", { - deckID: blocks[index].deckID, - cardID: blocks[index].cardID, + deckID: options.blocks[index].deckID, + cardID: options.blocks[index].cardID, rating: parseInt(type), - reviewedCards: blocks + reviewedCards: options.blocks }, () => { /// #if MOBILE if (type !== "-3" && @@ -352,18 +325,18 @@ export const openCardByData = (cardsData: { } /// #endif index++; - if (index > blocks.length - 1) { + if (index > options.blocks.length - 1) { const currentCardType = filterElement.getAttribute("data-cardtype"); fetchPost(currentCardType === "all" ? "/api/riff/getRiffDueCards" : (currentCardType === "doc" ? "/api/riff/getTreeRiffDueCards" : "/api/riff/getNotebookRiffDueCards"), { rootID: filterElement.getAttribute("data-id"), deckID: filterElement.getAttribute("data-id"), notebook: filterElement.getAttribute("data-id"), - reviewedCards: blocks + reviewedCards: options.blocks }, (result) => { index = 0; - blocks = result.data.cards; - if (blocks.length === 0) { + options.blocks = result.data.cards; + if (options.blocks.length === 0) { if (result.data.unreviewedCount > 0) { newRound(countElement, editor, actionElements, result.data.unreviewedCount); } else { @@ -375,7 +348,7 @@ export const openCardByData = (cardsData: { editor, actionElements, index, - blocks + blocks: options.blocks }); } }); @@ -386,11 +359,57 @@ export const openCardByData = (cardsData: { editor, actionElements, index, - blocks + blocks: options.blocks }); }); } }); + return editor; +}; + +export const openCard = () => { + fetchPost("/api/riff/getRiffDueCards", {deckID: ""}, (cardsResponse) => { + openCardByData(cardsResponse.data, "all"); + }); +}; + +export const openCardByData = (cardsData: { + cards: ICard[], + unreviewedCount: number +}, cardType: TCardType, id?: string, title?: string) => { + const exit = window.siyuan.dialogs.find(item => { + if (item.element.getAttribute("data-key") === window.siyuan.config.keymap.general.riffCard.custom) { + item.destroy(); + return true; + } + }); + if (exit) { + return; + } + + const dialog = new Dialog({ + content: genCardHTML({id, cardType, blocks: cardsData.cards, isTab: false}), + width: isMobile() ? "100vw" : "80vw", + height: isMobile() ? "100vh" : "70vh", + destroyCallback() { + if (editor) { + editor.destroy(); + if (window.siyuan.mobile) { + window.siyuan.mobile.popEditor = null; + } + } + } + }); + (dialog.element.querySelector(".b3-dialog__scrim") as HTMLElement).style.backgroundColor = "var(--b3-theme-background)"; + (dialog.element.querySelector(".b3-dialog__container") as HTMLElement).style.maxWidth = "1024px"; + const editor = bindCardEvent({ + element: dialog.element, + blocks: cardsData.cards, + title, + id, + cardType, + dialog + }); }; const nextCard = (options: { diff --git a/app/src/editor/util.ts b/app/src/editor/util.ts index 58bf8e7ed..61cdcde77 100644 --- a/app/src/editor/util.ts +++ b/app/src/editor/util.ts @@ -25,6 +25,7 @@ import {zoomOut} from "../menus/protyle"; import {countBlockWord, countSelectWord} from "../layout/status"; import {showMessage} from "../dialog/message"; import {getSearch} from "../util/functions"; +import {resize} from "../protyle/util/resize"; export const openFileById = async (options: { id: string, @@ -390,7 +391,7 @@ export const updatePanelByEditor = (protyle?: IProtyle, focus = true, pushBackSt return; } title = protyle.title.editElement.textContent; - setPadding(protyle); + resize(protyle); if (focus) { if (protyle.toolbar.range) { focusByRange(protyle.toolbar.range); diff --git a/app/src/layout/Wnd.ts b/app/src/layout/Wnd.ts index 823278711..2b4be1209 100644 --- a/app/src/layout/Wnd.ts +++ b/app/src/layout/Wnd.ts @@ -33,6 +33,7 @@ import {escapeHtml} from "../util/escape"; import {isWindow} from "../util/functions"; import {hideAllElements} from "../protyle/ui/hideElements"; import {focusByOffset, getSelectionOffset} from "../protyle/util/selection"; +import {Custom} from "./dock/Custom"; export class Wnd { public id: string; @@ -646,6 +647,9 @@ export class Wnd { model.pdfObject.pdfLoadingTask.destroy(); } } + if (model instanceof Custom) { + model.destroy(); + } model.send("closews", {}); } diff --git a/app/src/layout/dock/Custom.ts b/app/src/layout/dock/Custom.ts index 81114a205..0ac9425b4 100644 --- a/app/src/layout/dock/Custom.ts +++ b/app/src/layout/dock/Custom.ts @@ -8,8 +8,10 @@ export class Custom extends Model { constructor(options: { tab: Tab, data: any, + destroy?: () => void, + resize?: () => void, type: string, // 同一类型的唯一标识 - init:(element:Element)=>void + init: (element: Element) => void }) { super({id: options.tab.id}); if (window.siyuan.config.fileTree.openFilesUseCurrentTab) { @@ -20,10 +22,24 @@ export class Custom extends Model { this.element.addEventListener("click", () => { setPanelFocus(this.element.parentElement.parentElement); }); - this.update(); + this.data = options.data; + this.destroy = options.destroy; + this.resize = options.resize; + } + + public destroy() { + if (this.destroy) { + this.destroy(); + } + } + + public resize() { + if (this.resize) { + this.resize(); + } } private update() { - this.element.innerHTML = `eee` + // TODO } } diff --git a/app/src/layout/getAll.ts b/app/src/layout/getAll.ts index 78ec37b68..6824443d1 100644 --- a/app/src/layout/getAll.ts +++ b/app/src/layout/getAll.ts @@ -9,6 +9,7 @@ import {Search} from "../search"; import {Files} from "./dock/Files"; import {Bookmark} from "./dock/Bookmark"; import {Tag} from "./dock/Tag"; +import {Custom} from "./dock/Custom"; export const getAllModels = () => { const models: IModels = { @@ -21,7 +22,8 @@ export const getAllModels = () => { inbox: [], files: [], bookmark: [], - tag: [] + tag: [], + custom: [], }; const getTabs = (layout: Layout) => { for (let i = 0; i < layout.children.length; i++) { @@ -46,6 +48,8 @@ export const getAllModels = () => { models.bookmark.push(model); } else if (model instanceof Tag) { models.tag.push(model); + } else if (model instanceof Custom) { + models.custom.push(model); } } else { getTabs(item as Layout); diff --git a/app/src/layout/util.ts b/app/src/layout/util.ts index f6faec384..b1474a8f5 100644 --- a/app/src/layout/util.ts +++ b/app/src/layout/util.ts @@ -532,34 +532,9 @@ export const resizeTabs = () => { resizeTimeout = window.setTimeout(() => { const models = getAllModels(); models.editor.forEach((item) => { - if (item.editor && item.editor.protyle && item.element.parentElement) { - hideElements(["gutter"], item.editor.protyle); - setPadding(item.editor.protyle); - if (typeof echarts !== "undefined") { - item.editor.protyle.wysiwyg.element.querySelectorAll('[data-subtype="echarts"], [data-subtype="mindmap"]').forEach((chartItem: HTMLElement) => { - const chartInstance = echarts.getInstanceById(chartItem.firstElementChild.nextElementSibling.getAttribute("_echarts_instance_")); - if (chartInstance) { - chartInstance.resize(); - } - }); - } - // 保持光标位置不变 https://ld246.com/article/1673704873983/comment/1673765814595#comments - if (!item.element.classList.contains("fn__none") && item.editor.protyle.toolbar.range) { - let rangeRect = item.editor.protyle.toolbar.range.getBoundingClientRect(); - if (rangeRect.height === 0) { - const blockElement = hasClosestBlock(item.editor.protyle.toolbar.range.startContainer); - if (blockElement) { - rangeRect = blockElement.getBoundingClientRect(); - } - } - if (rangeRect.height === 0) { - return; - } - const protyleRect = item.editor.protyle.element.getBoundingClientRect(); - if (protyleRect.top + 30 > rangeRect.top || protyleRect.bottom < rangeRect.bottom) { - item.editor.protyle.toolbar.range.startContainer.parentElement.scrollIntoView(protyleRect.top > rangeRect.top); - } - } + if (item.editor && item.editor.protyle && + item.element.parentElement && !item.element.classList.contains("fn__none")) { + item.editor.resize(); } }); // https://github.com/siyuan-note/siyuan/issues/6250 @@ -572,6 +547,9 @@ export const resizeTabs = () => { hideElements(["gutter"], editorItem.protyle); }); }); + models.custom.forEach(item => { + item.resize(); + }) pdfResize(); hideAllElements(["gutter"]); }, 200); diff --git a/app/src/protyle/index.ts b/app/src/protyle/index.ts index e027ea817..c707bc990 100644 --- a/app/src/protyle/index.ts +++ b/app/src/protyle/index.ts @@ -26,6 +26,7 @@ import {disabledProtyle, enableProtyle, onGet} from "./util/onGet"; import {reloadProtyle} from "./util/reload"; import {renderBacklink} from "./wysiwyg/renderBacklink"; import {setEmpty} from "../mobile/util/setEmpty"; +import {resize} from "./util/resize"; export class Protyle { @@ -271,4 +272,8 @@ export class Protyle { public destroy() { destroy(this.protyle); } + + public resize() { + resize(this.protyle); + } } diff --git a/app/src/protyle/util/resize.ts b/app/src/protyle/util/resize.ts new file mode 100644 index 000000000..fb0215948 --- /dev/null +++ b/app/src/protyle/util/resize.ts @@ -0,0 +1,33 @@ +import {hideElements} from "../ui/hideElements"; +import {setPadding} from "../ui/initUI"; +import {hasClosestBlock} from "./hasClosest"; + +export const resize = (protyle: IProtyle) => { + hideElements(["gutter"], protyle); + setPadding(protyle); + if (typeof echarts !== "undefined") { + protyle.wysiwyg.element.querySelectorAll('[data-subtype="echarts"], [data-subtype="mindmap"]').forEach((chartItem: HTMLElement) => { + const chartInstance = echarts.getInstanceById(chartItem.firstElementChild.nextElementSibling.getAttribute("_echarts_instance_")); + if (chartInstance) { + chartInstance.resize(); + } + }); + } + // 保持光标位置不变 https://ld246.com/article/1673704873983/comment/1673765814595#comments + if (protyle.toolbar.range) { + let rangeRect = protyle.toolbar.range.getBoundingClientRect(); + if (rangeRect.height === 0) { + const blockElement = hasClosestBlock(protyle.toolbar.range.startContainer); + if (blockElement) { + rangeRect = blockElement.getBoundingClientRect(); + } + } + if (rangeRect.height === 0) { + return; + } + const protyleRect = protyle.element.getBoundingClientRect(); + if (protyleRect.top + 30 > rangeRect.top || protyleRect.bottom < rangeRect.bottom) { + protyle.toolbar.range.startContainer.parentElement.scrollIntoView(protyleRect.top > rangeRect.top); + } + } +}; diff --git a/app/src/types/index.d.ts b/app/src/types/index.d.ts index ad88fd425..65041a1aa 100644 --- a/app/src/types/index.d.ts +++ b/app/src/types/index.d.ts @@ -658,6 +658,7 @@ declare interface IModels { tag: import("../layout/dock/Tag").Tag[] asset: import("../asset").Asset[] search: import("../search").Search[] + custom: import("../layout/dock/Custom").Custom[] } declare interface IMenu {