Skip to content

Commit 697e799

Browse files
fix: disable table resizing UI in viewing mode (#2403)
* fix: disable table resizing UI in viewing mode * fix: suppress table overlay on viewing clicks
1 parent 33e2ce6 commit 697e799

4 files changed

Lines changed: 147 additions & 2 deletions

File tree

packages/super-editor/src/components/SuperEditor.test.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ vi.mock('./toolbar/LinkInput.vue', () => ({
4848
default: { name: 'LinkInput', render: () => null },
4949
}));
5050

51+
vi.mock('./TableResizeOverlay.vue', () => ({
52+
default: { name: 'TableResizeOverlay', render: () => null },
53+
}));
54+
5155
vi.mock('@superdoc/common', () => ({
5256
getFileObject: getFileObjectMock,
5357
}));
@@ -1244,5 +1248,56 @@ describe('SuperEditor.vue', () => {
12441248
wrapper.unmount();
12451249
vi.useRealTimers();
12461250
});
1251+
1252+
describe('table overlay click guard', () => {
1253+
it('should suppress overlay updates when clicking in viewing mode', async () => {
1254+
vi.useFakeTimers();
1255+
EditorConstructor.loadXmlData.mockResolvedValueOnce(['<docx />', {}, {}, {}]);
1256+
1257+
const wrapper = mount(SuperEditor, {
1258+
props: {
1259+
documentId: 'doc-click-guard',
1260+
options: {},
1261+
},
1262+
});
1263+
1264+
await flushPromises();
1265+
1266+
await flushPromises();
1267+
1268+
const updateSpy = vi.spyOn(wrapper.vm, 'updateTableResizeOverlay');
1269+
// Force viewing mode
1270+
Object.defineProperty(wrapper.vm, 'activeEditor', {
1271+
value: {
1272+
value: {
1273+
options: { documentMode: 'viewing' },
1274+
isEditable: false,
1275+
view: { focus: vi.fn() },
1276+
},
1277+
},
1278+
});
1279+
wrapper.vm.getDocumentMode = () => 'viewing';
1280+
wrapper.vm.isViewingMode = () => true;
1281+
1282+
wrapper.vm.tableResizeState.visible = true;
1283+
wrapper.vm.tableResizeState.tableElement = { foo: 'bar' };
1284+
wrapper.vm.editorElem.value = {
1285+
querySelector: () => ({
1286+
contains: () => false,
1287+
}),
1288+
};
1289+
1290+
const event = new MouseEvent('click');
1291+
Object.defineProperty(event, 'stopPropagation', { value: vi.fn() });
1292+
Object.defineProperty(event, 'preventDefault', { value: vi.fn() });
1293+
1294+
wrapper.vm.handleSuperEditorClick(event);
1295+
1296+
expect(updateSpy).not.toHaveBeenCalled();
1297+
1298+
wrapper.unmount();
1299+
vi.useRealTimers();
1300+
});
1301+
});
12471302
});
12481303
});

packages/super-editor/src/components/SuperEditor.vue

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -721,8 +721,20 @@ const setSelectedImage = (element, blockId, pmStart) => {
721721
/**
722722
* Combined handler to update both table and image resize overlays
723723
*/
724+
const getDocumentMode = () => {
725+
if (activeEditor.value?.options?.documentMode) return activeEditor.value.options.documentMode;
726+
if (props.options?.documentMode) return props.options.documentMode;
727+
return 'editing';
728+
};
729+
730+
const isViewingMode = () => getDocumentMode() === 'viewing';
731+
724732
const handleOverlayUpdates = (event) => {
725-
updateTableResizeOverlay(event);
733+
if (isViewingMode()) {
734+
hideTableResizeOverlay();
735+
} else {
736+
updateTableResizeOverlay(event);
737+
}
726738
updateImageResizeOverlay(event);
727739
};
728740
@@ -1036,7 +1048,11 @@ const handleSuperEditorClick = (event) => {
10361048
}
10371049
10381050
// Update table resize overlay on click
1039-
updateTableResizeOverlay(event);
1051+
if (isViewingMode()) {
1052+
hideTableResizeOverlay();
1053+
} else {
1054+
updateTableResizeOverlay(event);
1055+
}
10401056
};
10411057
10421058
onMounted(() => {

packages/super-editor/src/components/TableResizeOverlay.test.js

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,71 @@ describe('TableResizeOverlay', () => {
740740
});
741741
});
742742

