@sequent-org/moodboard 1.2.49 → 1.2.51
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/ApiClient.js +7 -2
- package/src/core/SaveManager.js +7 -0
- package/src/core/index.js +46 -1
- package/src/moodboard/DataManager.js +31 -1
package/package.json
CHANGED
package/src/core/ApiClient.js
CHANGED
|
@@ -42,8 +42,12 @@ export class ApiClient {
|
|
|
42
42
|
|
|
43
43
|
async saveBoard(boardId, boardData) {
|
|
44
44
|
try {
|
|
45
|
+
// Поддержка нового формата: { boardData: {...}, settings: {...} }
|
|
46
|
+
let payloadBoardData = boardData && boardData.boardData ? boardData.boardData : boardData;
|
|
47
|
+
let payloadSettings = boardData && boardData.settings ? boardData.settings : undefined;
|
|
48
|
+
|
|
45
49
|
// Фильтруем объекты изображений и файлов - убираем избыточные данные
|
|
46
|
-
const cleanedData = this._cleanObjectData(
|
|
50
|
+
const cleanedData = this._cleanObjectData(payloadBoardData);
|
|
47
51
|
|
|
48
52
|
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
|
|
49
53
|
|
|
@@ -58,7 +62,8 @@ export class ApiClient {
|
|
|
58
62
|
credentials: 'same-origin',
|
|
59
63
|
body: JSON.stringify({
|
|
60
64
|
boardId: boardId,
|
|
61
|
-
boardData: cleanedData
|
|
65
|
+
boardData: cleanedData,
|
|
66
|
+
settings: payloadSettings
|
|
62
67
|
})
|
|
63
68
|
});
|
|
64
69
|
|
package/src/core/SaveManager.js
CHANGED
|
@@ -132,6 +132,13 @@ export class SaveManager {
|
|
|
132
132
|
try {
|
|
133
133
|
// Получаем данные для сохранения
|
|
134
134
|
const saveData = data || await this.getBoardData();
|
|
135
|
+
|
|
136
|
+
// Защита: если данные не получены (например, при уничтожении/отписке обработчиков) — выходим без ошибки
|
|
137
|
+
if (!saveData || typeof saveData !== 'object') {
|
|
138
|
+
console.warn('SaveManager: нет данных для сохранения (saveData is null) — пропускаем сохранение');
|
|
139
|
+
this.updateSaveStatus('idle');
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
135
142
|
|
|
136
143
|
// Проверяем, изменились ли данные с последнего сохранения
|
|
137
144
|
if (this.lastSavedData && JSON.stringify(saveData) === JSON.stringify(this.lastSavedData)) {
|
package/src/core/index.js
CHANGED
|
@@ -2151,7 +2151,52 @@ export class CoreMoodBoard {
|
|
|
2151
2151
|
* Получение данных доски для сохранения
|
|
2152
2152
|
*/
|
|
2153
2153
|
getBoardData() {
|
|
2154
|
-
|
|
2154
|
+
// Базовые данные доски (объекты и метаданные из state)
|
|
2155
|
+
const s = this.state.serialize();
|
|
2156
|
+
const boardData = {
|
|
2157
|
+
objects: Array.isArray(s.objects) ? s.objects : [],
|
|
2158
|
+
name: s.name || s.title || 'Untitled Board',
|
|
2159
|
+
description: s.description || null
|
|
2160
|
+
};
|
|
2161
|
+
|
|
2162
|
+
// Настройки (settings): фон, сетка, зум, размеры канваса
|
|
2163
|
+
const app = this.pixi?.app;
|
|
2164
|
+
const rendererBg = app?.renderer?.background?.color ?? app?.renderer?.backgroundColor;
|
|
2165
|
+
const toHex = (num) => {
|
|
2166
|
+
try { return '#' + Number(num >>> 0).toString(16).padStart(6, '0'); } catch (_) { return '#F5F5F5'; }
|
|
2167
|
+
};
|
|
2168
|
+
const world = this.pixi?.worldLayer || app?.stage;
|
|
2169
|
+
const currentZoom = Math.max(0.1, Math.min(5, world?.scale?.x || 1));
|
|
2170
|
+
const canvasW = app?.view?.clientWidth || app?.view?.width || 0;
|
|
2171
|
+
const canvasH = app?.view?.clientHeight || app?.view?.height || 0;
|
|
2172
|
+
|
|
2173
|
+
// Сетка: берём то, что накапливается в state.board.grid через BoardService
|
|
2174
|
+
const gridState = (this.state?.state?.board && this.state.state.board.grid) ? this.state.state.board.grid : null;
|
|
2175
|
+
const gridSettings = (() => {
|
|
2176
|
+
if (gridState && gridState.type) {
|
|
2177
|
+
// Если храним полные options от serialize(), извлекаем ключевые
|
|
2178
|
+
const opts = gridState.options || {};
|
|
2179
|
+
// Унификация ключей под формат из задачи
|
|
2180
|
+
return {
|
|
2181
|
+
type: gridState.type,
|
|
2182
|
+
size: opts.size || 20,
|
|
2183
|
+
visible: opts.enabled !== false,
|
|
2184
|
+
color: toHex(opts.color ?? 0xE0E0E0)
|
|
2185
|
+
};
|
|
2186
|
+
}
|
|
2187
|
+
return null;
|
|
2188
|
+
})();
|
|
2189
|
+
|
|
2190
|
+
const settings = {
|
|
2191
|
+
backgroundColor: toHex(rendererBg ?? 0xF5F5F5),
|
|
2192
|
+
grid: gridSettings || undefined,
|
|
2193
|
+
zoom: { min: 0.1, max: 5.0, default: 1.0, current: currentZoom },
|
|
2194
|
+
canvas: { width: canvasW, height: canvasH }
|
|
2195
|
+
};
|
|
2196
|
+
|
|
2197
|
+
const boardId = (this.state?.state?.board && this.state.state.board.id) || this.options?.boardId || null;
|
|
2198
|
+
|
|
2199
|
+
return { id: boardId, boardData, settings };
|
|
2155
2200
|
}
|
|
2156
2201
|
|
|
2157
2202
|
/**
|
|
@@ -19,7 +19,7 @@ export class DataManager {
|
|
|
19
19
|
|
|
20
20
|
// Восстанавливаем тип сетки и её параметры до загрузки объектов
|
|
21
21
|
try {
|
|
22
|
-
const grid = data.grid || (data.board && data.board.grid);
|
|
22
|
+
const grid = (data.settings && data.settings.grid) || data.grid || (data.board && data.board.grid);
|
|
23
23
|
if (grid && grid.type) {
|
|
24
24
|
const payload = { type: grid.type };
|
|
25
25
|
const opts = grid.options || null;
|
|
@@ -29,6 +29,36 @@ export class DataManager {
|
|
|
29
29
|
this.coreMoodboard.eventBus.emit(this.coreMoodboard.Events?.UI?.GridChange || 'ui:grid:change', payload);
|
|
30
30
|
}
|
|
31
31
|
} catch (_) {}
|
|
32
|
+
|
|
33
|
+
// Восстановим фон и зум из settings, если есть
|
|
34
|
+
try {
|
|
35
|
+
const settings = data.settings || {};
|
|
36
|
+
// Фон
|
|
37
|
+
const bg = settings.backgroundColor;
|
|
38
|
+
if (bg && this.coreMoodboard?.pixi?.app?.renderer) {
|
|
39
|
+
const parseHex = (v) => {
|
|
40
|
+
if (typeof v === 'number') return v;
|
|
41
|
+
if (typeof v === 'string') {
|
|
42
|
+
const s = v.startsWith('#') ? v.slice(1) : v;
|
|
43
|
+
const n = parseInt(s, 16);
|
|
44
|
+
if (Number.isFinite(n)) return n;
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
};
|
|
48
|
+
const bgInt = parseHex(bg);
|
|
49
|
+
if (bgInt != null) this.coreMoodboard.pixi.app.renderer.backgroundColor = bgInt;
|
|
50
|
+
}
|
|
51
|
+
// Зум
|
|
52
|
+
const z = settings.zoom && (settings.zoom.current || settings.zoom.default);
|
|
53
|
+
const world = this.coreMoodboard?.pixi?.worldLayer || this.coreMoodboard?.pixi?.app?.stage;
|
|
54
|
+
if (world && Number.isFinite(z) && z > 0) {
|
|
55
|
+
world.scale.set(z);
|
|
56
|
+
const percent = Math.round(z * 100);
|
|
57
|
+
try {
|
|
58
|
+
this.coreMoodboard.eventBus.emit('ui:zoom:percent', { percentage: percent });
|
|
59
|
+
} catch (_) {}
|
|
60
|
+
}
|
|
61
|
+
} catch (_) {}
|
|
32
62
|
|
|
33
63
|
// Загружаем объекты
|
|
34
64
|
if (data.objects && Array.isArray(data.objects)) {
|