- fixed blue cell color after removing dynamic tag;
This commit is contained in:
@@ -24,6 +24,11 @@ const ElementSettingSpreadsheet = ({ value, name, setDataFn }) => {
|
||||
const isRestoringRef = useRef(false);
|
||||
const mousePos = useRef({ x: 0, y: 0 });
|
||||
const fileInputRef = useRef(null);
|
||||
const taggedCellsRef = useRef(new Set());
|
||||
const saveTimerRef = useRef(null);
|
||||
const setDataFnRef = useRef(setDataFn);
|
||||
|
||||
useEffect(() => { setDataFnRef.current = setDataFn; }, [setDataFn]);
|
||||
|
||||
const insertFieldTag = (ids, type, field) => {
|
||||
const api = univerAPIRef.current;
|
||||
@@ -63,7 +68,24 @@ const ElementSettingSpreadsheet = ({ value, name, setDataFn }) => {
|
||||
univerRef.current = univer;
|
||||
univerAPIRef.current = univerAPI;
|
||||
|
||||
// Restore tag cells whose display value was overwritten by raw tag on blur
|
||||
// Initialise tagged-cell tracking from the loaded workbook data
|
||||
const initialTagged = new Set();
|
||||
if (workbookData?.sheets) {
|
||||
const sid = workbookData.sheetOrder?.[0];
|
||||
const sd = sid ? workbookData.sheets[sid] : Object.values(workbookData.sheets)[0];
|
||||
if (sd?.cellData) {
|
||||
Object.entries(sd.cellData).forEach(([r, row]) =>
|
||||
Object.entries(row).forEach(([c, cell]) => {
|
||||
if (typeof cell.f === 'string' && TAG_RE.test(cell.f))
|
||||
initialTagged.add(`${r}:${c}`);
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
taggedCellsRef.current = initialTagged;
|
||||
|
||||
// Restore tag cells whose display value was overwritten by raw tag on blur;
|
||||
// also clear background for cells whose tag formula was removed.
|
||||
const restoreTagCells = () => {
|
||||
if (isRestoringRef.current) return;
|
||||
const wb = univerAPIRef.current?.getActiveWorkbook();
|
||||
@@ -76,6 +98,25 @@ const ElementSettingSpreadsheet = ({ value, name, setDataFn }) => {
|
||||
const sheetData = sheetId ? saved.sheets[sheetId] : Object.values(saved.sheets)[0];
|
||||
if (!sheetData?.cellData) return;
|
||||
|
||||
// Build set of cells that currently have a tag formula
|
||||
const currentlyTagged = new Set();
|
||||
Object.entries(sheetData.cellData).forEach(([r, row]) =>
|
||||
Object.entries(row).forEach(([c, cell]) => {
|
||||
if (typeof cell.f === 'string' && TAG_RE.test(cell.f))
|
||||
currentlyTagged.add(`${r}:${c}`);
|
||||
})
|
||||
);
|
||||
|
||||
// Cells that lost their tag formula → need background reset
|
||||
const cellsToDecolor = [];
|
||||
for (const key of taggedCellsRef.current) {
|
||||
if (!currentlyTagged.has(key)) {
|
||||
const [r, c] = key.split(':').map(Number);
|
||||
cellsToDecolor.push({ r, c });
|
||||
}
|
||||
}
|
||||
|
||||
// Cells whose displayed value was overwritten by raw formula text → restore
|
||||
const restorations = [];
|
||||
Object.entries(sheetData.cellData).forEach(([r, row]) => {
|
||||
Object.entries(row).forEach(([c, cell]) => {
|
||||
@@ -94,21 +135,33 @@ const ElementSettingSpreadsheet = ({ value, name, setDataFn }) => {
|
||||
});
|
||||
});
|
||||
|
||||
if (restorations.length === 0) return;
|
||||
if (restorations.length === 0 && cellsToDecolor.length === 0) {
|
||||
taggedCellsRef.current = currentlyTagged;
|
||||
return;
|
||||
}
|
||||
isRestoringRef.current = true;
|
||||
restorations.forEach(({ r, c, v, f }) => {
|
||||
sheet.getRange(r, c, 1, 1).setValues([[{ v, f }]]);
|
||||
});
|
||||
cellsToDecolor.forEach(({ r, c }) => {
|
||||
sheet.getRange(r, c, 1, 1).setBackground('');
|
||||
});
|
||||
isRestoringRef.current = false;
|
||||
taggedCellsRef.current = currentlyTagged;
|
||||
};
|
||||
|
||||
let restoreTimer;
|
||||
|
||||
// Disable adding new sheets; also schedule tag-cell restoration after each command
|
||||
// Disable adding new sheets; auto-save on every command; schedule tag restoration
|
||||
univerAPI.addEvent(univerAPI.Event.BeforeCommandExecute, (event) => {
|
||||
if (event.id === 'sheet.command.insert-sheet') {
|
||||
event.cancel = true;
|
||||
}
|
||||
clearTimeout(saveTimerRef.current);
|
||||
saveTimerRef.current = setTimeout(() => {
|
||||
const wb = univerAPIRef.current?.getActiveWorkbook();
|
||||
if (wb) setDataFnRef.current(name, wb.save());
|
||||
}, 300);
|
||||
clearTimeout(restoreTimer);
|
||||
restoreTimer = setTimeout(restoreTagCells, 80);
|
||||
});
|
||||
@@ -179,6 +232,7 @@ const ElementSettingSpreadsheet = ({ value, name, setDataFn }) => {
|
||||
initializeUniver(workbook);
|
||||
|
||||
return () => {
|
||||
clearTimeout(saveTimerRef.current);
|
||||
if (univerRef.current) {
|
||||
univerRef.current.dispose();
|
||||
univerRef.current = null;
|
||||
@@ -187,6 +241,22 @@ const ElementSettingSpreadsheet = ({ value, name, setDataFn }) => {
|
||||
};
|
||||
}, []); // run once on mount
|
||||
|
||||
// Flush workbook data to parent immediately when the user clicks outside the spreadsheet.
|
||||
// This runs in the capture phase — before the clicked element's own handler — so the
|
||||
// parent's store is up to date by the time any outer "Salva" button handler reads it.
|
||||
useEffect(() => {
|
||||
const container = containerRef.current;
|
||||
if (!container) return;
|
||||
const flushOnExternalClick = (e) => {
|
||||
if (container.contains(e.target)) return;
|
||||
clearTimeout(saveTimerRef.current);
|
||||
const wb = univerAPIRef.current?.getActiveWorkbook();
|
||||
if (wb) setDataFnRef.current(name, wb.save());
|
||||
};
|
||||
document.addEventListener('click', flushOnExternalClick, true);
|
||||
return () => document.removeEventListener('click', flushOnExternalClick, true);
|
||||
}, [name]); // name is stable ('template')
|
||||
|
||||
// Prevent page scroll while hovering over the spreadsheet
|
||||
useEffect(() => {
|
||||
const el = containerRef.current;
|
||||
|
||||
@@ -73,7 +73,11 @@ const BuilderElementSettings = ({ closeSettingsFn, callStatus, context }) => {
|
||||
|
||||
const saveSettings = () => {
|
||||
let newActiveElementData = klona(activeElementData);
|
||||
newActiveElementData = wrap(newActiveElementData).set(['settings'], settings).value();
|
||||
// Prefer the store value over React state: child components (e.g. ElementSettingSpreadsheet)
|
||||
// write to the store synchronously, but React state updates are batched and may lag behind
|
||||
// when saveSettings is called in the same event as the last setDataFn call.
|
||||
const latestSettings = storeGet('chosenFieldSettings') || settings;
|
||||
newActiveElementData = wrap(newActiveElementData).set(['settings'], latestSettings).value();
|
||||
newActiveElementData = wrap(newActiveElementData).set(['validators'], validators).value();
|
||||
newActiveElementData = wrap(newActiveElementData).set(['dynamicData'], dynamicData).value();
|
||||
newActiveElementData = wrap(newActiveElementData).set(['criteria'], criteria).value();
|
||||
|
||||
Reference in New Issue
Block a user