mirror of
https://github.com/pldubouilh/gossa.git
synced 2026-09-04 08:07:22 -04:00
add rm/rename commands
This commit is contained in:
+1
-1
@@ -2,7 +2,7 @@ debug
|
|||||||
test
|
test
|
||||||
gossa.go
|
gossa.go
|
||||||
gossa
|
gossa
|
||||||
gossa-linux
|
gossa-linux64
|
||||||
gossa-linux-arm
|
gossa-linux-arm
|
||||||
gossa-linux-arm64
|
gossa-linux-arm64
|
||||||
gossa-mac
|
gossa-mac
|
||||||
|
|||||||
@@ -5,17 +5,19 @@ gossa
|
|||||||
|
|
||||||
[](https://travis-ci.org/pldubouilh/gossa)
|
[](https://travis-ci.org/pldubouilh/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.
|
🎶 A fast and simple webserver for your files, that's dependency-free and with under 240 lines for the server code, easily code-reviewable.
|
||||||
|
|
||||||
### features
|
### features
|
||||||
* browse through files/directories
|
* browse through files/directories
|
||||||
* upload with drag-and-drop
|
* upload with drag-and-drop
|
||||||
* create new folders
|
* move/rename/delete files
|
||||||
* move files with drag-and-drop and keyboard
|
|
||||||
* browse through pictures with a full-screen carousel
|
* browse through pictures with a full-screen carousel
|
||||||
* simple keyboard navigation/shortcuts
|
* simple keyboard navigation/shortcuts
|
||||||
* fast ; fills my 80MB/s AC wifi link
|
* fast ; fills my 80MB/s AC wifi link
|
||||||
|
|
||||||
|
### built blobs
|
||||||
|
built blobs are available on the [release page](https://github.com/pldubouilh/gossa/releases).
|
||||||
|
|
||||||
### run
|
### run
|
||||||
```sh
|
```sh
|
||||||
# build
|
# build
|
||||||
@@ -26,15 +28,26 @@ make
|
|||||||
```
|
```
|
||||||
|
|
||||||
### keyboard shortcuts
|
### keyboard shortcuts
|
||||||
* Arrows/Enter browse throughout the files/directories and pictures
|
|shortcut | action|
|
||||||
* Ctrl/Meta + C copy URL to clipboard
|
|-------------|-------------|
|
||||||
* Ctrl/Meta + D create a new directory
|
|Arrows/Enter | browse through files/directories and pictures|
|
||||||
* Ctrl/Meta + X cut selected path
|
|Ctrl/Meta + C | copy URL to clipboard|
|
||||||
* Ctrl/Meta + V paste previously selected paths to directory
|
|Ctrl/Meta + E | rename file/folder|
|
||||||
* \<any letter\> search
|
|Ctrl/Meta + Del | delete file/folder|
|
||||||
|
|Ctrl/Meta + D | create a new directory|
|
||||||
|
|Ctrl/Meta + X | cut selected path|
|
||||||
|
|Ctrl/Meta + V | paste previously selected paths to directory|
|
||||||
|
|\<any letter\> | search|
|
||||||
|
|
||||||
### built blobs
|
### ui shortcuts
|
||||||
built blobs are available on the [release page](https://github.com/pldubouilh/gossa/releases).
|
|shortcut | action|
|
||||||
|
| ------------- |-------------|
|
||||||
|
|click new folder icon | create new folder|
|
||||||
|
|click images icon | toggle image carousel|
|
||||||
|
|click file icon | rename item|
|
||||||
|
|double click file icon | delete item|
|
||||||
|
|drag-and-drop item on UI | move item|
|
||||||
|
|drag-and-drop external item | upload file/folders|
|
||||||
|
|
||||||
### using with docker
|
### using with docker
|
||||||
a pretty short docker file is provided
|
a pretty short docker file is provided
|
||||||
|
|||||||
+3
-1
@@ -67,7 +67,7 @@ func row(name string, href string, size float64, ext string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return `<tr>
|
return `<tr>
|
||||||
<td><i class="btn icon icon-` + strings.ToLower(ext) + ` icon-blank"></i></td>
|
<td><i ondblclick="return rm(event)" onclick="return rename(event)" class="btn icon icon-` + strings.ToLower(ext) + ` icon-blank"></i></td>
|
||||||
<td class="file-size"><code>` + sizeToString(size) + `</code></td>
|
<td class="file-size"><code>` + sizeToString(size) + `</code></td>
|
||||||
<td class="arrow"><i class="arrow-icon"></i></td>
|
<td class="arrow"><i class="arrow-icon"></i></td>
|
||||||
<td class="display-name"><a class="list-links" onclick="return onClickLink(event)" href="` + url.PathEscape(href) + `">` + name + `</a></td>
|
<td class="display-name"><a class="list-links" onclick="return onClickLink(event)" href="` + url.PathEscape(href) + `">` + name + `</a></td>
|
||||||
@@ -185,6 +185,8 @@ func rpc(w http.ResponseWriter, r *http.Request) {
|
|||||||
err = os.MkdirAll(payload.Args[0], os.ModePerm)
|
err = os.MkdirAll(payload.Args[0], os.ModePerm)
|
||||||
} else if payload.Call == "mv" {
|
} else if payload.Call == "mv" {
|
||||||
err = os.Rename(payload.Args[0], payload.Args[1])
|
err = os.Rename(payload.Args[0], payload.Args[1])
|
||||||
|
} else if payload.Call == "rm" {
|
||||||
|
err = os.Remove(payload.Args[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
logVerb("RPC", err, payload)
|
logVerb("RPC", err, payload)
|
||||||
|
|||||||
+21
-4
@@ -77,7 +77,7 @@ func testDefaults(t *testing.T, url string) string {
|
|||||||
t.Fatal("error 中文 folder")
|
t.Fatal("error 中文 folder")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !strings.Contains(bodyStr, `<tr> <td><i class="btn icon icon-types icon-blank"></i></td> <td class="file-size"><code>0.2k</code></td> <td class="arrow"><i class="arrow-icon"></i></td> <td class="display-name"><a class="list-links" onclick="return onClickLink(event)" href="custom_mime_type.types">custom_mime_type.types</a></td> </tr>`) {
|
if !strings.Contains(bodyStr, `<tr> <td><i ondblclick="return rm(event)" onclick="return rename(event)" class="btn icon icon-types icon-blank"></i></td> <td class="file-size"><code>0.2k</code></td> <td class="arrow"><i class="arrow-icon"></i></td> <td class="display-name"><a class="list-links" onclick="return onClickLink(event)" href="custom_mime_type.types">custom_mime_type.types</a></td> </tr>`) {
|
||||||
t.Fatal("error row custom_mime_type")
|
t.Fatal("error row custom_mime_type")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +116,7 @@ func TestGetFolder(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bodyStr = testDefaults(t, "http://127.0.0.1:8001/")
|
bodyStr = testDefaults(t, "http://127.0.0.1:8001/")
|
||||||
if !strings.Contains(bodyStr, `<tr> <td><i class="btn icon icon-folder icon-blank"></i></td> <td class="file-size"><code>0</code></td> <td class="arrow"><i class="arrow-icon"></i></td> <td class="display-name"><a class="list-links" onclick="return onClickLink(event)" href="AAA">AAA/</a></td> </tr>`) {
|
if !strings.Contains(bodyStr, `<tr> <td><i ondblclick="return rm(event)" onclick="return rename(event)" class="btn icon icon-folder icon-blank"></i></td> <td class="file-size"><code>0</code></td> <td class="arrow"><i class="arrow-icon"></i></td> <td class="display-name"><a class="list-links" onclick="return onClickLink(event)" href="AAA">AAA/</a></td> </tr>`) {
|
||||||
t.Fatal("error new folder created")
|
t.Fatal("error new folder created")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,7 +140,7 @@ func TestGetFolder(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bodyStr = testDefaults(t, "http://127.0.0.1:8001/")
|
bodyStr = testDefaults(t, "http://127.0.0.1:8001/")
|
||||||
if strings.Contains(bodyStr, `<tr> <td><i class="btn icon icon-folder icon-blank"></i></td> <td class="file-size"><code>0</code></td> <td class="arrow"><i class="arrow-icon"></i></td> <td class="display-name"><a class="list-links" onclick="return onClickLink(event)" href="AAA">AAA/</a></td> </tr>`) {
|
if strings.Contains(bodyStr, `<tr> <td><i ondblclick="return rm(event)" onclick="return rename(event)" class="btn icon icon-folder icon-blank"></i></td> <td class="file-size"><code>0</code></td> <td class="arrow"><i class="arrow-icon"></i></td> <td class="display-name"><a class="list-links" onclick="return onClickLink(event)" href="AAA">AAA/</a></td> </tr>`) {
|
||||||
t.Fatal("error folder moved")
|
t.Fatal("error folder moved")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,7 +157,7 @@ func TestGetFolder(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bodyStr = testDefaults(t, "http://127.0.0.1:8001/")
|
bodyStr = testDefaults(t, "http://127.0.0.1:8001/")
|
||||||
if !strings.Contains(bodyStr, `<tr> <td><i class="btn icon icon-하 하 icon-blank"></i></td> <td class="file-size"><code>0.0k</code></td> <td class="arrow"><i class="arrow-icon"></i></td> <td class="display-name"><a class="list-links" onclick="return onClickLink(event)" href="%E1%84%92%E1%85%A1%20%E1%84%92%E1%85%A1">하 하</a></td> </tr>`) {
|
if !strings.Contains(bodyStr, `<tr> <td><i ondblclick="return rm(event)" onclick="return rename(event)" class="btn icon icon-하 하 icon-blank"></i></td> <td class="file-size"><code>0.0k</code></td> <td class="arrow"><i class="arrow-icon"></i></td> <td class="display-name"><a class="list-links" onclick="return onClickLink(event)" href="%E1%84%92%E1%85%A1%20%E1%84%92%E1%85%A1">하 하</a></td> </tr>`) {
|
||||||
t.Fatal("error checking new file row")
|
t.Fatal("error checking new file row")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,4 +167,21 @@ func TestGetFolder(t *testing.T) {
|
|||||||
if !strings.Contains(bodyStr, `err`) {
|
if !strings.Contains(bodyStr, `err`) {
|
||||||
t.Fatal("error not returned")
|
t.Fatal("error not returned")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ~~~~~~~~~~~~~~~~~
|
||||||
|
fmt.Println("\r\n~~~~~~~~~~ test rm rpc & cleanup")
|
||||||
|
bodyStr = postJSON(t, "http://127.0.0.1:8001/rpc", `{"call":"rm","args":["/hols/AAA"]}`)
|
||||||
|
if !strings.Contains(bodyStr, `ok`) {
|
||||||
|
t.Fatal("error returned value")
|
||||||
|
}
|
||||||
|
|
||||||
|
bodyStr = get(t, "http://127.0.0.1:8001/hols/AAA")
|
||||||
|
if !strings.Contains(bodyStr, `error`) {
|
||||||
|
t.Fatal("error not returned")
|
||||||
|
}
|
||||||
|
|
||||||
|
bodyStr = postJSON(t, "http://127.0.0.1:8001/rpc", `{"call":"rm","args":["/하 하"]}`)
|
||||||
|
if !strings.Contains(bodyStr, `ok`) {
|
||||||
|
t.Fatal("error returned value")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+85
-80
@@ -6,9 +6,8 @@ function cancelDefault (e) {
|
|||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
}
|
}
|
||||||
|
|
||||||
function warning (e) {
|
const warningMsg = () => 'Leaving will interrupt transfer?\n'
|
||||||
return 'Leaving will interrupt transfer\n?'
|
const rmMsg = () => !confirm('Remove file?\n')
|
||||||
}
|
|
||||||
|
|
||||||
const barName = document.getElementById('dlBarName')
|
const barName = document.getElementById('dlBarName')
|
||||||
const barPc = document.getElementById('dlBarPc')
|
const barPc = document.getElementById('dlBarPc')
|
||||||
@@ -17,16 +16,21 @@ const upGrid = document.getElementById('drop-grid')
|
|||||||
const pics = document.getElementById('pics')
|
const pics = document.getElementById('pics')
|
||||||
const picsHolder = document.getElementById('picsHolder')
|
const picsHolder = document.getElementById('picsHolder')
|
||||||
const picsLabel = document.getElementById('picsLabel')
|
const picsLabel = document.getElementById('picsLabel')
|
||||||
window.picsToggle = picsToggle
|
|
||||||
|
|
||||||
|
// helpers
|
||||||
let allA
|
let allA
|
||||||
let imgsIndex
|
let imgsIndex
|
||||||
let allImgs
|
let allImgs
|
||||||
|
const decode = a => decodeURIComponent(a).replace(location.origin, '')
|
||||||
|
const getArrowSelected = () => document.querySelectorAll('i.arrow-selected')[0]
|
||||||
|
const getASelected = () => !getArrowSelected() ? false : getArrowSelected().parentElement.parentElement.querySelectorAll('a')[0]
|
||||||
|
const prependPath = a => a.startsWith('/') ? a : decodeURI(location.pathname) + a
|
||||||
|
const prevent = e => e.preventDefault()
|
||||||
|
|
||||||
// Soft nav
|
// Soft nav
|
||||||
function browseTo (href) {
|
function browseTo (href) {
|
||||||
window.fetch(href).then(r => r.text().then(t => {
|
fetch(href).then(r => r.text().then(t => {
|
||||||
const parsed = new window.DOMParser().parseFromString(t, 'text/html')
|
const parsed = new DOMParser().parseFromString(t, 'text/html')
|
||||||
const table = parsed.querySelectorAll('table')[0].innerHTML
|
const table = parsed.querySelectorAll('table')[0].innerHTML
|
||||||
document.body.querySelectorAll('table')[0].innerHTML = table
|
document.body.querySelectorAll('table')[0].innerHTML = table
|
||||||
|
|
||||||
@@ -35,7 +39,7 @@ function browseTo (href) {
|
|||||||
if (document.head.querySelectorAll('title')[0].innerText !== title) {
|
if (document.head.querySelectorAll('title')[0].innerText !== title) {
|
||||||
document.head.querySelectorAll('title')[0].innerText = title
|
document.head.querySelectorAll('title')[0].innerText = title
|
||||||
document.body.querySelectorAll('h1')[0].innerText = '.' + title
|
document.body.querySelectorAll('h1')[0].innerText = '.' + title
|
||||||
window.history.pushState({}, '', window.encodeURI(title))
|
history.pushState({}, '', encodeURI(title))
|
||||||
}
|
}
|
||||||
|
|
||||||
init()
|
init()
|
||||||
@@ -55,24 +59,20 @@ window.onClickLink = e => {
|
|||||||
|
|
||||||
const refresh = () => browseTo(location.href)
|
const refresh = () => browseTo(location.href)
|
||||||
const prevPage = () => browseTo(location.href + '../')
|
const prevPage = () => browseTo(location.href + '../')
|
||||||
const getArrowSelected = () => document.querySelectorAll('i.arrow-selected')[0]
|
|
||||||
const getASelected = () => !getArrowSelected() ? false : getArrowSelected().parentElement.parentElement.querySelectorAll('a')[0]
|
|
||||||
window.onpopstate = prevPage
|
window.onpopstate = prevPage
|
||||||
|
|
||||||
// RPC
|
// RPC
|
||||||
function rpcFs (call, args, cb) {
|
function rpcFs (call, args, cb) {
|
||||||
console.log('RPC', call, args)
|
console.log('RPC', call, args)
|
||||||
const xhr = new window.XMLHttpRequest()
|
const xhr = new XMLHttpRequest()
|
||||||
xhr.open('POST', location.origin + '/rpc')
|
xhr.open('POST', location.origin + '/rpc')
|
||||||
xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8')
|
xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8')
|
||||||
xhr.send(JSON.stringify({ call, args }))
|
xhr.send(JSON.stringify({ call, args }))
|
||||||
xhr.onload = cb
|
xhr.onload = cb
|
||||||
}
|
}
|
||||||
|
|
||||||
const prependPath = (a) => a.startsWith('/') ? a : decodeURI(location.pathname) + a
|
|
||||||
|
|
||||||
const mkdirCall = (path, cb) => rpcFs('mkdirp', [prependPath(path)], cb)
|
const mkdirCall = (path, cb) => rpcFs('mkdirp', [prependPath(path)], cb)
|
||||||
|
const rmCall = (path1, cb) => rpcFs('rm', [prependPath(path1)], cb)
|
||||||
const mvCall = (path1, path2, cb) => rpcFs('mv', [path1, path2], cb)
|
const mvCall = (path1, path2, cb) => rpcFs('mv', [path1, path2], cb)
|
||||||
|
|
||||||
// File upload
|
// File upload
|
||||||
@@ -81,7 +81,8 @@ let totalUploads = 0
|
|||||||
let totalUploadsSize = 0
|
let totalUploadsSize = 0
|
||||||
let totalUploadedSize = []
|
let totalUploadedSize = []
|
||||||
|
|
||||||
const checkDupes = test => allA.find(a => a.innerText.replace('/', '') === test)
|
const dupe = test => allA.find(a => a.innerText.replace('/', '') === test)
|
||||||
|
const isDupe = t => dupe(t) ? alert(t + ' already already exists') || true : false
|
||||||
|
|
||||||
function shouldRefresh () {
|
function shouldRefresh () {
|
||||||
totalDone += 1
|
totalDone += 1
|
||||||
@@ -107,17 +108,17 @@ function updatePercent (ev) {
|
|||||||
|
|
||||||
function postFile (file, path) {
|
function postFile (file, path) {
|
||||||
path = decodeURI(location.pathname).slice(0, -1) + path
|
path = decodeURI(location.pathname).slice(0, -1) + path
|
||||||
window.onbeforeunload = warning
|
window.onbeforeunload = warningMsg
|
||||||
|
|
||||||
barDiv.style.display = 'block'
|
barDiv.style.display = 'block'
|
||||||
totalUploads += 1
|
totalUploads += 1
|
||||||
totalUploadsSize += file.size
|
totalUploadsSize += file.size
|
||||||
barName.innerText = totalUploads > 1 ? totalUploads + ' files' : file.name
|
barName.innerText = totalUploads > 1 ? totalUploads + ' files' : file.name
|
||||||
|
|
||||||
const formData = new window.FormData()
|
const formData = new FormData()
|
||||||
formData.append(file.name, file)
|
formData.append(file.name, file)
|
||||||
|
|
||||||
const xhr = new window.XMLHttpRequest()
|
const xhr = new XMLHttpRequest()
|
||||||
xhr.open('POST', location.origin + '/post')
|
xhr.open('POST', location.origin + '/post')
|
||||||
xhr.setRequestHeader('gossa-path', encodeURIComponent(path))
|
xhr.setRequestHeader('gossa-path', encodeURIComponent(path))
|
||||||
xhr.upload.addEventListener('load', shouldRefresh)
|
xhr.upload.addEventListener('load', shouldRefresh)
|
||||||
@@ -126,15 +127,12 @@ function postFile (file, path) {
|
|||||||
xhr.send(formData)
|
xhr.send(formData)
|
||||||
}
|
}
|
||||||
|
|
||||||
const parseDomFolder = f => {
|
const parseDomFolder = f => f.createReader().readEntries(e => e.forEach(i => parseDomItem(i)))
|
||||||
f.createReader().readEntries(e => e.forEach(i => parseDomItem(i)))
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseDomItem (domFile, shoudCheckDupes) {
|
function parseDomItem (domFile, shoudCheckDupes) {
|
||||||
if (shoudCheckDupes && checkDupes(domFile.name)) {
|
if (shoudCheckDupes && isDupe(domFile.name)) {
|
||||||
return window.alert(domFile.name + ' already exists !')
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (domFile.isFile) {
|
if (domFile.isFile) {
|
||||||
domFile.file(f => postFile(f, domFile.fullPath))
|
domFile.file(f => postFile(f, domFile.fullPath))
|
||||||
} else {
|
} else {
|
||||||
@@ -146,7 +144,7 @@ function parseDomItem (domFile, shoudCheckDupes) {
|
|||||||
|
|
||||||
function pushEntry (entry) {
|
function pushEntry (entry) {
|
||||||
if (!entry.webkitGetAsEntry && !entry.getAsEntry) {
|
if (!entry.webkitGetAsEntry && !entry.getAsEntry) {
|
||||||
return window.alert('Unsupported browser ! Please update to chrome/firefox.')
|
return alert('Unsupported browser ! Please update to chrome/firefox.')
|
||||||
} else {
|
} else {
|
||||||
entry = entry.webkitGetAsEntry() || entry.getAsEntry()
|
entry = entry.webkitGetAsEntry() || entry.getAsEntry()
|
||||||
}
|
}
|
||||||
@@ -165,7 +163,7 @@ const setBackgroundLinks = t => { t.style.backgroundColor = 'rgba(123, 123, 123,
|
|||||||
|
|
||||||
const getLink = e => e.target.parentElement.querySelectorAll('a.list-links')[0]
|
const getLink = e => e.target.parentElement.querySelectorAll('a.list-links')[0]
|
||||||
|
|
||||||
document.ondragenter = (e) => {
|
document.ondragenter = e => {
|
||||||
if (isPicMode()) { return }
|
if (isPicMode()) { return }
|
||||||
cancelDefault(e)
|
cancelDefault(e)
|
||||||
|
|
||||||
@@ -183,18 +181,18 @@ document.ondragenter = (e) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
upGrid.ondragleave = (e) => {
|
upGrid.ondragleave = e => {
|
||||||
cancelDefault(e)
|
cancelDefault(e)
|
||||||
upGrid.style.display = 'none'
|
upGrid.style.display = 'none'
|
||||||
}
|
}
|
||||||
|
|
||||||
document.ondragover = (e) => {
|
document.ondragover = e => {
|
||||||
cancelDefault(e)
|
cancelDefault(e)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle drop - upload or move
|
// Handle drop - upload or move
|
||||||
document.ondrop = (e) => {
|
document.ondrop = e => {
|
||||||
cancelDefault(e)
|
cancelDefault(e)
|
||||||
upGrid.style.display = 'none'
|
upGrid.style.display = 'none'
|
||||||
resetBackgroundLinks()
|
resetBackgroundLinks()
|
||||||
@@ -216,15 +214,34 @@ document.ondrop = (e) => {
|
|||||||
|
|
||||||
// Mkdir icon
|
// Mkdir icon
|
||||||
window.mkdirBtn = function () {
|
window.mkdirBtn = function () {
|
||||||
const folder = window.prompt('New folder name', '')
|
const folder = prompt('new folder name', '')
|
||||||
|
if (folder && !isDupe(folder)) {
|
||||||
|
mkdirCall(folder, refresh)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!folder) {
|
// Icon click handler
|
||||||
|
const getBtnA = e => e.target.parentElement.parentElement.querySelector('a')
|
||||||
|
|
||||||
|
window.rm = e => {
|
||||||
|
clearTimeout(window.clickToken)
|
||||||
|
const path = e.key ? getASelected().href : getBtnA(e).pathname
|
||||||
|
rmMsg() || rmCall(decode(path), refresh)
|
||||||
|
}
|
||||||
|
|
||||||
|
window.rename = (e, commit) => {
|
||||||
|
clearTimeout(window.clickToken)
|
||||||
|
|
||||||
|
if (!commit) {
|
||||||
|
window.clickToken = setTimeout(window.rename, 300, e, true)
|
||||||
return
|
return
|
||||||
} else if (checkDupes(folder)) {
|
|
||||||
return window.alert('Name already already exists')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mkdirCall(folder, refresh)
|
const orig = e.key ? getASelected().innerText : getBtnA(e).innerText
|
||||||
|
const chg = prompt('rename to', orig)
|
||||||
|
if (chg && !isDupe(chg)) {
|
||||||
|
mvCall(prependPath(orig), prependPath(chg), refresh)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keyboard Arrow
|
// Keyboard Arrow
|
||||||
@@ -232,7 +249,9 @@ const storeLastArrowSrc = src => localStorage.setItem('last-selected' + location
|
|||||||
|
|
||||||
function scrollToArrow () {
|
function scrollToArrow () {
|
||||||
const pos = getArrowSelected().getBoundingClientRect()
|
const pos = getArrowSelected().getBoundingClientRect()
|
||||||
window.scrollTo(0, pos.y)
|
if (pos.top < 0 || pos.bottom > window.innerHeight) {
|
||||||
|
setTimeout(scrollTo, 50, 0, pos.y)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearArrowSelected () {
|
function clearArrowSelected () {
|
||||||
@@ -277,13 +296,13 @@ function moveArrow (down) {
|
|||||||
const itemPos = all[i].getBoundingClientRect()
|
const itemPos = all[i].getBoundingClientRect()
|
||||||
|
|
||||||
if (i === 0) {
|
if (i === 0) {
|
||||||
window.scrollTo(0, 0)
|
scrollTo(0, 0)
|
||||||
} else if (i === all.length - 1) {
|
} else if (i === all.length - 1) {
|
||||||
window.scrollTo(0, document.documentElement.scrollHeight)
|
scrollTo(0, document.documentElement.scrollHeight)
|
||||||
} else if (itemPos.top < 0) {
|
} else if (itemPos.top < 0) {
|
||||||
window.scrollBy(0, -200)
|
scrollBy(0, -200)
|
||||||
} else if (itemPos.bottom > window.innerHeight) {
|
} else if (itemPos.bottom > window.innerHeight) {
|
||||||
window.scrollBy(0, 200)
|
scrollBy(0, 200)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,41 +312,33 @@ const isPic = src => src && picTypes.find(type => src.toLocaleLowerCase().includ
|
|||||||
const isPicMode = () => pics.style.display === 'flex'
|
const isPicMode = () => pics.style.display === 'flex'
|
||||||
window.picsNav = () => picsNav(true)
|
window.picsNav = () => picsNav(true)
|
||||||
|
|
||||||
function setImage (src) {
|
function setImage () {
|
||||||
src = src || allImgs[imgsIndex]
|
const src = allImgs[imgsIndex]
|
||||||
picsLabel.innerText = src.split('/').pop()
|
|
||||||
picsHolder.src = src
|
picsHolder.src = src
|
||||||
|
picsLabel.innerText = src.split('/').pop()
|
||||||
storeLastArrowSrc(src)
|
storeLastArrowSrc(src)
|
||||||
|
restoreCursorPos()
|
||||||
}
|
}
|
||||||
|
|
||||||
function picsOn (ifImgSelected, href) {
|
function picsOn (ifImgSelected, href) {
|
||||||
href = href || getASelected().href
|
href = href || getASelected().href
|
||||||
|
|
||||||
if (isPicMode()) {
|
if (isPicMode() || (ifImgSelected && !isPic(href))) {
|
||||||
return false
|
|
||||||
} else if (ifImgSelected && !isPic(href)) {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isPic(href)) {
|
if (isPic(href)) {
|
||||||
imgsIndex = allImgs.findIndex(el => el.includes(href))
|
imgsIndex = allImgs.findIndex(el => el.includes(href))
|
||||||
setImage()
|
|
||||||
} else {
|
|
||||||
setImage(picsHolder.src)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setImage()
|
||||||
pics.style.display = 'flex'
|
pics.style.display = 'flex'
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
function picsToggle () {
|
const picsOff = () => { pics.style.display = 'none' }
|
||||||
if (!isPicMode()) {
|
|
||||||
picsOn()
|
window.picsToggle = () => isPicMode() ? picsOff() : picsOn()
|
||||||
} else {
|
|
||||||
pics.style.display = 'none'
|
|
||||||
restoreCursorPos()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function picsNav (down) {
|
function picsNav (down) {
|
||||||
if (!isPicMode()) { return false }
|
if (!isPicMode()) { return false }
|
||||||
@@ -378,56 +389,50 @@ document.body.addEventListener('keydown', e => {
|
|||||||
switch (e.code) {
|
switch (e.code) {
|
||||||
case 'Tab':
|
case 'Tab':
|
||||||
case 'ArrowDown':
|
case 'ArrowDown':
|
||||||
e.preventDefault()
|
return prevent(e) || picsNav(true) || moveArrow(true)
|
||||||
return picsNav(true) || moveArrow(true)
|
|
||||||
|
|
||||||
case 'ArrowUp':
|
case 'ArrowUp':
|
||||||
e.preventDefault()
|
return prevent(e) || picsNav(false) || moveArrow(false)
|
||||||
return picsNav(false) || moveArrow(false)
|
|
||||||
|
|
||||||
case 'Enter':
|
case 'Enter':
|
||||||
case 'ArrowRight':
|
case 'ArrowRight':
|
||||||
e.preventDefault()
|
return prevent(e) || picsOn(true) || picsNav(true) || getASelected().click()
|
||||||
return picsOn(true) || picsNav(true) || getASelected().click()
|
|
||||||
|
|
||||||
case 'ArrowLeft':
|
case 'ArrowLeft':
|
||||||
e.preventDefault()
|
return prevent(e) || picsNav(false) || prevPage()
|
||||||
return picsNav(false) || prevPage()
|
|
||||||
|
|
||||||
case 'Escape':
|
case 'Escape':
|
||||||
if (isPicMode()) {
|
return prevent(e) || picsOff()
|
||||||
e.preventDefault()
|
|
||||||
return picsToggle()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ctrl keys
|
// Ctrl keys
|
||||||
if (e.ctrlKey || e.metaKey) {
|
if (e.ctrlKey || e.metaKey) {
|
||||||
switch (e.code) {
|
switch (e.code) {
|
||||||
case 'KeyD':
|
|
||||||
e.preventDefault()
|
|
||||||
return isPicMode() || window.mkdirBtn()
|
|
||||||
|
|
||||||
case 'KeyC':
|
case 'KeyC':
|
||||||
e.preventDefault()
|
return prevent(e) || isPicMode() || cpPath()
|
||||||
return isPicMode() || cpPath()
|
|
||||||
|
|
||||||
case 'KeyX':
|
case 'KeyX':
|
||||||
e.preventDefault()
|
cuts.push(prependPath(decode(getASelected().href)))
|
||||||
const x = decodeURIComponent(getASelected().href).replace(location.origin, '')
|
return prevent(e) || false
|
||||||
cuts.push(prependPath(x))
|
|
||||||
return false
|
|
||||||
|
|
||||||
case 'KeyV':
|
case 'KeyV':
|
||||||
e.preventDefault()
|
return prevent(e) || onPaste()
|
||||||
return onPaste()
|
|
||||||
|
case 'Backspace':
|
||||||
|
return prevent(e) || isPicMode() || window.rm(e)
|
||||||
|
|
||||||
|
case 'KeyE':
|
||||||
|
return prevent(e) || isPicMode() || window.rename(e)
|
||||||
|
|
||||||
|
case 'KeyD':
|
||||||
|
return prevent(e) || isPicMode() || window.mkdirBtn()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// text search
|
// text search
|
||||||
if (e.code.includes('Key')) {
|
if (e.code.includes('Key')) {
|
||||||
typedPath += e.code.replace('Key', '').toLocaleLowerCase()
|
typedPath += e.code.replace('Key', '').toLocaleLowerCase()
|
||||||
window.clearTimeout(typedToken)
|
clearTimeout(typedToken)
|
||||||
typedToken = setTimeout(() => { typedPath = '' }, 1000)
|
typedToken = setTimeout(() => { typedPath = '' }, 1000)
|
||||||
setCursorToClosestTyped()
|
setCursorToClosestTyped()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
width: 16px;
|
width: 16px;
|
||||||
zoom: 1.2;
|
zoom: 1.2;
|
||||||
margin: 1px;
|
margin: 1px;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.arrow-icon {
|
.arrow-icon {
|
||||||
|
|||||||
Reference in New Issue
Block a user