Skip to content

Commit

Permalink
feat: separate submenus for different contexts
Browse files Browse the repository at this point in the history
  • Loading branch information
lidel committed Sep 19, 2018
1 parent c9d5ffb commit bc03050
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 88 deletions.
54 changes: 35 additions & 19 deletions add-on/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,12 @@
"description": "A menu item in Browser Action pop-up (panel_unpinCurrentIpfsAddress)"
},
"panelCopy_currentIpfsAddress": {
"message": "Copy Canonical Address",
"message": "Copy IPFS Path",
"description": "A menu item in Browser Action pop-up and right-click context menu (panelCopy_currentIpfsAddress)"
},
"panelCopy_copyDirectCid": {
"message": "Copy Direct CID",
"description": "A menu item in Browser Action pop-up and right-click context menu (panelCopy_copyDirectCid)"
"panelCopy_copyRawCid": {
"message": "Copy Resolved CID",
"description": "A menu item in Browser Action pop-up and right-click context menu (panelCopy_copyRawCid)"
},
"panel_copyCurrentPublicGwUrl": {
"message": "Copy Public Gateway URL",
Expand All @@ -87,25 +87,41 @@
"message": "Non-IPFS resource",
"description": "Default label for icon hidden in Page Action menu (pageAction_titleNonIpfs)"
},
"contextMenu_AddToIpfsSelection": {
"message": "Add Selected Text to IPFS",
"description": "An item in right-click context menu (contextMenu_AddToIpfsSelection)"
"contextMenu_parentImage": {
"message": "Selected Image",
"description": "An item in right-click context menu (contextMenu_parentImage)"
},
"contextMenu_parentVideo": {
"message": "Selected Video",
"description": "An item in right-click context menu (contextMenu_parentVideo)"
},
"contextMenu_parentAudio": {
"message": "Selected Audio",
"description": "An item in right-click context menu (contextMenu_parentAudio)"
},
"contextMenu_AddToIpfsImage": {
"message": "Add this Image to IPFS",
"description": "An item in right-click context menu (contextMenu_AddToIpfsImage)"
"contextMenu_parentLink": {
"message": "Linked Content",
"description": "An item in right-click context menu (contextMenu_parentLink)"
},
"contextMenu_AddToIpfsVideo": {
"message": "Add this Video to IPFS",
"description": "An item in right-click context menu (contextMenu_AddToIpfsVideo)"
"contextMenu_parentText": {
"message": "Selected Text",
"description": "An item in right-click context menu (contextMenu_parentText)"
},
"contextMenu_AddToIpfsAudio": {
"message": "Add this Audio to IPFS",
"description": "An item in right-click context menu (contextMenu_AddToIpfsAudio)"
"contextMenu_parentPage": {
"message": "This Page",
"description": "An item in right-click context menu (contextMenu_parentPage)"
},
"contextMenu_AddToIpfsLink": {
"message": "Add Linked Content to IPFS",
"description": "An item in right-click context menu (contextMenu_AddToIpfsLink)"
"contextMenu_AddToIpfsKeepFilename": {
"message": "Add to IPFS (Keep Filename)",
"description": "An item in right-click context menu (contextMenu_AddToIpfsKeepFilename)"
},
"contextMenu_AddToIpfsRawCid": {
"message": "Add to IPFS (Raw CID)",
"description": "An item in right-click context menu (contextMenu_AddToIpfsRawCid)"
},
"contextMenu_AddToIpfsSelection": {
"message": "Add Selected Text to IPFS",
"description": "An item in right-click context menu (contextMenu_AddToIpfsSelection)"
},
"notify_addonIssueTitle": {
"message": "IPFS Add-on Issue",
Expand Down
147 changes: 100 additions & 47 deletions add-on/src/lib/context-menus.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,23 @@

const browser = require('webextension-polyfill')

async function findUrlForContext (context, contextField) {
// 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 (contextField) {
return context[contextField]
console.log(context)
if (contextType) {
const field = contextSources[contextType]
return context[field]
}
if (context.srcUrl) {
// present when clicked on page element such as image or video
Expand All @@ -25,69 +38,108 @@ async function findUrlForContext (context, contextField) {
return currentTab.url
}

module.exports.findUrlForContext = findUrlForContext
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 contextMenuAddToIpfsRawCid = 'contextMenu_AddToIpfsRawCid'
const contextMenuAddToIpfsKeepFilename = 'contextMenu_AddToIpfsKeepFilename'
// Add X to IPFS
const contextMenuAddToIpfsSelection = 'contextMenu_AddToIpfsSelection'
const contextMenuAddToIpfsImage = 'contextMenu_AddToIpfsImage'
const contextMenuAddToIpfsVideo = 'contextMenu_AddToIpfsVideo'
const contextMenuAddToIpfsAudio = 'contextMenu_AddToIpfsAudio'
const contextMenuAddToIpfsLink = 'contextMenu_AddToIpfsLink'
// Copy X
const contextMenuCopyCanonicalAddress = 'panelCopy_currentIpfsAddress'
const contextMenuCopyDirectCid = 'panelCopy_copyDirectCid'
const contextMenuCopyRawCid = 'panelCopy_copyRawCid'
const contextMenuCopyAddressAtPublicGw = 'panel_copyCurrentPublicGwUrl'
module.exports.contextMenuCopyCanonicalAddress = contextMenuCopyCanonicalAddress
module.exports.contextMenuCopyDirectCid = contextMenuCopyDirectCid
module.exports.contextMenuCopyRawCid = contextMenuCopyRawCid
module.exports.contextMenuCopyAddressAtPublicGw = contextMenuCopyAddressAtPublicGw

// menu items that are enabled only when API is online
const apiMenuItems = [
contextMenuAddToIpfsSelection,
contextMenuAddToIpfsImage,
contextMenuAddToIpfsVideo,
contextMenuAddToIpfsAudio,
contextMenuAddToIpfsLink,
contextMenuCopyDirectCid
]
const apiMenuItems = new Set()
// menu items enabled only in IPFS context
const ipfsContextItems = new Set()

function createContextMenus (getState, runtime, ipfsPathValidator, { onAddFromContext, onCopyCanonicalAddress, onCopyDirectCid, onCopyAddressAtPublicGw }) {
let copyAddressContexts = ['page', 'image', 'video', 'audio', 'link']
if (runtime.isFirefox) {
// https://github.com/ipfs-shipyard/ipfs-companion/issues/398
copyAddressContexts.push('page_action')
}
function createContextMenus (getState, runtime, ipfsPathValidator, { onAddFromContext, onCopyCanonicalAddress, onCopyRawCid, onCopyAddressAtPublicGw }) {
try {
const createAddToIpfsMenuItem = (menuItemId, contextName, contextField, ipfsAddOptions) => {
const createSubmenu = (id, contextType, menuBuilder) => {
browser.contextMenus.create({
id: menuItemId,
title: browser.i18n.getMessage(menuItemId),
contexts: [contextName],
id,
title: browser.i18n.getMessage(id),
documentUrlPatterns: ['<all_urls>'],
contexts: [contextType]
})
}
const createSeparator = (parentId, id, contextType) => {
return browser.contextMenus.create({
id: `${parentId}_${id}`,
parentId,
type: 'separator',
contexts: ['all']
})
}
const createAddToIpfsMenuItem = (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,
onclick: (context) => onAddFromContext(context, contextField, ipfsAddOptions)
icons: {
'48': '/ui-kit/icons/stroke_cube.svg'
},
onclick: (context) => onAddFromContext(context, contextType, ipfsAddOptions)
})
}
createAddToIpfsMenuItem(contextMenuAddToIpfsSelection, 'selection', 'selectionText')
createAddToIpfsMenuItem(contextMenuAddToIpfsImage, 'image', 'srcUrl', { wrapWithDirectory: true })
createAddToIpfsMenuItem(contextMenuAddToIpfsVideo, 'video', 'srcUrl', { wrapWithDirectory: true })
createAddToIpfsMenuItem(contextMenuAddToIpfsAudio, 'audio', 'srcUrl', { wrapWithDirectory: true })
createAddToIpfsMenuItem(contextMenuAddToIpfsLink, 'link', 'linkUrl', { wrapWithDirectory: true })

const createCopierMenuItem = (menuItemId, handler) => {
browser.contextMenus.create({
id: menuItemId,
title: browser.i18n.getMessage(menuItemId),
contexts: copyAddressContexts,
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/*'],
onclick: handler
icons: {
'48': '/ui-kit/icons/stroke_copy.svg'
},
onclick: (context) => handler(context, contextType)
})
}
createCopierMenuItem(contextMenuCopyCanonicalAddress, onCopyCanonicalAddress)
createCopierMenuItem(contextMenuCopyDirectCid, onCopyDirectCid)
createCopierMenuItem(contextMenuCopyAddressAtPublicGw, onCopyAddressAtPublicGw)
const buildSubmenu = (parentId, contextType) => {
createSubmenu(parentId, contextType)
createAddToIpfsMenuItem(parentId, contextMenuAddToIpfsKeepFilename, contextType, { wrapWithDirectory: true })
createAddToIpfsMenuItem(parentId, contextMenuAddToIpfsRawCid, contextType, { wrapWithDirectory: false })
createSeparator(parentId, 'separator-1', contextType)
createCopierMenuItem(parentId, contextMenuCopyCanonicalAddress, contextType, onCopyCanonicalAddress)
createCopierMenuItem(parentId, contextMenuCopyRawCid, contextType, onCopyRawCid)
createCopierMenuItem(parentId, contextMenuCopyAddressAtPublicGw, contextType, onCopyAddressAtPublicGw)
}

/*
createSubmenu(menuParentText, 'selection')
createAddToIpfsMenuItem(menuParentText, contextMenuAddToIpfsSelection, 'selection')
*/
createAddToIpfsMenuItem(null, contextMenuAddToIpfsSelection, 'selection')
buildSubmenu(menuParentImage, 'image')
buildSubmenu(menuParentVideo, 'video')
buildSubmenu(menuParentAudio, 'audio')
buildSubmenu(menuParentLink, 'link')
buildSubmenu(menuParentPage, 'page')
} catch (err) {
// documentUrlPatterns is not supported in Brave
// documentUrlPatterns is not supported in Muon-Brave
if (err.message.indexOf('createProperties.documentUrlPatterns of contextMenus.create is not supported yet') > -1) {
console.warn('[ipfs-companion] Context menus disabled - createProperties.documentUrlPatterns of contextMenus.create is not supported yet')
return { update: () => Promise.resolve() }
Expand All @@ -112,8 +164,9 @@ function createContextMenus (getState, runtime, ipfsPathValidator, { onAddFromCo
const currentTab = await browser.tabs.query({ active: true, currentWindow: true }).then(tabs => tabs[0])
if (currentTab && currentTab.id === changedTabId) {
const ipfsContext = ipfsPathValidator.isIpfsPageActionsContext(currentTab.url)
browser.contextMenus.update(contextMenuCopyCanonicalAddress, { enabled: ipfsContext })
browser.contextMenus.update(contextMenuCopyAddressAtPublicGw, { enabled: ipfsContext })
for (let item of ipfsContextItems) {
browser.contextMenus.update(item, { enabled: ipfsContext })
}
}
}
} catch (err) {
Expand Down
14 changes: 7 additions & 7 deletions add-on/src/lib/copier.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

const browser = require('webextension-polyfill')
const { safeIpfsPath, trimHashAndSearch } = require('./ipfs-path')
const { findUrlForContext } = require('./context-menus')
const { findValueForContext } = require('./context-menus')

async function copyTextToClipboard (copyText) {
const currentTab = await browser.tabs.query({ active: true, currentWindow: true }).then(tabs => tabs[0])
Expand Down Expand Up @@ -36,17 +36,17 @@ async function copyTextToClipboard (copyText) {

function createCopier (getState, getIpfs, notify) {
return {
async copyCanonicalAddress (context) {
const url = await findUrlForContext(context)
async copyCanonicalAddress (context, contextType) {
const url = await findValueForContext(context, contextType)
const rawIpfsAddress = safeIpfsPath(url)
copyTextToClipboard(rawIpfsAddress)
notify('notify_copiedTitle', rawIpfsAddress)
},

async copyDirectCid (context) {
async copyRawCid (context, contextType) {
try {
const ipfs = getIpfs()
const url = await findUrlForContext(context)
const url = await findValueForContext(context, contextType)
const rawIpfsAddress = trimHashAndSearch(safeIpfsPath(url))
const directCid = (await ipfs.resolve(rawIpfsAddress, { recursive: true })).split('/')[2]
copyTextToClipboard(directCid)
Expand All @@ -57,8 +57,8 @@ function createCopier (getState, getIpfs, notify) {
}
},

async copyAddressAtPublicGw (context) {
const url = await findUrlForContext(context)
async copyAddressAtPublicGw (context, contextType) {
const url = await findValueForContext(context, contextType)
const state = getState()
const urlAtPubGw = url.replace(state.gwURLString, state.pubGwURLString)
copyTextToClipboard(urlAtPubGw)
Expand Down
18 changes: 9 additions & 9 deletions add-on/src/lib/ipfs-companion.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const { createIpfsUrlProtocolHandler } = require('./ipfs-protocol')
const createNotifier = require('./notifier')
const createCopier = require('./copier')
const createRuntimeChecks = require('./runtime-checks')
const { createContextMenus, findUrlForContext, contextMenuCopyAddressAtPublicGw, contextMenuCopyDirectCid, contextMenuCopyCanonicalAddress } = require('./context-menus')
const { createContextMenus, findValueForContext, contextMenuCopyAddressAtPublicGw, contextMenuCopyRawCid, contextMenuCopyCanonicalAddress } = require('./context-menus')
const createIpfsProxy = require('./ipfs-proxy')
const { showPendingLandingPages } = require('./on-installed')

Expand Down Expand Up @@ -61,7 +61,7 @@ module.exports = async function init () {
contextMenus = createContextMenus(getState, runtime, ipfsPathValidator, {
onAddFromContext,
onCopyCanonicalAddress: copier.copyCanonicalAddress,
onCopyDirectCid: copier.copyDirectCid,
onCopyRawCid: copier.copyRawCid,
onCopyAddressAtPublicGw: copier.copyAddressAtPublicGw
})
modifyRequest = createRequestModifier(getState, dnslinkResolver, ipfsPathValidator, runtime)
Expand Down Expand Up @@ -192,7 +192,7 @@ module.exports = async function init () {
const BrowserActionMessageHandlers = {
notification: (message) => notify(message.title, message.message),
[contextMenuCopyCanonicalAddress]: copier.copyCanonicalAddress,
[contextMenuCopyDirectCid]: copier.copyDirectCid,
[contextMenuCopyRawCid]: copier.copyRawCid,
[contextMenuCopyAddressAtPublicGw]: copier.copyAddressAtPublicGw
}

Expand Down Expand Up @@ -257,12 +257,12 @@ module.exports = async function init () {
// Context Menu Uploader
// -------------------------------------------------------------------

async function onAddFromContext (context, contextField, options) {
async function onAddFromContext (context, contextType, options) {
let result
try {
const srcUrl = await findUrlForContext(context, contextField)
if (contextField === 'selectionText') {
result = await ipfs.files.add(Buffer.from(context.selectionText), options)
const dataSrc = await findValueForContext(context, contextType)
if (contextType === 'selection') {
result = await ipfs.files.add(Buffer.from(dataSrc), options)
} else if (runtime.isFirefox) {
// workaround due to https://github.com/ipfs/ipfs-companion/issues/227
const fetchOptions = {
Expand All @@ -271,7 +271,7 @@ module.exports = async function init () {
}
// console.log('onAddFromContext.context', context)
// console.log('onAddFromContext.fetchOptions', fetchOptions)
const response = await fetch(srcUrl, fetchOptions)
const response = await fetch(dataSrc, fetchOptions)
const blob = await response.blob()
const buffer = await new Promise((resolve, reject) => {
const reader = new FileReader()
Expand All @@ -285,7 +285,7 @@ module.exports = async function init () {
}
result = await ipfs.files.add(data, options)
} else {
result = await ipfs.util.addFromURL(srcUrl, options)
result = await ipfs.util.addFromURL(dataSrc, options)
}
} catch (error) {
console.error('Error in upload to IPFS context menu', error)
Expand Down
6 changes: 3 additions & 3 deletions add-on/src/popup/browser-action/context-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
const browser = require('webextension-polyfill')
const html = require('choo/html')
const navItem = require('./nav-item')
const { contextMenuCopyAddressAtPublicGw, contextMenuCopyDirectCid, contextMenuCopyCanonicalAddress } = require('../../lib/context-menus')
const { contextMenuCopyAddressAtPublicGw, contextMenuCopyRawCid, contextMenuCopyCanonicalAddress } = require('../../lib/context-menus')

module.exports = function contextActions ({
active,
Expand All @@ -28,8 +28,8 @@ module.exports = function contextActions ({
onClick: () => onCopy(contextMenuCopyCanonicalAddress)
})}
${navItem({
text: browser.i18n.getMessage(contextMenuCopyDirectCid),
onClick: () => onCopy(contextMenuCopyDirectCid)
text: browser.i18n.getMessage(contextMenuCopyRawCid),
onClick: () => onCopy(contextMenuCopyRawCid)
})}
${navItem({
text: browser.i18n.getMessage(contextMenuCopyAddressAtPublicGw),
Expand Down
Loading

0 comments on commit bc03050

Please sign in to comment.