Skip to content

Commit

Permalink
feat(pageAction): pinning of IPNS resources
Browse files Browse the repository at this point in the history
- page action detects if resource is IPNS
  and converts it to IPFS before executing pin
  (closes #222)
- pin action is faded when not active, which removes
  jumping UI bug
- page action uses async/await, which improved code A LOT!
  (first step towards #212)
  • Loading branch information
lidel committed Mar 25, 2017
1 parent 45c272a commit 0e6418b
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 72 deletions.
5 changes: 4 additions & 1 deletion add-on/manifest.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
{
"manifest_version": 2,
"name": "IPFS Gateway Redirect (Development Channel)",
"short_name": "IPFS Add-On",
"version" : "2.0.0alpha3",

"description": "Access IPFS resources via custom HTTP2IPFS gateway",
"homepage_url": "https://github.com/lidel/ipfs-firefox-addon",
"author": "Marcin Rataj",
"icons": {
"48": "icons/ipfs-logo-on.svg"
},
"applications": {
"gecko": {
"id": "ipfs-firefox-addon@lidel.org",
"strict_min_version": "50.0"
"strict_min_version": "52.0"
}
},

Expand All @@ -24,6 +26,7 @@
"alarms",
"storage",
"contextMenus",
"clipboardWrite",
"webRequest",
"webRequestBlocking"
],
Expand Down
5 changes: 5 additions & 0 deletions add-on/src/popup/browser-action.css
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ li.action:active {
font-weight: bold;
}

.faded {
cursor: default !important;
opacity: 0.5 !important;
}

.hidden {
display: none !important;
}
206 changes: 135 additions & 71 deletions add-on/src/popup/page-action.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,50 @@
'use strict'
/* eslint-env browser, webextensions */

const pinResource = document.getElementById('pin-current-ipfs-address')
const unpinResource = document.getElementById('unpin-current-ipfs-address')
const copyIpfsAddress = document.getElementById('copy-current-ipfs-address')
const copyPublicGwAddress = document.getElementById('copy-current-public-gw-url')
const pinResourceButton = document.getElementById('pin-current-ipfs-address')
const unpinResourceButton = document.getElementById('unpin-current-ipfs-address')
const copyIpfsAddressButton = document.getElementById('copy-current-ipfs-address')
const copyPublicGwAddressButton = document.getElementById('copy-current-public-gw-url')

function show (element) {
element.classList.remove('faded')
element.classList.remove('hidden')
}

function fade (element) {
element.classList.add('faded')
}

function hide (element) {
element.classList.add('hidden')
}

async function getBackgroundPage () {
return browser.runtime.getBackgroundPage()
}

async function getCurrentTab () {
return browser.tabs.query({active: true, currentWindow: true}).then(tabs => tabs[0])
}

async function copyCurrentPublicGwAddress () {
const bg = await getBackgroundPage()
const currentTab = await getCurrentTab()
const publicGwAddress = new URL(currentTab.url.replace(bg.state.gwURLString, 'https://ipfs.io/')).toString()
copyTextToClipboard(publicGwAddress)
bg.notify('Copied Public URL', publicGwAddress) // TODO: i18
window.close()
}

async function copyCurrentCanonicalAddress () {
const bg = await getBackgroundPage()
const currentTab = await getCurrentTab()
const rawIpfsAddress = currentTab.url.replace(/^.+(\/ip(f|n)s\/.+)/, '$1')
copyTextToClipboard(rawIpfsAddress)
bg.notify('Copied Canonical Address', rawIpfsAddress) // TODO: i18
window.close()
}

function copyTextToClipboard (copyText) {
// lets take a moment and ponder on the state of copying a string in 2017
const copyFrom = document.createElement('textarea')
Expand All @@ -25,73 +56,106 @@ function copyTextToClipboard (copyText) {
body.removeChild(copyFrom)
}

async function pinCurrentResource () {
deactivatePinButton()
try {
const bg = await getBackgroundPage()
const currentTab = await getCurrentTab()
const currentPath = await resolveToIPFS(new URL(currentTab.url).pathname)
const pinResult = await bg.ipfs.pin.add(currentPath, { recursive: true })
console.log('ipfs.pin.add result', pinResult)
bg.notify('Pinned IPFS Resource', currentPath) // TODO: i18
} catch (error) {
handlePinError('Error while pinning', error)
}
window.close()
}

async function unpinCurrentResource () {
deactivatePinButton()
try {
const bg = await getBackgroundPage()
const currentTab = await getCurrentTab()
const currentPath = await resolveToIPFS(new URL(currentTab.url).pathname)
const result = await bg.ipfs.pin.rm(currentPath)
console.log('ipfs.pin.rm result', result)
bg.notify('Removed IPFS Pin', currentPath) // TODO: i18
} catch (error) {
handlePinError('Error while unpinning', error)
}
window.close()
}

function activatePinning () {
pinResourceButton.onclick = pinCurrentResource
show(pinResourceButton)
unpinResourceButton.onclick = undefined
hide(unpinResourceButton)
}

function activateUnpinning () {
pinResourceButton.onclick = undefined
unpinResourceButton.onclick = unpinCurrentResource
hide(pinResourceButton)
show(unpinResourceButton)
}

function deactivatePinButton () {
pinResourceButton.onclick = undefined
unpinResourceButton.onclick = undefined
fade(pinResourceButton)
hide(unpinResourceButton)
}

async function handlePinError (errorMessage, error) {
console.error(errorMessage, error)
deactivatePinButton()
try {
const bg = await getBackgroundPage()
bg.notify(errorMessage, error.message) // TODO: i18
} catch (error) {
console.error('unable to access background page', error)
}
}

async function resolveToIPFS (path) {
if (/^\/ipns/.test(path)) {
const bg = await getBackgroundPage()
const response = await bg.ipfs.name.resolve(path, {recursive: true, nocache: false})
return response.Path
}
return path
}

async function activatePinButton () {
try {
const bg = await getBackgroundPage()
const currentTab = await getCurrentTab()
const currentPath = await resolveToIPFS(new URL(currentTab.url).pathname)
const response = await bg.ipfs.pin.ls(currentPath, {quiet: true})
console.log(`positive ipfs.pin.ls for ${currentPath}: ${JSON.stringify(response)}`)
activateUnpinning()
} catch (error) {
if (/is not pinned/.test(error.message)) {
console.log(`negative ipfs.pin.ls: ${error} (${JSON.stringify(error)})`)
activatePinning()
} else {
console.error(`unexpected result of ipfs.pin.ls: ${error} (${JSON.stringify(error)})`)
deactivatePinButton()
}
}
}

function initPageAction () {
console.log('running initPageAction()')
return browser.tabs.query({active: true, currentWindow: true})
.then(tabs => {
const currentTab = tabs[0]
const currentPath = new URL(currentTab.url).pathname

return browser.runtime.getBackgroundPage()
.then(bg => {
copyPublicGwAddress.onclick = () => {
const publicGwAddress = new URL(currentTab.url.replace(bg.state.gwURLString, 'https://ipfs.io/')).toString()
copyTextToClipboard(publicGwAddress)
bg.notify('Copied Public URL', publicGwAddress) // TODO: i18
window.close()
}

copyIpfsAddress.onclick = () => {
const rawIpfsAddress = currentTab.url.replace(/^.+(\/ip(f|n)s\/.+)/, '$1')
copyTextToClipboard(rawIpfsAddress)
bg.notify('Copied Canonical Address', rawIpfsAddress) // TODO: i18
window.close()
}

// check pin status to decide which action to display
return bg.ipfs.pin.ls({arg: currentPath, quiet: true})
.then(response => {
console.log(`positive ipfs.pin.ls for ${currentPath}: ${JSON.stringify(response)}`)

show(unpinResource)
unpinResource.onclick = () => {
bg.ipfs.pin.rm(currentPath)
.then(result => {
console.log('ipfs.pin.rm result', result)
bg.notify('Removed IPFS Pin', currentPath) // TODO: i18
})
.catch(error => {
console.error(`Error while unpinning ${currentPath}`, error)
bg.notify('Error while unpinning', JSON.stringify(error)) // TODO: i18
})
.then(() => window.close())
}
})
.catch(error => {
console.log(`negative ipfs.pin.ls: ${error} (${JSON.stringify(error)})`)
if (/is not pinned/.test(error.message)) {
show(pinResource)
pinResource.onclick = () => {
bg.ipfs.pin.add(currentPath)
.then(result => {
console.log('ipfs.pin.add result', result)
bg.notify('Pinned IPFS Resource', currentPath) // TODO: i18
})
.catch(error => {
console.error(`Error while pinning ${currentPath}`, error)
bg.notify('Error while pinning', JSON.strinfigy(error)) // TODO: i18
})
.then(() => window.close())
}
}
})
})
})
.catch(error => {
console.error(`Error while setting up pageAction: ${error}`)
})
}

hide(pinResource)
hide(unpinResource)
try {
deactivatePinButton()
copyPublicGwAddressButton.onclick = copyCurrentPublicGwAddress
copyIpfsAddressButton.onclick = copyCurrentCanonicalAddress
return activatePinButton()
} catch (error) {
console.error(`Error while setting up pageAction: ${error}`)
}
}

document.addEventListener('DOMContentLoaded', initPageAction)

0 comments on commit 0e6418b

Please sign in to comment.