-
Notifications
You must be signed in to change notification settings - Fork 336
Expand file tree
/
Copy pathcontext-menus.js
More file actions
185 lines (172 loc) · 6.97 KB
/
Copy pathcontext-menus.js
File metadata and controls
185 lines (172 loc) · 6.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
'use strict'
const browser = require('webextension-polyfill')
const debug = require('debug')
const log = debug('ipfs-companion:context-menus')
log.error = debug('ipfs-companion:context-menus:error')
// mapping between context name and field with data for it
// https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/menus/ContextType
const contextSources = {
selection: 'selectionText',
image: 'srcUrl',
video: 'srcUrl',
audio: 'srcUrl',
link: 'linkUrl',
page: 'pageUrl'
}
async function findValueForContext (context, contextType) {
if (context) {
if (contextType) {
const field = contextSources[contextType]
return context[field]
}
if (context.srcUrl) {
// present when clicked on page element such as image or video
return context.srcUrl
}
if (context.linkUrl) {
// present when clicked on a link
return context.linkUrl
}
if (context.pageUrl) {
// pageUrl is the root frame
return context.pageUrl
}
}
// falback to the url of current tab
const currentTab = await browser.tabs.query({ active: true, currentWindow: true }).then(tabs => tabs[0])
return currentTab.url
}
module.exports.findValueForContext = findValueForContext
// Context Roots
const menuParentImage = 'contextMenu_parentImage'
const menuParentVideo = 'contextMenu_parentVideo'
const menuParentAudio = 'contextMenu_parentAudio'
const menuParentLink = 'contextMenu_parentLink'
const menuParentPage = 'contextMenu_parentPage'
// const menuParentText = 'contextMenu_parentText'
// Generic Add to IPFS
const contextMenuImportToIpfs = 'contextMenu_importToIpfs'
// Add X to IPFS
const contextMenuImportToIpfsSelection = 'contextMenu_importToIpfsSelection'
// Copy X
const contextMenuCopyCanonicalAddress = 'panelCopy_currentIpfsAddress'
const contextMenuCopyRawCid = 'panelCopy_copyRawCid'
const contextMenuCopyAddressAtPublicGw = 'panel_copyCurrentPublicGwUrl'
const contextMenuViewOnGateway = 'panel_contextMenuViewOnGateway'
module.exports.contextMenuCopyCanonicalAddress = contextMenuCopyCanonicalAddress
module.exports.contextMenuCopyRawCid = contextMenuCopyRawCid
module.exports.contextMenuCopyAddressAtPublicGw = contextMenuCopyAddressAtPublicGw
module.exports.contextMenuViewOnGateway = contextMenuViewOnGateway
// menu items that are enabled only when API is online
const apiMenuItems = new Set()
// menu items enabled only in IPFS context
const ipfsContextItems = new Set()
function createContextMenus (getState, runtime, ipfsPathValidator, { onAddFromContext, onCopyCanonicalAddress, onCopyRawCid, onCopyAddressAtPublicGw }) {
try {
const createSubmenu = (id, contextType, menuBuilder) => {
browser.contextMenus.create({
id,
title: browser.i18n.getMessage(id),
documentUrlPatterns: ['<all_urls>'],
contexts: [contextType]
})
}
const createImportToIpfsMenuItem = (parentId, id, contextType, ipfsAddOptions) => {
const itemId = `${parentId}_${id}`
apiMenuItems.add(itemId)
return browser.contextMenus.create({
id: itemId,
parentId,
title: browser.i18n.getMessage(id),
contexts: [contextType],
documentUrlPatterns: ['<all_urls>'],
enabled: false,
/* no support for 'icons' in Chrome
icons: {
'48': '/ui-kit/icons/stroke_cube.svg'
}, */
onclick: (context) => onAddFromContext(context, contextType, ipfsAddOptions)
})
}
const createCopierMenuItem = (parentId, id, contextType, handler) => {
const itemId = `${parentId}_${id}`
ipfsContextItems.add(itemId)
// some items also require API access
if (id === contextMenuCopyRawCid) {
apiMenuItems.add(itemId)
}
return browser.contextMenus.create({
id: itemId,
parentId,
title: browser.i18n.getMessage(id),
contexts: [contextType],
documentUrlPatterns: ['*://*/ipfs/*', '*://*/ipns/*'],
/* no support for 'icons' in Chrome
icons: {
'48': '/ui-kit/icons/stroke_copy.svg'
}, */
onclick: (context) => handler(context, contextType)
})
}
const buildSubmenu = (parentId, contextType) => {
createSubmenu(parentId, contextType)
createImportToIpfsMenuItem(parentId, contextMenuImportToIpfs, contextType, { wrapWithDirectory: true, pin: false })
createCopierMenuItem(parentId, contextMenuCopyAddressAtPublicGw, contextType, onCopyAddressAtPublicGw)
createCopierMenuItem(parentId, contextMenuCopyCanonicalAddress, contextType, onCopyCanonicalAddress)
createCopierMenuItem(parentId, contextMenuCopyRawCid, contextType, onCopyRawCid)
}
/*
createSubmenu(menuParentText, 'selection')
createImportToIpfsMenuItem(menuParentText, contextMenuImportToIpfsSelection, 'selection')
*/
createImportToIpfsMenuItem(null, contextMenuImportToIpfsSelection, 'selection', { pin: false })
buildSubmenu(menuParentImage, 'image')
buildSubmenu(menuParentVideo, 'video')
buildSubmenu(menuParentAudio, 'audio')
buildSubmenu(menuParentLink, 'link')
buildSubmenu(menuParentPage, 'page')
} catch (err) {
// documentUrlPatterns is not supported in Muon-Brave
if (err.message.indexOf('createProperties.documentUrlPatterns of contextMenus.create is not supported yet') > -1) {
log('context menus disabled - createProperties.documentUrlPatterns of contextMenus.create is not supported yet')
return { update: () => Promise.resolve() }
}
// contextMenus are not supported in Firefox for Android
if (err.message === 'browser.contextMenus is undefined' || typeof browser.contextMenus === 'undefined') {
log('context menus disabled - browser.contextMenus is undefined')
return { update: () => Promise.resolve() }
}
throw err
}
// enabled only when ipfsContext is shown when API is up
const apiAndIpfsContextItems = new Set([...apiMenuItems].filter(i => ipfsContextItems.has(i)))
// state to avoid async tab lookups
let ipfsContext = false
return {
async update (changedTabId) {
try {
if (changedTabId) {
// recalculate tab-dependant menu items
const currentTab = await browser.tabs.query({ active: true, currentWindow: true }).then(tabs => tabs[0])
if (currentTab && currentTab.id === changedTabId) {
ipfsContext = ipfsPathValidator.isIpfsPageActionsContext(currentTab.url)
}
}
const { apiAvailable } = getState()
for (const item of apiMenuItems) {
await browser.contextMenus.update(item, { enabled: apiAvailable })
}
for (const item of ipfsContextItems) {
await browser.contextMenus.update(item, { enabled: ipfsContext })
}
for (const item of apiAndIpfsContextItems) {
await browser.contextMenus.update(item, { enabled: (apiAvailable && ipfsContext) })
}
} catch (err) {
log.error('Error updating context menus', err)
}
}
// TODO: destroy?
}
}
module.exports.createContextMenus = createContextMenus