Skip to content

Commit b6a9ef2

Browse files
authored
Improve spaced repetition interface (#15627)
* Improve spaced repetition interface fix #10331 * Improve spaced repetition interface fix #14149 * Improve spaced repetition interface fix #10331 * Improve spaced repetition interface fix #10331
1 parent 404d9f6 commit b6a9ef2

File tree

2 files changed

+113
-64
lines changed

2 files changed

+113
-64
lines changed

app/src/card/newCardTab.ts

Lines changed: 60 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {Tab} from "../layout/Tab";
22
import {Custom} from "../layout/dock/Custom";
3-
import {bindCardEvent, genCardHTML} from "./openCard";
3+
import {bindCardEvent, genCardHTML, initCardComponent} from "./openCard";
44
import {fetchPost} from "../util/fetch";
55
import {Protyle} from "../protyle";
66
import {setPanelFocus} from "../layout/util";
@@ -19,65 +19,76 @@ export const newCardModel = (options: {
1919
}
2020
}) => {
2121
let editor: Protyle;
22+
23+
const fetchCardsData = async (): Promise<ICardData> => {
24+
return new Promise((resolve) => {
25+
fetchPost(options.data.cardType === "all" ? "/api/riff/getRiffDueCards" :
26+
(options.data.cardType === "doc" ? "/api/riff/getTreeRiffDueCards" : "/api/riff/getNotebookRiffDueCards"), {
27+
rootID: options.data.id,
28+
deckID: options.data.id,
29+
notebook: options.data.id,
30+
}, async (response) => {
31+
let cardsData: ICardData = response.data;
32+
for (let i = 0; i < options.app.plugins.length; i++) {
33+
cardsData = await options.app.plugins[i].updateCards(response.data);
34+
}
35+
resolve(cardsData);
36+
});
37+
});
38+
};
39+
40+
const renderCardsAndBindEvents = async (element: HTMLElement, data: any, cardsData: ICardData, index?: number, isUpdate?: boolean) => {
41+
customObj.editors.forEach(editor => {
42+
editor.destroy();
43+
});
44+
customObj.editors.length = 0;
45+
46+
element.innerHTML = genCardHTML({
47+
id: data.id,
48+
cardType: data.cardType,
49+
cardsData,
50+
isTab: true,
51+
});
52+
53+
const cardOptions = {
54+
app: options.app,
55+
element: element,
56+
id: data.id,
57+
title: data.title,
58+
cardType: data.cardType,
59+
cardsData,
60+
index,
61+
};
62+
63+
if (isUpdate) {
64+
const initResult = await initCardComponent(cardOptions);
65+
editor = initResult.editor;
66+
} else {
67+
editor = await bindCardEvent(cardOptions);
68+
}
69+
70+
customObj.editors.push(editor);
71+
};
72+
2273
const customObj = new Custom({
2374
app: options.app,
2475
type: "siyuan-card",
2576
tab: options.tab,
2677
data: options.data,
2778
async init() {
2879
if (options.data.cardsData) {
80+
// 使用现有的 cardsData
2981
for (let i = 0; i < options.app.plugins.length; i++) {
3082
options.data.cardsData = await options.app.plugins[i].updateCards(options.data.cardsData);
3183
}
32-
this.element.innerHTML = genCardHTML({
33-
id: this.data.id,
34-
cardType: this.data.cardType,
35-
cardsData: options.data.cardsData,
36-
isTab: true,
37-
});
38-
39-
editor = await bindCardEvent({
40-
app: options.app,
41-
element: this.element,
42-
id: this.data.id,
43-
title: this.data.title,
44-
cardType: this.data.cardType,
45-
cardsData: options.data.cardsData,
46-
index: options.data.index,
47-
});
48-
customObj.editors.push(editor);
84+
await renderCardsAndBindEvents(this.element, this.data, options.data.cardsData, options.data.index);
4985
// https://github.com/siyuan-note/siyuan/issues/9561#issuecomment-1794473512
5086
delete options.data.cardsData;
5187
delete options.data.index;
5288
} else {
53-
fetchPost(this.data.cardType === "all" ? "/api/riff/getRiffDueCards" :
54-
(this.data.cardType === "doc" ? "/api/riff/getTreeRiffDueCards" : "/api/riff/getNotebookRiffDueCards"), {
55-
rootID: this.data.id,
56-
deckID: this.data.id,
57-
notebook: this.data.id,
58-
}, async (response) => {
59-
let cardsData: ICardData = response.data;
60-
for (let i = 0; i < options.app.plugins.length; i++) {
61-
cardsData = await options.app.plugins[i].updateCards(response.data);
62-
}
63-
this.element.innerHTML = genCardHTML({
64-
id: this.data.id,
65-
cardType: this.data.cardType,
66-
cardsData,
67-
isTab: true,
68-
});
69-
70-
editor = await bindCardEvent({
71-
app: options.app,
72-
element: this.element,
73-
id: this.data.id,
74-
title: this.data.title,
75-
cardType: this.data.cardType,
76-
cardsData,
77-
});
78-
79-
customObj.editors.push(editor);
80-
});
89+
// 获取新的 cardsData
90+
const cardsData = await fetchCardsData();
91+
await renderCardsAndBindEvents(this.element, this.data, cardsData);
8192
}
8293
},
8394
destroy() {
@@ -90,23 +101,9 @@ export const newCardModel = (options: {
90101
editor.resize();
91102
}
92103
},
93-
update() {
94-
fetchPost(this.data.cardType === "all" ? "/api/riff/getRiffDueCards" :
95-
(this.data.cardType === "doc" ? "/api/riff/getTreeRiffDueCards" : "/api/riff/getNotebookRiffDueCards"), {
96-
rootID: this.data.id,
97-
deckID: this.data.id,
98-
notebook: this.data.id,
99-
}, async (response) => {
100-
for (let i = 0; i < options.app.plugins.length; i++) {
101-
options.data.cardsData = await options.app.plugins[i].updateCards(options.data.cardsData);
102-
}
103-
this.element.innerHTML = genCardHTML({
104-
id: this.data.id,
105-
cardType: this.data.cardType,
106-
cardsData: response.data,
107-
isTab: true,
108-
});
109-
});
104+
async update() {
105+
const cardsData = await fetchCardsData();
106+
await renderCardsAndBindEvents(this.element, this.data, cardsData ,undefined, true);
110107
}
111108
});
112109
customObj.element.addEventListener("click", () => {

app/src/card/openCard.ts

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ const getEditor = (id: string, protyle: IProtyle, element: Element, currentCard:
225225

226226
};
227227

228-
export const bindCardEvent = async (options: {
228+
export const initCardComponent = async (options: {
229229
app: App,
230230
element: Element,
231231
title?: string,
@@ -301,6 +301,33 @@ export const bindCardEvent = async (options: {
301301
};
302302

303303
countElement.innerHTML = genCardCount(options.cardsData, index);
304+
305+
return {
306+
editor,
307+
index,
308+
actionElements,
309+
countElement,
310+
filterElement,
311+
fetchNewRound
312+
};
313+
};
314+
315+
export const bindCardEvent = async (options: {
316+
app: App,
317+
element: Element,
318+
title?: string,
319+
cardsData: ICardData
320+
cardType: TCardType,
321+
id?: string,
322+
dialog?: Dialog,
323+
index?: number
324+
}) => {
325+
// 初始化卡片组件
326+
const initResult = await initCardComponent(options);
327+
const { editor, actionElements, countElement, filterElement, fetchNewRound } = initResult;
328+
let index = initResult.index;
329+
330+
// 绑定点击事件
304331
options.element.addEventListener("click", (event: MouseEvent) => {
305332
const target = event.target as HTMLElement;
306333
let type = "";
@@ -489,6 +516,29 @@ export const bindCardEvent = async (options: {
489516
const sticktabElement = hasClosestByAttribute(target, "data-type", "sticktab");
490517
if (sticktabElement) {
491518
const stickMenu = new Menu();
519+
stickMenu.addItem({
520+
id: "openInNewTab",
521+
icon: "iconOpen",
522+
label: window.siyuan.languages.openInNewTab,
523+
click() {
524+
openFile({
525+
app: options.app,
526+
custom: {
527+
icon: "iconRiffCard",
528+
title: window.siyuan.languages.spaceRepetition,
529+
data: {
530+
cardsData: options.cardsData,
531+
index,
532+
cardType: filterElement.getAttribute("data-cardtype") as TCardType,
533+
id: docId,
534+
title: options.title
535+
},
536+
id: "siyuan-card"
537+
},
538+
});
539+
options.dialog.destroy();
540+
}
541+
});
492542
stickMenu.addItem({
493543
id: "insertRight",
494544
icon: "iconLayoutRight",
@@ -527,6 +577,8 @@ export const bindCardEvent = async (options: {
527577
"instance": "Custom",
528578
"customModelType": "siyuan-card",
529579
"customModelData": {
580+
"cardsData": options.cardsData,
581+
"index": index,
530582
"cardType": filterElement.getAttribute("data-cardtype"),
531583
"id": docId,
532584
"title": options.title

0 commit comments

Comments
 (0)