dazscript-framework 0.2.4 → 0.3.1
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/README.md +94 -4
- package/dist/scripts/app-data-path.js +50 -0
- package/dist/scripts/cli.js +63 -0
- package/dist/scripts/init.js +13 -0
- package/dist/scripts/install-generator.js +54 -43
- package/dist/scripts/launchers.js +121 -0
- package/package.json +2 -1
- package/src/{Install.dsa.ts → Setup.dsa.ts} +3 -3
- package/src/helpers/action-helper.ts +14 -1
- package/src/helpers/custom-action-helper.ts +375 -84
- package/src/helpers/custom-action-installer-helper.ts +332 -0
- package/src/shared/set-keyboard-shortcut.ts +29 -5
- package/webpack.config.js +33 -0
- package/src/Uninstall.dsa.ts +0 -19
|
@@ -37,7 +37,7 @@ const shortcutTokenMap: { [key: string]: string } = {
|
|
|
37
37
|
'DOWN': 'Down',
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
const normalizeShortcut = (shortcut: string): string => {
|
|
40
|
+
export const normalizeShortcut = (shortcut: string): string => {
|
|
41
41
|
if (!shortcut) return ''
|
|
42
42
|
|
|
43
43
|
return shortcut
|
|
@@ -53,6 +53,19 @@ const normalizeShortcut = (shortcut: string): string => {
|
|
|
53
53
|
.join('+')
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
export const getActionShortcut = (name: string): string => {
|
|
57
|
+
const action = findAction(name)
|
|
58
|
+
if (!action) return ''
|
|
59
|
+
|
|
60
|
+
if (isCustomAction(action)) {
|
|
61
|
+
const index = actionMgr.findCustomAction(name)
|
|
62
|
+
if (index < 0) return ''
|
|
63
|
+
return normalizeShortcut(String(actionMgr.getCustomActionShortcut(index) ?? '').trim())
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return normalizeShortcut(String(action.shortcut?.toString() ?? '').trim())
|
|
67
|
+
}
|
|
68
|
+
|
|
56
69
|
type ActionShortcutEntry = {
|
|
57
70
|
action: DzAction
|
|
58
71
|
shortcut: string
|
|
@@ -2,52 +2,195 @@ import { debug } from '@dsf/common/log'
|
|
|
2
2
|
import { CustomAction } from '@dsf/core/custom-action'
|
|
3
3
|
import { mainWindow } from '@dsf/core/global'
|
|
4
4
|
import * as array from '@dsf/helpers/array-helper'
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { progress } from './progress-helper'
|
|
5
|
+
import { keys } from '@dsf/helpers/object-helper'
|
|
6
|
+
import { progress } from '@dsf/helpers/progress-helper'
|
|
8
7
|
import { getScriptPath } from './script-helper'
|
|
8
|
+
import { getMenu } from './menu-helper'
|
|
9
9
|
|
|
10
10
|
const actionMgr = mainWindow.getActionMgr()
|
|
11
11
|
const paneMgr = mainWindow.getPaneMgr()
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
const normalizePath = (value: string | null | undefined): string => {
|
|
14
|
+
if (!value) return ''
|
|
15
|
+
|
|
16
|
+
return String(value)
|
|
17
|
+
.replace(/\\/g, '/')
|
|
18
|
+
.replace(/\/+/g, '/')
|
|
19
|
+
.replace(/\/$/, '')
|
|
20
|
+
.toLowerCase()
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const getFileName = (value: string | null | undefined): string => {
|
|
24
|
+
const normalized = normalizePath(value)
|
|
25
|
+
if (!normalized) return ''
|
|
26
|
+
const parts = normalized.split('/')
|
|
27
|
+
return parts[parts.length - 1] ?? ''
|
|
28
|
+
}
|
|
17
29
|
|
|
18
|
-
|
|
30
|
+
const getTrailingPathSegments = (value: string | null | undefined, segmentCount: number): string => {
|
|
31
|
+
const normalized = normalizePath(value)
|
|
32
|
+
if (!normalized) return ''
|
|
19
33
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
var desc = actionMgr.getCustomActionDesc(i)
|
|
23
|
-
var icon = actionMgr.getCustomActionIcon(i)
|
|
34
|
+
const segments = normalized.split('/').filter(Boolean)
|
|
35
|
+
if (segments.length === 0) return ''
|
|
24
36
|
|
|
25
|
-
|
|
37
|
+
return segments.slice(Math.max(segments.length - segmentCount, 0)).join('/')
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const getStablePathSuffixes = (action: CustomAction, filePath: string): string[] => {
|
|
41
|
+
const suffixes: string[] = []
|
|
42
|
+
const seen: Record<string, true> = {}
|
|
43
|
+
|
|
44
|
+
const addSuffixes = (value: string | null | undefined) => {
|
|
45
|
+
const normalized = normalizePath(value)
|
|
46
|
+
if (!normalized) return
|
|
47
|
+
|
|
48
|
+
const segments = normalized.split('/').filter(Boolean)
|
|
49
|
+
for (let segmentCount = segments.length; segmentCount >= 1; segmentCount -= 1) {
|
|
50
|
+
const suffix = segments.slice(segments.length - segmentCount).join('/')
|
|
51
|
+
if (!suffix || seen[suffix]) continue
|
|
52
|
+
seen[suffix] = true
|
|
53
|
+
suffixes.push(suffix)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
addSuffixes(filePath)
|
|
58
|
+
addSuffixes(action.filePath)
|
|
59
|
+
return suffixes
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const pathEndsWithSegments = (filePath: string | null | undefined, trailingSegments: string): boolean => {
|
|
63
|
+
const normalized = normalizePath(filePath)
|
|
64
|
+
if (!normalized || !trailingSegments) return false
|
|
65
|
+
return normalized === trailingSegments || normalized.endsWith(`/${trailingSegments}`)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export type CustomActionInstallState = {
|
|
69
|
+
action: CustomAction
|
|
70
|
+
customAction: CustomAction | null
|
|
71
|
+
installedMenu: boolean
|
|
72
|
+
installedToolbar: boolean
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export type CustomActionTargets = {
|
|
76
|
+
menu: boolean
|
|
77
|
+
toolbar: boolean
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
type CustomActionCandidate = {
|
|
81
|
+
name: string
|
|
82
|
+
text: string
|
|
83
|
+
description: string
|
|
84
|
+
filePath: string
|
|
85
|
+
icon: string
|
|
86
|
+
shortcut: string
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const cloneAction = (action: CustomAction): CustomAction => ({
|
|
90
|
+
...action,
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
const resolveActionPaths = (action: CustomAction, scriptsPath: string = getScriptPath()): CustomAction => ({
|
|
94
|
+
...action,
|
|
95
|
+
filePath: `${scriptsPath}/${action.filePath}`,
|
|
96
|
+
icon: action.icon ? `${scriptsPath}/${action.icon}` : ''
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
const getCustomActionCandidates = (action: CustomAction): CustomActionCandidate[] => {
|
|
100
|
+
const candidates: CustomActionCandidate[] = []
|
|
101
|
+
const actionsCount = actionMgr.getNumCustomActions()
|
|
102
|
+
|
|
103
|
+
for (let i = 0; i < actionsCount; i++) {
|
|
104
|
+
const actionFilePath = actionMgr.getCustomActionFile(i)
|
|
105
|
+
const name = actionMgr.getCustomActionName(i)
|
|
106
|
+
const text = actionMgr.getCustomActionText(i)
|
|
107
|
+
const desc = actionMgr.getCustomActionDesc(i)
|
|
108
|
+
const icon = actionMgr.getCustomActionIcon(i)
|
|
109
|
+
|
|
110
|
+
candidates.push({
|
|
26
111
|
name: name.toString(),
|
|
27
112
|
text: text.toString(),
|
|
28
113
|
description: desc.toString(),
|
|
29
114
|
filePath: actionFilePath.toString(),
|
|
30
115
|
icon: icon.toString(),
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
shortcut: action.shortcut,
|
|
34
|
-
sort: action.sort,
|
|
35
|
-
toolbar: action.toolbar
|
|
36
|
-
} as CustomAction
|
|
116
|
+
shortcut: String(actionMgr.getCustomActionShortcut(i) ?? '').trim()
|
|
117
|
+
})
|
|
37
118
|
}
|
|
38
119
|
|
|
39
|
-
return
|
|
120
|
+
return candidates
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const toCustomAction = (candidate: CustomActionCandidate, action: CustomAction): CustomAction => ({
|
|
124
|
+
name: candidate.name,
|
|
125
|
+
text: candidate.text,
|
|
126
|
+
description: candidate.description,
|
|
127
|
+
filePath: candidate.filePath,
|
|
128
|
+
icon: candidate.icon,
|
|
129
|
+
shortcut: candidate.shortcut,
|
|
130
|
+
menuPath: action.menuPath,
|
|
131
|
+
group: action.group,
|
|
132
|
+
sort: action.sort,
|
|
133
|
+
toolbar: action.toolbar
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
const filterUniqueBy = (candidates: CustomActionCandidate[], predicate: (candidate: CustomActionCandidate) => boolean): CustomActionCandidate[] => {
|
|
137
|
+
const matches = candidates.filter(predicate)
|
|
138
|
+
return matches.length === 1 ? matches : []
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const findByPathHeuristics = (action: CustomAction, filePath: string): CustomActionCandidate[] => {
|
|
142
|
+
const candidates = getCustomActionCandidates(action)
|
|
143
|
+
const normalizedTarget = normalizePath(filePath)
|
|
144
|
+
|
|
145
|
+
const exactMatches = filterUniqueBy(candidates, candidate => normalizePath(candidate.filePath) === normalizedTarget)
|
|
146
|
+
if (exactMatches.length > 0) return exactMatches
|
|
147
|
+
|
|
148
|
+
const stableSuffixes = getStablePathSuffixes(action, filePath)
|
|
149
|
+
for (const trailingSegments of stableSuffixes) {
|
|
150
|
+
if (!trailingSegments) continue
|
|
151
|
+
|
|
152
|
+
const suffixMatches = filterUniqueBy(candidates, candidate => pathEndsWithSegments(candidate.filePath, trailingSegments))
|
|
153
|
+
if (suffixMatches.length > 0) return suffixMatches
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const expectedFileName = getFileName(filePath)
|
|
157
|
+
if (action.menuPath) {
|
|
158
|
+
const menuMatches = filterUniqueBy(candidates, candidate =>
|
|
159
|
+
getFileName(candidate.filePath) === expectedFileName &&
|
|
160
|
+
normalizePath(String(findMenuFor(candidate.name, actionMgr.getMenu())?.getPath() ?? '')) === normalizePath(action.menuPath)
|
|
161
|
+
)
|
|
162
|
+
if (menuMatches.length > 0) return menuMatches
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (action.toolbar) {
|
|
166
|
+
const toolbarMatches = filterUniqueBy(candidates, candidate =>
|
|
167
|
+
getFileName(candidate.filePath) === expectedFileName &&
|
|
168
|
+
isInstalledToToolbar(action.toolbar, candidate.name)
|
|
169
|
+
)
|
|
170
|
+
if (toolbarMatches.length > 0) return toolbarMatches
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return []
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export const findAllByFilePath = (action: CustomAction, filePath: string): CustomAction[] => {
|
|
177
|
+
return findByPathHeuristics(action, filePath).map(candidate => toCustomAction(candidate, action))
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export const findByFilePath = (action: CustomAction, filePath: string): CustomAction | null => {
|
|
181
|
+
const matches = findAllByFilePath(action, filePath)
|
|
182
|
+
return matches.length > 0 ? matches[0] : null
|
|
40
183
|
}
|
|
41
184
|
|
|
42
185
|
export const findMenuFor = (actionName: string, topMenu?: DzActionMenu): DzActionMenu | null => {
|
|
43
186
|
topMenu = topMenu ?? actionMgr.getMenu()
|
|
44
187
|
if (!topMenu.hasItems()) return null
|
|
45
188
|
for (let i = 0; i < topMenu.getNumItems(); i++) {
|
|
46
|
-
|
|
189
|
+
const item = topMenu.getItem(i)
|
|
47
190
|
if (item.type == DzActionMenuItem.CustomAction && item.action == actionName)
|
|
48
191
|
return item.getParentMenu()
|
|
49
192
|
if (item.type == DzActionMenuItem.SubMenu) {
|
|
50
|
-
|
|
193
|
+
const subMenu = findMenuFor(actionName, item.getSubMenu())
|
|
51
194
|
if (subMenu) return subMenu
|
|
52
195
|
}
|
|
53
196
|
}
|
|
@@ -55,11 +198,9 @@ export const findMenuFor = (actionName: string, topMenu?: DzActionMenu): DzActio
|
|
|
55
198
|
}
|
|
56
199
|
|
|
57
200
|
export const findInMenu = (menu: DzActionMenu, actionName: string): DzActionMenuItem | null => {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
for (var i = 0; i < aItems.length; i += 1) {
|
|
62
|
-
item = aItems[i]
|
|
201
|
+
const items = menu.getItemList()
|
|
202
|
+
for (let i = 0; i < items.length; i += 1) {
|
|
203
|
+
const item = items[i]
|
|
63
204
|
|
|
64
205
|
if (item.type != DzActionMenuItem.CustomAction) {
|
|
65
206
|
continue
|
|
@@ -73,91 +214,230 @@ export const findInMenu = (menu: DzActionMenu, actionName: string): DzActionMenu
|
|
|
73
214
|
return null
|
|
74
215
|
}
|
|
75
216
|
|
|
76
|
-
|
|
77
|
-
|
|
217
|
+
const findToolbarItemIndex = (toolbar: DzToolBar, actionName: string): number => {
|
|
218
|
+
const toolbarItems = toolbar.getItemList()
|
|
219
|
+
for (let i = 0; i < toolbarItems.length; i++) {
|
|
220
|
+
const item = toolbarItems[i]
|
|
221
|
+
if (item.type !== DzToolBarItem.CustomAction) continue
|
|
222
|
+
if (item.action !== actionName) continue
|
|
223
|
+
return i
|
|
224
|
+
}
|
|
225
|
+
return -1
|
|
226
|
+
}
|
|
78
227
|
|
|
79
|
-
|
|
228
|
+
const findToolbarItem = (toolbarName: string, actionName: string): DzToolBarItem | null => {
|
|
229
|
+
const toolbar = paneMgr.findToolBar(toolbarName)
|
|
230
|
+
if (!toolbar) return null
|
|
80
231
|
|
|
81
|
-
|
|
82
|
-
|
|
232
|
+
const toolbarItems = toolbar.getItemList()
|
|
233
|
+
for (let i = 0; i < toolbarItems.length; i++) {
|
|
234
|
+
const item = toolbarItems[i]
|
|
235
|
+
if (item.type !== DzToolBarItem.CustomAction) continue
|
|
236
|
+
if (item.action !== actionName) continue
|
|
237
|
+
return item
|
|
83
238
|
}
|
|
84
239
|
|
|
85
|
-
|
|
86
|
-
|
|
240
|
+
return null
|
|
241
|
+
}
|
|
87
242
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
243
|
+
const isInstalledToToolbar = (toolbarName: string | null | undefined, actionName: string | null | undefined): boolean => {
|
|
244
|
+
if (!toolbarName || !actionName) return false
|
|
245
|
+
return findToolbarItem(toolbarName, actionName) !== null
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const removeFromMenu = (actionName: string | null | undefined) => {
|
|
249
|
+
if (!actionName) return
|
|
250
|
+
const menu = findMenuFor(actionName, actionMgr.getMenu())
|
|
251
|
+
if (!menu) return
|
|
92
252
|
|
|
93
|
-
|
|
94
|
-
|
|
253
|
+
const menuAction = findInMenu(menu, actionName)
|
|
254
|
+
if (!menuAction) return
|
|
255
|
+
|
|
256
|
+
menu.removeItem(menuAction)
|
|
257
|
+
debug(`Action ${actionName} removed from menu`)
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const removeFromToolbar = (toolbarName: string | null | undefined, actionName: string | null | undefined) => {
|
|
261
|
+
if (!toolbarName || !actionName) return
|
|
262
|
+
const toolbar = paneMgr.findToolBar(toolbarName)
|
|
263
|
+
if (!toolbar) return
|
|
264
|
+
|
|
265
|
+
const itemIndex = findToolbarItemIndex(toolbar, actionName)
|
|
266
|
+
if (itemIndex < 0) return
|
|
267
|
+
|
|
268
|
+
toolbar.removeItem(itemIndex)
|
|
269
|
+
debug(`Action ${actionName} removed from toolbar ${toolbarName} (index ${itemIndex})`)
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const removeUnderlyingCustomAction = (actionName: string | null | undefined) => {
|
|
273
|
+
if (!actionName) return
|
|
274
|
+
|
|
275
|
+
const index = actionMgr.findCustomAction(actionName)
|
|
276
|
+
if (index < 0) return
|
|
277
|
+
|
|
278
|
+
actionMgr.removeCustomAction(index)
|
|
279
|
+
debug(`Action ${actionName} removed`)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
export const clearToolbar = (toolbarName: string | null | undefined) => {
|
|
283
|
+
if (!toolbarName) return
|
|
284
|
+
const toolbar = paneMgr.findToolBar(toolbarName)
|
|
285
|
+
if (!toolbar) return
|
|
286
|
+
toolbar.clear()
|
|
287
|
+
debug(`Toolbar ${toolbarName} cleared`)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export const cleanupEmptyToolbar = (toolbarName: string | null | undefined) => {
|
|
291
|
+
if (!toolbarName) return
|
|
292
|
+
const toolbar = paneMgr.findToolBar(toolbarName)
|
|
293
|
+
if (!toolbar) return
|
|
294
|
+
|
|
295
|
+
if (toolbar.hasItems() || toolbar.getItemList().length > 0) return
|
|
296
|
+
|
|
297
|
+
toolbar.setClosed(true)
|
|
298
|
+
debug(`Toolbar ${toolbarName} closed (setClosed=true)`)
|
|
299
|
+
toolbar.clear()
|
|
300
|
+
debug(`Toolbar ${toolbarName} cleared`)
|
|
301
|
+
paneMgr.removeToolBar(toolbar)
|
|
302
|
+
debug(`Toolbar ${toolbarName} removeToolBar called`)
|
|
95
303
|
}
|
|
96
304
|
|
|
97
305
|
export const addToMenu = (action: CustomAction) => {
|
|
98
|
-
if (!action.menuPath) return
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
306
|
+
if (!action.menuPath || !action.name) return
|
|
307
|
+
const menuPath = `${action.menuPath}/`
|
|
308
|
+
const menu = getMenu(menuPath, true)
|
|
309
|
+
const menuAction = findInMenu(menu, action.name)
|
|
102
310
|
if (menuAction) return
|
|
103
311
|
menu.insertCustomAction(action.name, action.sort ?? -1)
|
|
104
312
|
debug(`Action "${action.text}" added to menu "${menu.getPath()}"`)
|
|
105
313
|
}
|
|
106
314
|
|
|
107
315
|
export const addToToolbar = (action: CustomAction) => {
|
|
108
|
-
if (!action.toolbar) return
|
|
316
|
+
if (!action.toolbar || !action.name) return
|
|
109
317
|
|
|
110
|
-
|
|
318
|
+
let toolbar = paneMgr.findToolBar(action.toolbar)
|
|
111
319
|
|
|
112
320
|
if (!toolbar) {
|
|
113
|
-
toolbar = paneMgr.createToolBar(action.toolbar)
|
|
114
|
-
toolbar.dock(DzToolBar.ToolBarTop)
|
|
321
|
+
toolbar = paneMgr.createToolBar(action.toolbar)
|
|
322
|
+
toolbar.dock(DzToolBar.ToolBarTop)
|
|
323
|
+
} else {
|
|
324
|
+
toolbar.setClosed(false)
|
|
115
325
|
}
|
|
116
326
|
|
|
117
|
-
if (
|
|
327
|
+
if (findToolbarItem(action.toolbar, action.name)) return
|
|
118
328
|
|
|
119
|
-
|
|
120
|
-
|
|
329
|
+
toolbar.insertCustomAction(action.name, action.sort ?? -1)
|
|
330
|
+
debug(`Action "${action.text}" added to toolbar "${action.toolbar}"`)
|
|
121
331
|
}
|
|
122
332
|
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
333
|
+
const createOrUpdateCustomAction = (sourceAction: CustomAction, resolvedAction: CustomAction): CustomAction => {
|
|
334
|
+
const existingActions = findAllByFilePath(sourceAction, resolvedAction.filePath)
|
|
335
|
+
existingActions.forEach((existingAction) => {
|
|
336
|
+
removeFromMenu(existingAction.name)
|
|
337
|
+
removeFromToolbar(existingAction.toolbar, existingAction.name)
|
|
338
|
+
removeUnderlyingCustomAction(existingAction.name)
|
|
339
|
+
})
|
|
340
|
+
|
|
341
|
+
const name = actionMgr
|
|
342
|
+
.addCustomAction(
|
|
343
|
+
String(resolvedAction.text),
|
|
344
|
+
String(resolvedAction.description),
|
|
345
|
+
String(resolvedAction.filePath),
|
|
346
|
+
true,
|
|
347
|
+
resolvedAction.shortcut ?? "",
|
|
348
|
+
String(resolvedAction.icon ?? '')
|
|
349
|
+
)
|
|
350
|
+
.toString()
|
|
351
|
+
|
|
352
|
+
const created = {
|
|
353
|
+
...resolvedAction,
|
|
354
|
+
name
|
|
355
|
+
} as CustomAction
|
|
356
|
+
|
|
357
|
+
if (resolvedAction.shortcut) {
|
|
358
|
+
actionMgr.setCustomActionShortcut(actionMgr.findCustomAction(name), resolvedAction.shortcut)
|
|
132
359
|
}
|
|
133
360
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
361
|
+
debug(`Created Custom Action: ${created.text} (${created.name}): ${created.filePath}`)
|
|
362
|
+
return created
|
|
363
|
+
}
|
|
137
364
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
toolbar.
|
|
143
|
-
|
|
144
|
-
|
|
365
|
+
export const getInstalledCustomActionState = (action: CustomAction, scriptsPath: string = getScriptPath()): CustomActionInstallState => {
|
|
366
|
+
const resolvedAction = resolveActionPaths(action, scriptsPath)
|
|
367
|
+
const customAction = findByFilePath(action, resolvedAction.filePath)
|
|
368
|
+
const installedMenu = customAction?.name ? findMenuFor(customAction.name, actionMgr.getMenu()) !== null : false
|
|
369
|
+
const installedToolbar = customAction?.name ? isInstalledToToolbar(action.toolbar, customAction.name) : false
|
|
370
|
+
|
|
371
|
+
return {
|
|
372
|
+
action: resolvedAction,
|
|
373
|
+
customAction,
|
|
374
|
+
installedMenu,
|
|
375
|
+
installedToolbar
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
export const applyCustomActionTargets = (action: CustomAction, targets: CustomActionTargets, scriptsPath: string = getScriptPath()) => {
|
|
380
|
+
const resolvedAction = resolveActionPaths(action, scriptsPath)
|
|
381
|
+
const shouldInstall = targets.menu || targets.toolbar
|
|
382
|
+
|
|
383
|
+
if (!shouldInstall) {
|
|
384
|
+
removeCustomActionTargets(action, { menu: true, toolbar: true }, scriptsPath)
|
|
385
|
+
return
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
const customAction = createOrUpdateCustomAction(action, resolvedAction)
|
|
389
|
+
|
|
390
|
+
if (targets.menu && action.menuPath) {
|
|
391
|
+
addToMenu(customAction)
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
if (targets.toolbar && action.toolbar) {
|
|
395
|
+
addToToolbar(customAction)
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
export const removeCustomActionTargets = (action: CustomAction, targets: CustomActionTargets, scriptsPath: string = getScriptPath()) => {
|
|
400
|
+
const resolvedAction = resolveActionPaths(action, scriptsPath)
|
|
401
|
+
const matches = findAllByFilePath(action, resolvedAction.filePath)
|
|
402
|
+
|
|
403
|
+
if (matches.length === 0) return
|
|
404
|
+
|
|
405
|
+
matches.forEach((match) => {
|
|
406
|
+
const installedMenu = match.name ? findMenuFor(match.name, actionMgr.getMenu()) !== null : false
|
|
407
|
+
const installedToolbar = match.name ? isInstalledToToolbar(action.toolbar, match.name) : false
|
|
408
|
+
|
|
409
|
+
if (!match.name) return
|
|
410
|
+
|
|
411
|
+
if (targets.menu && installedMenu) {
|
|
412
|
+
removeFromMenu(match.name)
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (targets.toolbar && installedToolbar) {
|
|
416
|
+
removeFromToolbar(action.toolbar, match.name)
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
const menuStillInstalled = !targets.menu && installedMenu
|
|
420
|
+
const toolbarStillInstalled = !targets.toolbar && installedToolbar
|
|
421
|
+
|
|
422
|
+
if (!menuStillInstalled && !toolbarStillInstalled) {
|
|
423
|
+
removeUnderlyingCustomAction(match.name)
|
|
424
|
+
}
|
|
425
|
+
})
|
|
145
426
|
}
|
|
146
427
|
|
|
147
428
|
export const installCustomActions = (actions: CustomAction[]) => {
|
|
148
|
-
|
|
149
|
-
let scriptsPath = getScriptPath()
|
|
429
|
+
const scriptsPath = getScriptPath()
|
|
150
430
|
debug(`Script path: ${scriptsPath}`)
|
|
151
|
-
|
|
431
|
+
const menuPaths = array.group(actions, (a => a.menuPath ?? ""))
|
|
152
432
|
progress('Installing', keys(menuPaths), (menuPath) => {
|
|
153
|
-
|
|
154
|
-
|
|
433
|
+
const groupedActions = menuPaths[menuPath] as CustomAction[]
|
|
434
|
+
const groups = array.group(groupedActions, (action) => action.group ?? "")
|
|
155
435
|
keys(groups).forEach(group => {
|
|
156
436
|
groups[group].forEach(action => {
|
|
157
|
-
action
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
437
|
+
applyCustomActionTargets(action, {
|
|
438
|
+
menu: Boolean(action.menuPath),
|
|
439
|
+
toolbar: Boolean(action.toolbar)
|
|
440
|
+
}, scriptsPath)
|
|
161
441
|
})
|
|
162
442
|
})
|
|
163
443
|
})
|
|
@@ -165,12 +445,23 @@ export const installCustomActions = (actions: CustomAction[]) => {
|
|
|
165
445
|
|
|
166
446
|
export const uninstallCustomActions = (actions: CustomAction[]) => {
|
|
167
447
|
debug(`Uninstalling Actions`)
|
|
448
|
+
const toolbarNames = new Set<string>()
|
|
449
|
+
|
|
168
450
|
actions.forEach(action => {
|
|
169
451
|
if (!action) return
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
debug(`Uninstalling action "${customAction.text} (${customAction.name})"`)
|
|
173
|
-
removeCustomAction(customAction)
|
|
452
|
+
if (action.toolbar) toolbarNames.add(action.toolbar)
|
|
453
|
+
removeCustomActionTargets(action, { menu: true, toolbar: true })
|
|
174
454
|
})
|
|
175
|
-
}
|
|
176
455
|
|
|
456
|
+
toolbarNames.forEach(toolbarName => {
|
|
457
|
+
const toolbar = paneMgr.findToolBar(toolbarName)
|
|
458
|
+
if (!toolbar) {
|
|
459
|
+
debug(`Toolbar ${toolbarName} not found for post-uninstall cleanup`)
|
|
460
|
+
return
|
|
461
|
+
}
|
|
462
|
+
toolbar.clear()
|
|
463
|
+
toolbar.setClosed(true)
|
|
464
|
+
paneMgr.removeToolBar(toolbar)
|
|
465
|
+
debug(`Toolbar ${toolbarName} cleared, closed, and removed after uninstall`)
|
|
466
|
+
})
|
|
467
|
+
}
|