Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: preserve file name, support sharing multiple files #479

Merged
merged 8 commits into from
May 18, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions add-on/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,18 @@
"message": "drop it here to share",
"description": "Partial info stats beneath the header on the share files page (quickUpload_drop_it_here)"
},
"quickUpload_options_show": {
"message": "upload options",
"description": "Button on the share files page (quickUpload_options_show)"
},
"quickUpload_options_wrapWithDirectory": {
"message": "Wrap single files in a directory to preserve their filenames.",
"description": "Checkbox label on the share files page (quickUpload_options_wrapWithDirectory)"
},
"quickUpload_options_pinUpload": {
"message": "Pin files so they are retained when performing garbage collection on your IPFS repo.",
"description": "Checkbox label on the share files page (quickUpload_options_pinUpload)"
},
"page_proxyAcl_title": {
"message": "Manage Permissions",
"description": "Page title for the IPFS proxy ACL page (page_proxyAcl_title)"
Expand Down
12 changes: 12 additions & 0 deletions add-on/src/background/big-deps.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
'use strict'
/* eslint-env browser, webextensions */

// Problem: addons-linter does not permit .js bigger than 4MB (FILE_TOO_LARGE)
// Solution: this file lets us fine-tune to decide what to extract
// into a shared bundle created by browserify+factor-bundle

const Ipfs = require('ipfs')
// const IpfsApi = require('ipfs-api')
const node = new Ipfs({ start: false })
console.log('this code wont run :-)', node)
// console.log('fake api', IpfsApi)
42 changes: 26 additions & 16 deletions add-on/src/lib/ipfs-companion.js
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ module.exports = async function init () {
// URL Uploader
// -------------------------------------------------------------------

async function addFromURL (info) {
async function addFromURL (info, options) {
const srcUrl = await findUrlForContext(info)
let result
try {
Expand All @@ -233,17 +233,19 @@ module.exports = async function init () {
// console.log('addFromURL.fetchOptions', fetchOptions)
const response = await fetch(srcUrl, fetchOptions)
const blob = await response.blob()

const buffer = await new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onloadend = () => resolve(Buffer.from(reader.result))
reader.onerror = reject
reader.readAsArrayBuffer(blob)
})

result = await ipfs.files.add(buffer)
const data = {
path: decodeURIComponent(new URL(response.url).pathname.split('/').pop()),
content: buffer
}
result = await ipfs.files.add(data, options)
} else {
result = await ipfs.util.addFromURL(srcUrl)
result = await ipfs.util.addFromURL(srcUrl, options)
}
} catch (error) {
console.error('Error in upload to IPFS context menu', error)
Expand Down Expand Up @@ -274,19 +276,24 @@ module.exports = async function init () {
}
}

function uploadResultHandler (result) {
result.forEach(function (file) {
async function uploadResultHandler (result) {
for (let file of result) {
if (file && file.hash) {
const {path, url} = getIpfsPathAndNativeAddress(file.hash)
browser.tabs.create({
'url': url
})
console.info('[ipfs-companion] successfully stored', path)
// open the wrapping directory (or the CID if wrapping was disabled)
if (result.length === 1 || file.path === '' || file.path === file.hash) {
await browser.tabs.create({
'url': url
})
}
// preload every item
if (state.preloadAtPublicGateway) {
preloadAtPublicGateway(path)
}
console.info('[ipfs-companion] successfully stored', file)
}
})
}
return result
}

// Page-specific Actions
Expand Down Expand Up @@ -589,17 +596,20 @@ module.exports = async function init () {
return ipfs
},

async ipfsAddAndShow (buffer) {
async ipfsAddAndShow (data, options) {
options = options || {}
let result
try {
result = await api.ipfs.files.add(buffer)
result = await api.ipfs.files.add(data, options)
if (options.wrapWithDirectory && result.length !== data.length + 1) {
throw new Error(`ipfs.files.add result should include an entry for every uploaded file plus additional one for a wrapping directory (${data.length + 1} in total), but found only ${result.length} entries`)
}
} catch (err) {
console.error('Failed to IPFS add', err)
notify('notify_uploadErrorTitle', 'notify_inlineErrorMsg', `${err.message}`)
throw err
}
uploadResultHandler(result)
return result
return uploadResultHandler(result)
},

async destroy () {
Expand Down
35 changes: 35 additions & 0 deletions add-on/src/popup/quick-upload.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@import url('../../ui-kit/tachyons.css');
@import url('../../ui-kit/ipfs.css');
@import url('heartbeat.css');

html, body, #root {
Expand All @@ -11,3 +12,37 @@ html, body, #root {
.hover-inner-shadow:hover {
box-shadow: inset 0 0 10px 5px rgba(211, 235, 237, 0.2);
}

.no-user-select {
user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
}

/* Temporary CSS for custom checkbox (TODO: move/replace with ipfs-css */
input[type='checkbox'] {
display:none;
}

input[type=checkbox] + .mark {
background: transparent;
height: 16px;
width: 16px;
display: inline-block;
padding: 0;
border: 1px #6ACAD1 solid;
position: relative;
}

input[type=checkbox]:checked + .mark::after {
color: #6ACAD1;
position: absolute;
left: 4px;
top: 2px;
content: "";
height: 6px;
width: 6px;
border-left: 2px solid;
border-bottom: 2px solid;
transform: rotate(-45deg);
}
1 change: 0 additions & 1 deletion add-on/src/popup/quick-upload.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
<html>

<head>
<title>IPFS Upload</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" href="quick-upload.css">
Expand Down
80 changes: 63 additions & 17 deletions add-on/src/popup/quick-upload.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,30 @@ const choo = require('choo')
const html = require('choo/html')
const logo = require('./logo')

document.title = browser.i18n.getMessage('panel_quickUpload')

const app = choo()

app.use(quickUploadStore)
app.route('*', quickUploadPage)
app.mount('#root')

function file2buffer (file) {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onloadend = () => resolve(Buffer.from(reader.result))
reader.onerror = reject
reader.readAsArrayBuffer(file)
})
}

function quickUploadStore (state, emitter) {
state.message = ''
state.peerCount = ''
state.ipfsNodeType = 'external'
state.wrapWithDirectory = true
state.pinUpload = true
state.expandOptions = false

function updateState ({ipfsNodeType, peerCount}) {
state.ipfsNodeType = ipfsNodeType
Expand All @@ -37,22 +51,25 @@ function quickUploadStore (state, emitter) {
})

emitter.on('fileInputChange', async (event) => {
const file = event.target.files[0]
try {
const { ipfsCompanion } = await browser.runtime.getBackgroundPage()

const buffer = await new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onloadend = () => resolve(Buffer.from(reader.result))
reader.onerror = reject
reader.readAsArrayBuffer(file)
})

await ipfsCompanion.ipfsAddAndShow(buffer)

const uploadTab = await browser.tabs.getCurrent()
const files = []
for (let file of event.target.files) {
const buffer = await file2buffer(file)
files.push({
path: file.name,
content: buffer
})
}
const uploadOptions = {
wrapWithDirectory: state.wrapWithDirectory || files.length > 1,
pin: state.pinUpload
}
const result = await ipfsCompanion.ipfsAddAndShow(files, uploadOptions)
console.log('Upload result', result)
// close upload tab as it will be replaced with a new tab with uploaded content
const tab = await browser.tabs.getCurrent()
browser.tabs.remove(tab.id)
browser.tabs.remove(uploadTab.id)
} catch (err) {
console.error('Unable to perform quick upload', err)
// keep upload tab and display error message in it
Expand All @@ -62,14 +79,41 @@ function quickUploadStore (state, emitter) {
})
}

function quickUploadOptions (state, emit) {
const onExpandOptions = (e) => { state.expandOptions = true; emit('render') }
const onWrapWithDirectoryChange = (e) => { state.wrapWithDirectory = e.target.checked }
const onPinUploadChange = (e) => { state.pinUpload = e.target.checked }
if (state.expandOptions) {
return html`
<div id='quickUploadOptions' class='sans-serif mt3 f6 lh-copy light-gray no-user-select'>
<label for='wrapWithDirectory' class='flex items-center db relative mt1 pointer'>
<input id='wrapWithDirectory' type='checkbox' onchange=${onWrapWithDirectoryChange} checked=${state.wrapWithDirectory} />
<span class='mark db flex items-center relative mr2 br2'></span>
${browser.i18n.getMessage('quickUpload_options_wrapWithDirectory')}
</label>
<label for='pinUpload' class='flex items-center db relative mt1 pointer'>
<input id='pinUpload' type='checkbox' onchange=${onPinUploadChange} checked=${state.pinUpload} />
<span class='mark db flex items-center relative mr2 br2'></span>
${browser.i18n.getMessage('quickUpload_options_pinUpload')}
</label>
</div>
`
}
return html`
<button class='mt3 f6 lh-copy link bn bg-transparent moon-gray dib pa0 pointer' style='color: #6ACAD1' onclick=${onExpandOptions}>
${browser.i18n.getMessage('quickUpload_options_show')} »
</button>
`
}

function quickUploadPage (state, emit) {
const onFileInputChange = (e) => emit('fileInputChange', e)
const {peerCount} = state

return html`
<div class="avenir pt5" style="background: linear-gradient(to top, #041727 0%,#043b55 100%); height:100%;">
<div class="montserrat pt5" style="background: linear-gradient(to top, #041727 0%,#043b55 100%); height:100%;">
<div class="mw8 center pa3 white">
<header class="flex items-center">
<header class="flex items-center no-user-select">
${logo({
size: 80,
path: '../../icons',
Expand All @@ -84,8 +128,8 @@ function quickUploadPage (state, emit) {
</p>
</div>
</header>
<label for="quickUploadInput" class='db relative mv5 hover-inner-shadow' style="border:solid 2px #6ACAD1">
<input class="db absolute pointer w-100 h-100 top-0 o-0" type="file" id="quickUploadInput" onchange=${onFileInputChange} />
<label for="quickUploadInput" class='db relative mt5 hover-inner-shadow' style="border:solid 2px #6ACAD1">
<input class="db absolute pointer w-100 h-100 top-0 o-0" type="file" id="quickUploadInput" multiple onchange=${onFileInputChange} />
<div class='dt dim' style='padding-left: 100px; height: 300px'>
<div class='dtc v-mid'>
<span class="f3 link dim br1 ph4 pv3 dib white" style="background: #6ACAD1">
Expand All @@ -101,6 +145,8 @@ function quickUploadPage (state, emit) {
</div>
</div>
</label>
<!-- TODO: enable wrapping in embedded node after js-ipfs release -->
${state.ipfsNodeType === 'external' ? quickUploadOptions(state, emit) : null}
</div>
</div>
`
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"build:copy:wx-polyfill-lib": "shx cp node_modules/webextension-polyfill/dist/browser-polyfill.min.js add-on/dist/contentScripts/browser-polyfill.min.js",
"build:js": "run-p build:js:*",
"build:js:gui": "browserify -p prundupify -g [ uglifyify --compress [ --inline=0 ] ] -t [ browserify-package-json --global ] add-on/src/popup/browser-action/index.js add-on/src/popup/page-action/index.js add-on/src/popup/quick-upload.js -p [ factor-bundle -o add-on/dist/popup/browser-action/browser-action.js -o add-on/dist/popup/page-action/page-action.js -o add-on/dist/popup/quick-upload.js] -o add-on/dist/ipfs-companion-gui-common.js",
"build:js:backend": "browserify -p prundupify -g [ uglifyify --compress [ --inline=0 ] ] -t [ browserify-package-json --global ] add-on/src/background/background.js add-on/src/options/options.js add-on/src/pages/proxy-acl/index.js add-on/src/pages/proxy-access-dialog/index.js -p [ factor-bundle -o add-on/dist/background/background.js -o add-on/dist/options/options.js -o add-on/dist/pages/proxy-acl/proxy-acl.js -o add-on/dist/pages/proxy-access-dialog/proxy-access-dialog.js ] -o add-on/dist/ipfs-companion-common.js",
"build:js:backend": "browserify -p prundupify -g [ uglifyify --compress [ --inline=0 ] ] -t [ browserify-package-json --global ] add-on/src/background/background.js add-on/src/background/big-deps.js add-on/src/options/options.js add-on/src/pages/proxy-acl/index.js add-on/src/pages/proxy-access-dialog/index.js -p [ factor-bundle -o add-on/dist/background/background.js -o add-on/dist/background/big-deps.js -o add-on/dist/options/options.js -o add-on/dist/pages/proxy-acl/proxy-acl.js -o add-on/dist/pages/proxy-access-dialog/proxy-access-dialog.js ] -o add-on/dist/ipfs-companion-common.js",
"build:content-scripts": "run-p build:content-scripts:*",
"build:content-scripts:ipfs-proxy": "run-s build:content-scripts:ipfs-proxy:*",
"build:content-scripts:ipfs-proxy:page": "browserify -p prundupify -g uglifyify -t [ browserify-package-json --global ] add-on/src/contentScripts/ipfs-proxy/page.js -o add-on/dist/contentScripts/ipfs-proxy/page.js",
Expand Down Expand Up @@ -94,7 +94,7 @@
"doc-sniff": "1.0.1",
"file-type": "7.6.0",
"ipfs": "0.28.2",
"ipfs-api": "18.2.0",
"ipfs-api": "21.0.0",
"ipfs-css": "0.3.0",
"ipfs-postmsg-proxy": "2.16.0",
"is-ipfs": "0.3.2",
Expand Down
Loading