Skip to content

Commit c66ee09

Browse files
committed
fix: disable all relevant context menu buttons when readOnly (see #411)
1 parent 4b3af48 commit c66ee09

File tree

5 files changed

+59
-47
lines changed

5 files changed

+59
-47
lines changed

src/lib/components/modes/tablemode/TableMode.svelte

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -926,14 +926,17 @@
926926
const defaultItems: ContextMenuItem[] = createTableContextMenuItems({
927927
json,
928928
documentState,
929+
readOnly,
929930
parser,
930931
931932
onEditValue: handleEditValue,
932933
onEditRow: handleEditRow,
933934
onToggleEnforceString: handleToggleEnforceString,
935+
934936
onCut: handleCut,
935937
onCopy: handleCopy,
936938
onPaste: handlePasteFromMenu,
939+
937940
onRemove: handleRemove,
938941
onDuplicateRow: handleDuplicateRow,
939942
onInsertBeforeRow: handleInsertBeforeRow,

src/lib/components/modes/tablemode/contextmenu/createTableContextMenuItems.ts

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { getEnforceString } from '$lib/logic/documentState'
1919
export default function ({
2020
json,
2121
documentState,
22+
readOnly,
2223
parser,
2324
onEditValue,
2425
onEditRow,
@@ -34,6 +35,7 @@ export default function ({
3435
}: {
3536
json: unknown | undefined
3637
documentState: DocumentState
38+
readOnly: boolean
3739
parser: JSONParser
3840
onEditValue: () => void
3941
onEditRow: () => void
@@ -58,9 +60,11 @@ export default function ({
5860
hasJson &&
5961
(isMultiSelection(selection) || isKeySelection(selection) || isValueSelection(selection))
6062

61-
const canEditValue = hasJson && selection != null && singleItemSelected(selection)
63+
const canEditValue = !readOnly && hasJson && selection != null && singleItemSelected(selection)
6264
const canEnforceString = canEditValue && !isObjectOrArray(focusValue)
6365

66+
const canCut = !readOnly && hasSelectionContents
67+
6468
const enforceString =
6569
selection != null && focusValue !== undefined
6670
? getEnforceString(
@@ -118,7 +122,7 @@ export default function ({
118122
icon: faCut,
119123
text: 'Cut',
120124
title: 'Cut selected contents, formatted with indentation (Ctrl+X)',
121-
disabled: !hasSelectionContents
125+
disabled: !canCut
122126
},
123127
width: '10em',
124128
items: [
@@ -128,15 +132,15 @@ export default function ({
128132
text: 'Cut formatted',
129133
title: 'Cut selected contents, formatted with indentation (Ctrl+X)',
130134
onClick: () => onCut(true),
131-
disabled: !hasSelectionContents
135+
disabled: readOnly || !hasSelectionContents
132136
},
133137
{
134138
type: 'button',
135139
icon: faCut,
136140
text: 'Cut compacted',
137141
title: 'Cut selected contents, without indentation (Ctrl+Shift+X)',
138142
onClick: () => onCut(false),
139-
disabled: !hasSelectionContents
143+
disabled: readOnly || !hasSelectionContents
140144
}
141145
]
142146
},
@@ -176,15 +180,15 @@ export default function ({
176180
icon: faPaste,
177181
text: 'Paste',
178182
title: 'Paste clipboard contents (Ctrl+V)',
179-
disabled: !hasSelection
183+
disabled: readOnly || !hasSelection
180184
},
181185
{
182186
type: 'button',
183187
onClick: () => onRemove(),
184188
icon: faTrashCan,
185189
text: 'Remove',
186190
title: 'Remove selected contents (Delete)',
187-
disabled: !hasSelectionContents
191+
disabled: readOnly || !hasSelectionContents
188192
}
189193
]
190194
},
@@ -198,39 +202,39 @@ export default function ({
198202
icon: faPen,
199203
text: 'Edit row',
200204
title: 'Edit the current row',
201-
disabled: !hasSelectionContents
205+
disabled: readOnly || !hasSelectionContents
202206
},
203207
{
204208
type: 'button',
205209
onClick: () => onDuplicateRow(),
206210
icon: faClone,
207211
text: 'Duplicate row',
208212
title: 'Duplicate the current row',
209-
disabled: !hasSelection
213+
disabled: readOnly || !hasSelection
210214
},
211215
{
212216
type: 'button',
213217
onClick: () => onInsertBeforeRow(),
214218
icon: faPlus,
215219
text: 'Insert before',
216220
title: 'Insert a row before the current row',
217-
disabled: !hasSelection
221+
disabled: readOnly || !hasSelection
218222
},
219223
{
220224
type: 'button',
221225
onClick: () => onInsertAfterRow(),
222226
icon: faPlus,
223227
text: 'Insert after',
224228
title: 'Insert a row after the current row',
225-
disabled: !hasSelection
229+
disabled: readOnly || !hasSelection
226230
},
227231
{
228232
type: 'button',
229233
onClick: () => onRemoveRow(),
230234
icon: faTrashCan,
231235
text: 'Remove row',
232236
title: 'Remove current row',
233-
disabled: !hasSelection
237+
disabled: readOnly || !hasSelection
234238
}
235239
]
236240
}

src/lib/components/modes/treemode/TreeMode.svelte

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1811,6 +1811,7 @@
18111811
const defaultItems: ContextMenuItem[] = createTreeContextMenuItems({
18121812
json,
18131813
documentState,
1814+
readOnly,
18141815
parser,
18151816
18161817
onEditKey: handleEditKey,

src/lib/components/modes/treemode/contextmenu/createTreeContextMenuItems.ts

Lines changed: 39 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import {
2323
isValueSelection,
2424
singleItemSelected
2525
} from '$lib/logic/selection'
26-
import type { DocumentState, InsertType, JSONParser } from 'svelte-jsoneditor'
26+
import type { ConvertType, DocumentState, InsertType, JSONParser } from '$lib/types'
2727
import { initial, isEmpty } from 'lodash-es'
2828
import { compileJSONPointer, getIn } from 'immutable-json-patch'
2929
import { isObjectOrArray, isObject } from '$lib/utils/typeUtils'
@@ -33,8 +33,8 @@ import type { ContextMenuItem } from 'svelte-jsoneditor'
3333
export default function ({
3434
json,
3535
documentState,
36+
readOnly,
3637
parser,
37-
3838
onEditKey,
3939
onEditValue,
4040
onToggleEnforceString,
@@ -53,8 +53,8 @@ export default function ({
5353
}: {
5454
json: unknown
5555
documentState: DocumentState
56+
readOnly: boolean
5657
parser: JSONParser
57-
5858
onEditKey: () => void
5959
onEditValue: () => void
6060
onToggleEnforceString: () => void
@@ -66,7 +66,7 @@ export default function ({
6666
onExtract: () => void
6767
onInsertBefore: () => void
6868
onInsert: (type: InsertType) => void
69-
onConvert: (type: InsertType) => void
69+
onConvert: (type: ConvertType) => void
7070
onInsertAfter: () => void
7171
onSort: () => void
7272
onTransform: () => void
@@ -87,36 +87,38 @@ export default function ({
8787
hasJson &&
8888
(isMultiSelection(selection) || isKeySelection(selection) || isValueSelection(selection))
8989

90-
const canDuplicate = hasJson && hasSelectionContents && !rootSelected // must not be root
91-
const canExtract =
92-
hasJson &&
93-
selection != null &&
94-
(isMultiSelection(selection) || isValueSelection(selection)) &&
95-
!rootSelected // must not be root
96-
9790
const canEditKey =
91+
!readOnly &&
9892
hasJson &&
9993
selection != null &&
10094
singleItemSelected(selection) &&
10195
!rootSelected &&
10296
!Array.isArray(getIn(json, initial(getFocusPath(selection))))
10397

104-
const canEditValue = hasJson && selection != null && singleItemSelected(selection)
98+
const canEditValue = !readOnly && hasJson && selection != null && singleItemSelected(selection)
10599
const canEnforceString = canEditValue && !isObjectOrArray(focusValue)
106100

101+
const canCut = !readOnly && hasSelectionContents
102+
const canCopy = hasSelectionContents
103+
const canPaste = !readOnly && hasSelection
104+
const canDuplicate = !readOnly && hasJson && hasSelectionContents && !rootSelected // must not be root
105+
const canExtract =
106+
!readOnly &&
107+
hasJson &&
108+
selection != null &&
109+
(isMultiSelection(selection) || isValueSelection(selection)) &&
110+
!rootSelected // must not be root
111+
107112
const convertMode = hasSelectionContents
108113
const insertOrConvertText = convertMode ? 'Convert to:' : 'Insert:'
109114

110-
const canInsertOrConvertStructure = convertMode ? false : hasSelection
111-
const canInsertOrConvertObject = convertMode
112-
? canConvert(selection) && !isObject(focusValue)
113-
: hasSelection
114-
const canInsertOrConvertArray = convertMode
115-
? canConvert(selection) && !Array.isArray(focusValue)
116-
: hasSelection
117-
const canInsertOrConvertValue = convertMode
118-
? canConvert(selection) && isObjectOrArray(focusValue)
119-
: hasSelection
115+
const canInsertOrConvertStructure = readOnly || convertMode ? false : hasSelection
116+
const canInsertOrConvertObject =
117+
!readOnly && (convertMode ? canConvert(selection) && !isObject(focusValue) : hasSelection)
118+
const canInsertOrConvertArray =
119+
!readOnly && (convertMode ? canConvert(selection) && !Array.isArray(focusValue) : hasSelection)
120+
const canInsertOrConvertValue =
121+
!readOnly && (convertMode ? canConvert(selection) && isObjectOrArray(focusValue) : hasSelection)
120122

121123
const enforceString =
122124
selection != null && focusValue
@@ -130,7 +132,9 @@ export default function ({
130132

131133
function handleInsertOrConvert(type: InsertType) {
132134
if (hasSelectionContents) {
133-
onConvert(type)
135+
if (type !== 'structure') {
136+
onConvert(type)
137+
}
134138
} else {
135139
onInsert(type)
136140
}
@@ -192,7 +196,7 @@ export default function ({
192196
icon: faCut,
193197
text: 'Cut',
194198
title: 'Cut selected contents, formatted with indentation (Ctrl+X)',
195-
disabled: !hasSelectionContents
199+
disabled: !canCut
196200
},
197201
width: '10em',
198202
items: [
@@ -202,15 +206,15 @@ export default function ({
202206
text: 'Cut formatted',
203207
title: 'Cut selected contents, formatted with indentation (Ctrl+X)',
204208
onClick: () => onCut(true),
205-
disabled: !hasSelectionContents
209+
disabled: !canCut
206210
},
207211
{
208212
type: 'button',
209213
icon: faCut,
210214
text: 'Cut compacted',
211215
title: 'Cut selected contents, without indentation (Ctrl+Shift+X)',
212216
onClick: () => onCut(false),
213-
disabled: !hasSelectionContents
217+
disabled: !canCut
214218
}
215219
]
216220
},
@@ -222,7 +226,7 @@ export default function ({
222226
icon: faCopy,
223227
text: 'Copy',
224228
title: 'Copy selected contents, formatted with indentation (Ctrl+C)',
225-
disabled: !hasSelectionContents
229+
disabled: !canCopy
226230
},
227231
width: '12em',
228232
items: [
@@ -232,15 +236,15 @@ export default function ({
232236
text: 'Copy formatted',
233237
title: 'Copy selected contents, formatted with indentation (Ctrl+C)',
234238
onClick: () => onCopy(true),
235-
disabled: !hasSelectionContents
239+
disabled: !canCopy
236240
},
237241
{
238242
type: 'button',
239243
icon: faCopy,
240244
text: 'Copy compacted',
241245
title: 'Copy selected contents, without indentation (Ctrl+Shift+C)',
242246
onClick: () => onCopy(false),
243-
disabled: !hasSelectionContents
247+
disabled: !canCopy
244248
}
245249
]
246250
},
@@ -250,7 +254,7 @@ export default function ({
250254
icon: faPaste,
251255
text: 'Paste',
252256
title: 'Paste clipboard contents (Ctrl+V)',
253-
disabled: !hasSelection
257+
disabled: !canPaste
254258
}
255259
]
256260
},
@@ -283,23 +287,23 @@ export default function ({
283287
icon: faSortAmountDownAlt,
284288
text: 'Sort',
285289
title: 'Sort array or object contents',
286-
disabled: !hasSelectionContents
290+
disabled: readOnly || !hasSelectionContents
287291
},
288292
{
289293
type: 'button',
290294
onClick: () => onTransform(),
291295
icon: faFilter,
292296
text: 'Transform',
293297
title: 'Transform array or object contents (filter, sort, project)',
294-
disabled: !hasSelectionContents
298+
disabled: readOnly || !hasSelectionContents
295299
},
296300
{
297301
type: 'button',
298302
onClick: () => onRemove(),
299303
icon: faTrashCan,
300304
text: 'Remove',
301305
title: 'Remove selected contents (Delete)',
302-
disabled: !hasSelectionContents
306+
disabled: readOnly || !hasSelectionContents
303307
}
304308
]
305309
},
@@ -355,15 +359,15 @@ export default function ({
355359
icon: faCaretSquareUp,
356360
text: 'Insert before',
357361
title: 'Select area before current entry to insert or paste contents',
358-
disabled: !hasSelectionContents || rootSelected
362+
disabled: readOnly || !hasSelectionContents || rootSelected
359363
},
360364
{
361365
type: 'button',
362366
onClick: () => onInsertAfter(),
363367
icon: faCaretSquareDown,
364368
text: 'Insert after',
365369
title: 'Select area after current entry to insert or paste contents',
366-
disabled: !hasSelectionContents || rootSelected
370+
disabled: readOnly || !hasSelectionContents || rootSelected
367371
}
368372
]
369373
}

src/routes/development/+page.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@
381381
382382
function onRenderContextMenu(items: ContextMenuItem[], context: RenderMenuContext) {
383383
console.log('onRenderContextMenu', items, context)
384-
return context.readOnly ? false : items // This return is equivalent to onRenderContextMenu is undefined
384+
return items // This return is equivalent to onRenderContextMenu is undefined
385385
}
386386
387387
function openInWindow() {

0 commit comments

Comments
 (0)