@sequent-org/moodboard 1.4.2 → 1.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/core/HistoryManager.js +0 -8
- package/src/core/SaveManager.js +1 -0
- package/src/core/index.js +0 -7
- package/src/core/keyboard/KeyboardSelectionActions.js +2 -2
- package/src/moodboard/integration/MoodBoardEventBindings.js +27 -29
- package/src/moodboard/integration/MoodBoardLoadApi.js +31 -8
package/package.json
CHANGED
|
@@ -18,8 +18,6 @@ export class HistoryManager {
|
|
|
18
18
|
// Флаг для предотвращения зацикливания при undo/redo
|
|
19
19
|
this.isExecutingCommand = false;
|
|
20
20
|
this._listenersAttached = false;
|
|
21
|
-
this._onUndo = () => this.undo();
|
|
22
|
-
this._onRedo = () => this.redo();
|
|
23
21
|
this._onDebug = () => this.debugHistory();
|
|
24
22
|
|
|
25
23
|
this.initEventListeners();
|
|
@@ -28,10 +26,6 @@ export class HistoryManager {
|
|
|
28
26
|
initEventListeners() {
|
|
29
27
|
if (this._listenersAttached) return;
|
|
30
28
|
this._listenersAttached = true;
|
|
31
|
-
// Слушаем события клавиатуры
|
|
32
|
-
this.eventBus.on(Events.Keyboard.Undo, this._onUndo);
|
|
33
|
-
this.eventBus.on(Events.Keyboard.Redo, this._onRedo);
|
|
34
|
-
|
|
35
29
|
// Для отладки
|
|
36
30
|
this.eventBus.on(Events.History.Debug, this._onDebug);
|
|
37
31
|
}
|
|
@@ -253,8 +247,6 @@ export class HistoryManager {
|
|
|
253
247
|
*/
|
|
254
248
|
destroy() {
|
|
255
249
|
this.clear();
|
|
256
|
-
this.eventBus.off(Events.Keyboard.Undo, this._onUndo);
|
|
257
|
-
this.eventBus.off(Events.Keyboard.Redo, this._onRedo);
|
|
258
250
|
this.eventBus.off(Events.History.Debug, this._onDebug);
|
|
259
251
|
this._listenersAttached = false;
|
|
260
252
|
}
|
package/src/core/SaveManager.js
CHANGED
package/src/core/index.js
CHANGED
|
@@ -226,13 +226,6 @@ export class CoreMoodBoard {
|
|
|
226
226
|
historySize: data.historySize,
|
|
227
227
|
});
|
|
228
228
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
// Можно здесь обновить состояние кнопок Undo/Redo в UI
|
|
232
|
-
this.eventBus.emit(Events.UI.UpdateHistoryButtons, {
|
|
233
|
-
canUndo: data.canUndo,
|
|
234
|
-
canRedo: data.canRedo
|
|
235
|
-
});
|
|
236
229
|
});
|
|
237
230
|
}
|
|
238
231
|
|
|
@@ -10,11 +10,11 @@ export class KeyboardSelectionActions {
|
|
|
10
10
|
switch (actionId) {
|
|
11
11
|
case 'undo':
|
|
12
12
|
return () => {
|
|
13
|
-
this.eventBus.emit(Events.
|
|
13
|
+
this.eventBus.emit(Events.UI.LoadPrevVersion);
|
|
14
14
|
};
|
|
15
15
|
case 'redo':
|
|
16
16
|
return () => {
|
|
17
|
-
this.eventBus.emit(Events.
|
|
17
|
+
this.eventBus.emit(Events.UI.LoadNextVersion);
|
|
18
18
|
};
|
|
19
19
|
case 'select-all':
|
|
20
20
|
return () => {
|
|
@@ -91,40 +91,25 @@ export function bindToolbarEvents(board) {
|
|
|
91
91
|
if (!moodboardId) return;
|
|
92
92
|
if (!Number.isFinite(targetVersion) || targetVersion < 1) return;
|
|
93
93
|
try {
|
|
94
|
-
await board.loadFromApi(moodboardId, targetVersion, {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
const restoreSnapshot = board.coreMoodboard?.getBoardData?.();
|
|
99
|
-
if (restoreSnapshot && board.coreMoodboard?.apiClient) {
|
|
100
|
-
const saveResult = await board.coreMoodboard.apiClient.saveBoard(
|
|
101
|
-
moodboardId,
|
|
102
|
-
restoreSnapshot,
|
|
103
|
-
{ actionType: 'history_restore' }
|
|
104
|
-
);
|
|
105
|
-
const restoredVersion = Number(saveResult?.historyVersion);
|
|
106
|
-
if (Number.isFinite(restoredVersion) && restoredVersion > 0) {
|
|
107
|
-
board.currentLoadedVersion = restoredVersion;
|
|
108
|
-
board.coreMoodboard.eventBus.emit(Events.UI.UpdateHistoryButtons, {
|
|
109
|
-
canUndo: restoredVersion > 1,
|
|
110
|
-
canRedo: false,
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
}
|
|
94
|
+
await board.loadFromApi(moodboardId, targetVersion, {
|
|
95
|
+
fallbackToSeedOnError: false,
|
|
96
|
+
historyNavigation: true,
|
|
97
|
+
});
|
|
114
98
|
} catch (error) {
|
|
115
99
|
console.warn(`⚠️ Не удалось загрузить версию ${targetVersion}:`, error?.message || error);
|
|
116
100
|
}
|
|
117
101
|
};
|
|
118
102
|
|
|
119
103
|
board.coreMoodboard.eventBus.on(Events.UI.LoadPrevVersion, () => {
|
|
120
|
-
const current = Number(board.
|
|
104
|
+
const current = Number(board.historyCursorVersion);
|
|
121
105
|
if (!Number.isFinite(current) || current <= 1) return;
|
|
122
106
|
loadVersion(current - 1);
|
|
123
107
|
});
|
|
124
108
|
|
|
125
109
|
board.coreMoodboard.eventBus.on(Events.UI.LoadNextVersion, () => {
|
|
126
|
-
const current = Number(board.
|
|
127
|
-
|
|
110
|
+
const current = Number(board.historyCursorVersion);
|
|
111
|
+
const head = Number(board.historyHeadVersion);
|
|
112
|
+
if (!Number.isFinite(current) || !Number.isFinite(head) || current >= head) return;
|
|
128
113
|
loadVersion(current + 1);
|
|
129
114
|
});
|
|
130
115
|
}
|
|
@@ -154,8 +139,19 @@ export function bindSaveCallbacks(board) {
|
|
|
154
139
|
return;
|
|
155
140
|
}
|
|
156
141
|
|
|
157
|
-
|
|
158
|
-
|
|
142
|
+
board.coreMoodboard.eventBus.on('save:success', (data) => {
|
|
143
|
+
const savedVersion = Number(data?.response?.historyVersion);
|
|
144
|
+
if (Number.isFinite(savedVersion) && savedVersion > 0) {
|
|
145
|
+
board.currentLoadedVersion = savedVersion;
|
|
146
|
+
board.historyHeadVersion = savedVersion;
|
|
147
|
+
board.historyCursorVersion = savedVersion;
|
|
148
|
+
board.coreMoodboard.eventBus.emit(Events.UI.UpdateHistoryButtons, {
|
|
149
|
+
canUndo: savedVersion > 1,
|
|
150
|
+
canRedo: false,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (typeof board.options.onSave === 'function') {
|
|
159
155
|
try {
|
|
160
156
|
let screenshot = null;
|
|
161
157
|
if (board.coreMoodboard.pixi && board.coreMoodboard.pixi.app && board.coreMoodboard.pixi.app.view) {
|
|
@@ -171,9 +167,11 @@ export function bindSaveCallbacks(board) {
|
|
|
171
167
|
} catch (error) {
|
|
172
168
|
console.warn('⚠️ Ошибка в коллбеке onSave:', error);
|
|
173
169
|
}
|
|
174
|
-
}
|
|
170
|
+
}
|
|
171
|
+
});
|
|
175
172
|
|
|
176
|
-
|
|
173
|
+
board.coreMoodboard.eventBus.on('save:error', (data) => {
|
|
174
|
+
if (typeof board.options.onSave === 'function') {
|
|
177
175
|
try {
|
|
178
176
|
board.options.onSave({
|
|
179
177
|
success: false,
|
|
@@ -183,6 +181,6 @@ export function bindSaveCallbacks(board) {
|
|
|
183
181
|
} catch (error) {
|
|
184
182
|
console.warn('⚠️ Ошибка в коллбеке onSave:', error);
|
|
185
183
|
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
184
|
+
}
|
|
185
|
+
});
|
|
188
186
|
}
|
|
@@ -17,6 +17,21 @@ export function getCsrfToken(board) {
|
|
|
17
17
|
|| '';
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
function resolveMoodboardApiBase(board) {
|
|
21
|
+
const raw = String(board?.options?.apiUrl || '').trim();
|
|
22
|
+
if (!raw) return '/api/v2/moodboard';
|
|
23
|
+
|
|
24
|
+
// Совместимость с legacy конфигом: /api/moodboard -> /api/v2/moodboard
|
|
25
|
+
if (raw.endsWith('/api/moodboard')) {
|
|
26
|
+
return raw.replace(/\/api\/moodboard$/, '/api/v2/moodboard');
|
|
27
|
+
}
|
|
28
|
+
if (raw.endsWith('/api/moodboard/')) {
|
|
29
|
+
return raw.replace(/\/api\/moodboard\/$/, '/api/v2/moodboard/');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return raw;
|
|
33
|
+
}
|
|
34
|
+
|
|
20
35
|
function normalizeLoadedPayload(payload, moodboardIdFallback) {
|
|
21
36
|
const state = (payload?.state && typeof payload.state === 'object')
|
|
22
37
|
? payload.state
|
|
@@ -36,6 +51,7 @@ function normalizeLoadedPayload(payload, moodboardIdFallback) {
|
|
|
36
51
|
|
|
37
52
|
export async function loadExistingBoard(board, version = null, options = {}) {
|
|
38
53
|
const fallbackToSeedOnError = options?.fallbackToSeedOnError !== false;
|
|
54
|
+
const historyNavigation = options?.historyNavigation === true;
|
|
39
55
|
try {
|
|
40
56
|
const boardId = board.options.boardId;
|
|
41
57
|
|
|
@@ -47,11 +63,12 @@ export async function loadExistingBoard(board, version = null, options = {}) {
|
|
|
47
63
|
return;
|
|
48
64
|
}
|
|
49
65
|
|
|
50
|
-
|
|
66
|
+
const apiBase = resolveMoodboardApiBase(board);
|
|
67
|
+
console.log(`📦 MoodBoard: загружаем доску ${boardId} с ${apiBase}`);
|
|
51
68
|
|
|
52
|
-
const baseUrl =
|
|
53
|
-
? `${
|
|
54
|
-
: `${
|
|
69
|
+
const baseUrl = apiBase.endsWith('/')
|
|
70
|
+
? `${apiBase}${boardId}`
|
|
71
|
+
: `${apiBase}/${boardId}`;
|
|
55
72
|
const loadUrl = Number.isFinite(version) ? `${baseUrl}/${version}` : baseUrl;
|
|
56
73
|
|
|
57
74
|
const response = await fetch(loadUrl, {
|
|
@@ -71,14 +88,20 @@ export async function loadExistingBoard(board, version = null, options = {}) {
|
|
|
71
88
|
|
|
72
89
|
if (apiResponse?.success && payload) {
|
|
73
90
|
const normalizedData = normalizeLoadedPayload(payload, boardId);
|
|
74
|
-
|
|
91
|
+
const loadedVersion = Number(normalizedData.version) || null;
|
|
92
|
+
board.currentLoadedVersion = loadedVersion;
|
|
93
|
+
board.historyCursorVersion = loadedVersion;
|
|
94
|
+
if (!historyNavigation) {
|
|
95
|
+
board.historyHeadVersion = loadedVersion;
|
|
96
|
+
}
|
|
75
97
|
console.log('✅ MoodBoard: данные загружены с сервера', normalizedData);
|
|
76
98
|
board.dataManager.loadData(normalizedData);
|
|
77
99
|
if (board?.coreMoodboard?.eventBus) {
|
|
100
|
+
const cursor = Number(board.historyCursorVersion);
|
|
101
|
+
const head = Number(board.historyHeadVersion);
|
|
78
102
|
board.coreMoodboard.eventBus.emit(Events.UI.UpdateHistoryButtons, {
|
|
79
|
-
canUndo: Number(
|
|
80
|
-
|
|
81
|
-
canRedo: true,
|
|
103
|
+
canUndo: Number.isFinite(cursor) && cursor > 1,
|
|
104
|
+
canRedo: Number.isFinite(cursor) && Number.isFinite(head) && cursor < head,
|
|
82
105
|
});
|
|
83
106
|
}
|
|
84
107
|
invokeOnLoad(board, { success: true, data: normalizedData });
|