diff --git a/Makefile b/Makefile index c4326d4..5d5db15 100755 --- a/Makefile +++ b/Makefile @@ -3,6 +3,28 @@ build: go build gossa.go rm gossa.go +embed: + echo "embedding css and js into binary" + cp main.go gossa.go + perl -pe 's/css_will_be_here/`cat style.css`/ge' -i gossa.go + perl -pe 's/js_will_be_here/`cat script.js`/ge' -i gossa.go + +run: + make build + ./gossa fixture + +ci: + go fmt + go vet + timeout 5 make run & + sleep 1 && go test + +ci-watch: + ls main.go script.js main_test.go | entr -rc make ci + +watch: + ls main.go script.js | entr -rc make run + build-all: make embed env GOOS=linux GOARCH=amd64 go build gossa.go @@ -25,26 +47,3 @@ clean: -rm gossa-linux-arm64 -rm gossa-mac -rm gossa-windows.exe - -embed: - echo "embedding css and js into binary" - cp main.go gossa.go - perl -pe 's/css_will_be_here/`cat style.css`/ge' -i gossa.go - perl -pe 's/js_will_be_here/`cat script.js`/ge' -i gossa.go - -ci: - go fmt - go vet - timeout 5 go run main.go fixture & - sleep 1 && go test - -ci-watch: - ls main.go script.js main_test.go | entr -rc make ci - -watch: - ls main.go script.js | entr -rc make run - -run: - make embed - go run gossa.go fixture - rm gossa.go diff --git a/readme.md b/readme.md index ec68ba1..ab49e1b 100644 --- a/readme.md +++ b/readme.md @@ -8,19 +8,20 @@ gossa 🎶 A fast and simple webserver for your files. It's dependency-free and with under 250 lines for the server code, easily code-reviewable. ### features - * upload files and folders with drag-and-drop * browse throughout files/directories + * upload files and folders with drag-and-drop * create new folders + * move files to different directories with drag-and-drop and keyboard * browse throughout pictures with a full-screen carousel * simple keyboard navigation/shortcuts * fast ; fills my 80MB/s AC wifi link ### run ```sh -# run -go run main.go fixture +# run on test fixture folder +make run -# build embedding the js/css in the binary +# build make ./gossa --help @@ -32,6 +33,8 @@ make ci * Arrows/Enter browse throughout the files/directories and pictures * Ctrl/Meta + C copy selected path to clipboard * Ctrl/Meta + D create a new directory + * Ctrl/Meta + X cut selected path + * Ctrl/Meta + V paste paths previously selected with the above shortcut to directory * \ search on first letters in filename ### built blobs diff --git a/script.js b/script.js index d6e5edc..274be6b 100755 --- a/script.js +++ b/script.js @@ -1,5 +1,4 @@ /* eslint-env browser */ -/* global allA */ /* eslint-disable no-multi-str */ function cancelDefault (e) { @@ -9,10 +8,6 @@ function cancelDefault (e) { // RPC function rpcFs (call, args, cb) { - // Prefix path with pwd if not absolute - const decodedPath = decodeURI(location.pathname) - args = args.map(a => a.startsWith('/') ? a : decodedPath + a) - console.log('RPC', call, args) const xhr = new window.XMLHttpRequest() xhr.open('POST', location.origin + '/rpc') @@ -21,8 +16,10 @@ function rpcFs (call, args, cb) { xhr.onload = cb } +const prependPath = (a) => a.startsWith('/') ? a : decodeURI(location.pathname) + a + // RPC Handlers -const mkdirCall = (path, cb) => rpcFs('mkdirp', [path], cb) +const mkdirCall = (path, cb) => rpcFs('mkdirp', [prependPath(path)], cb) const mvCall = (path1, path2, cb) => rpcFs('mv', [path1, path2], cb) @@ -178,9 +175,9 @@ document.ondrop = (e) => { const t = e.target.classList.contains('fav') ? e.target : getLink(e) if (!t || !t.innerText.endsWith('/')) return e.dataTransfer.items[0].getAsString(s => { - const root = decodeURI(s.replace(location.href, '')) + const root = decodeURIComponent(s.replace(location.href, '')) const dest = t.innerText + root - mvCall(root, dest, refresh) + mvCall(prependPath(root), prependPath(dest), refresh) }) } else { Array.from(e.dataTransfer.items).forEach(pushEntry) @@ -360,6 +357,18 @@ function setCursorToClosestTyped () { restoreCursorPos() } +let cuts = [] + +function onPaste () { + if (!cuts.length) { return refresh() } + const root = cuts.pop() + const pwd = decodeURIComponent(location.pathname) + const isFolderDest = getASelected().innerText.endsWith('/') + const filename = root.split('/').pop() + const dest = isFolderDest ? pwd + getASelected().innerText : pwd + mvCall(root, dest + filename, onPaste) +} + // Kb handler document.body.addEventListener('keydown', e => { switch (e.code) { @@ -373,7 +382,6 @@ document.body.addEventListener('keydown', e => { return picsNav(false) || moveArrow(false) case 'Enter': - case 'Space': case 'ArrowRight': e.preventDefault() return picsOn(true) || picsNav(true) || getASelected().click() @@ -399,6 +407,16 @@ document.body.addEventListener('keydown', e => { case 'KeyC': e.preventDefault() return isPicMode() || cpPath() + + case 'KeyX': + e.preventDefault() + const x = decodeURIComponent(getASelected().href).replace(location.origin, '') + cuts.push(prependPath(x)) + return false + + case 'KeyV': + e.preventDefault() + return onPaste() } }