743+
// ==========================================================================
744+
// Viewing Mode Guard Tests
745+
// ==========================================================================
746+
747+
describe('Viewing mode restrictions', () => {
748+
it('should ignore column handle drags when documentMode is viewing', async () => {
749+
const tableElement = createMockTableElement();
750+
751+
const wrapper = mount(TableResizeOverlay, {
752+
props: {
753+
editor: createMockEditor({ options: { documentMode: 'viewing' } }),
754+
visible: true,
755+
tableElement,
756+
},
757+
});
758+
759+
await nextTick();
760+
761+
const event = new MouseEvent('mousedown', { clientX: 100, clientY: 50 });
762+
Object.defineProperty(event, 'preventDefault', { value: vi.fn() });
763+
Object.defineProperty(event, 'stopPropagation', { value: vi.fn() });
764+
765+
wrapper.vm.onHandleMouseDown(event, 0);
766+
767+
expect(wrapper.vm.dragState).toBeNull();
768+
expect(wrapper.emitted('resize-start')).toBeUndefined();
769+
770+
wrapper.unmount();
771+
});
772+
773+
it('should ignore row handle drags when documentMode is viewing', async () => {
774+
const tableElement = createMockTableElement({
775+
columns: [
776+
{ i: 0, x: 0, w: 100, min: 50, r: 1 },
777+
{ i: 1, x: 100, w: 150, min: 50, r: 1 },
778+
],
779+
rows: [
780+
{ i: 0, y: 0, h: 50, min: 30, r: 1 },
781+
{ i: 1, y: 50, h: 50, min: 30, r: 1 },
782+
],
783+
});
784+
785+
const wrapper = mount(TableResizeOverlay, {
786+
props: {
787+
editor: createMockEditor({ options: { documentMode: 'viewing' } }),
788+
visible: true,
789+
tableElement,
790+
},
791+
});
792+
793+
await nextTick();
794+
795+
const event = new MouseEvent('mousedown', { clientX: 100, clientY: 50 });
796+
Object.defineProperty(event, 'preventDefault', { value: vi.fn() });
797+
Object.defineProperty(event, 'stopPropagation', { value: vi.fn() });
798+
799+
wrapper.vm.onRowHandleMouseDown(event, 0);
800+
801+
expect(wrapper.vm.rowDragState).toBeNull();
802+
expect(wrapper.emitted('resize-start')).toBeUndefined();
803+
804+
wrapper.unmount();
805+
});
806+
});
807+
743808
// ==========================================================================
744809
// Overlay Rect Tests
745810
// ==========================================================================

packages/super-editor/src/components/TableResizeOverlay.vue

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ const emit = defineEmits(['resize-start', 'resize-move', 'resize-end', 'resize-s
7878
7979
const overlayEl = ref(null);
8080
const overlayRect = ref(null);
81+
const isViewingMode = () => props.editor?.options?.documentMode === 'viewing';
8182
/**
8283
* Parsed table metadata from data-table-boundaries attribute
8384
* @type {import('vue').Ref<{columns: Array<{i: number, x: number, w: number, min: number, r?: number}>} | null>}
@@ -727,6 +728,10 @@ function onHandleMouseDown(event, resizableBoundaryIndex) {
727728
event.preventDefault();
728729
event.stopPropagation();
729730
731+
if (isViewingMode()) {
732+
return;
733+
}
734+
730735
if (!tableMetadata.value?.columns) return;
731736
732737
const boundary = resizableBoundaries.value[resizableBoundaryIndex];
@@ -1115,6 +1120,10 @@ function onRowHandleMouseDown(event, rowBoundaryIndex) {
11151120
event.preventDefault();
11161121
event.stopPropagation();
11171122
1123+
if (isViewingMode()) {
1124+
return;
1125+
}
1126+
11181127
const rowBoundary = resizableRowBoundaries.value[rowBoundaryIndex];
11191128
if (!rowBoundary) return;
11201129

0 commit comments

Comments
 (0)