diff --git a/frontend/src/css/_share.css b/frontend/src/css/_share.css index 9e1b3528..a9c4e624 100644 --- a/frontend/src/css/_share.css +++ b/frontend/src/css/_share.css @@ -49,11 +49,17 @@ } .share__box__items #listing.list .item { - cursor: auto; + cursor: pointer; border-left: 0; border-right: 0; border-bottom: 0; border-top: 1px solid rgba(0, 0, 0, 0.1); + -webkit-user-select:none; + -khtml-user-select:none; + -moz-user-select:none; + -ms-user-select:none; + -o-user-select:none; + user-select:none; } .share__box__items #listing.list .item .name { diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json index a925c0c4..96d3ad8b 100644 --- a/frontend/src/i18n/en.json +++ b/frontend/src/i18n/en.json @@ -245,6 +245,7 @@ }, "download": { "downloadFile": "Download File", - "downloadFolder": "Download Folder" + "downloadFolder": "Download Folder", + "downloadSelected": "Download Selected" } } diff --git a/frontend/src/i18n/zh-cn.json b/frontend/src/i18n/zh-cn.json index 67564253..6c323786 100644 --- a/frontend/src/i18n/zh-cn.json +++ b/frontend/src/i18n/zh-cn.json @@ -242,6 +242,7 @@ }, "download": { "downloadFile": "下载文件", - "downloadFolder": "下载文件夹" + "downloadFolder": "下载文件夹", + "downloadSelected": "下载已选" } } \ No newline at end of file diff --git a/frontend/src/views/Share.vue b/frontend/src/views/Share.vue index 53dc681b..cb1240b1 100644 --- a/frontend/src/views/Share.vue +++ b/frontend/src/views/Share.vue @@ -13,7 +13,7 @@
-
+
- {{ item.isDir ? 'folder' : (item.type==='image') ? 'insert_photo' : 'insert_drive_file' }} + {{ item.isDir ? 'folder' : (item.type==='image') ? 'insert_photo' : 'insert_drive_file' }}
-

{{ item.name }}

+

{{ item.name }}

@@ -74,7 +78,9 @@ export default { loaded: false, notFound: false, file: null, - showLimit: 500 + showLimit: 500, + selected: [], + firstSelected: -1 }), watch: { '$route': 'fetchData' @@ -83,6 +89,9 @@ export default { this.fetchData() }, computed: { + multiple: function () { + return this.selected.length > 0 + }, hash: function () { if (this.$route.params.pathMatch[this.$route.params.pathMatch.length - 1] !== '/') return this.$route.params.pathMatch + '/' return this.$route.params.pathMatch @@ -91,7 +100,12 @@ export default { return this.$route.params.pathMatch.split('/')[0] + '/' }, link: function () { - return `${baseURL}/api/public/dl/${this.hash}${encodeURI(this.file.name)}` + if (!this.multiple) return `${baseURL}/api/public/dl/${this.hash}${encodeURI(this.file.name)}` + let files = [] + for (let s of this.selected) { + files.push('/' + encodeURI(s) + '/') + } + return `${baseURL}/api/public/raw/${this.hash}?files=${encodeURIComponent(files.join(','))}` }, fullLink: function () { return window.location.origin + this.link @@ -146,12 +160,67 @@ export default { return window.btoa(unescape(encodeURIComponent(name))) }, fetchData: async function () { + this.loaded = false + this.notFound = false + this.selected = [] + this.firstSelected = -1 try { this.file = await api.getHash(this.hash) this.loaded = true } catch (e) { this.notFound = true } + }, + addSelected: function(name) { + this.selected.push(name) + }, + removeSelected: function (name) { + let i = this.selected.indexOf(name) + if (i === -1) return + this.selected.splice(i, 1) + if (i === 0 && this.multiple) { + this.firstSelected = this.file.items.indexOf(this.file.items.filter(item => item.name === this.selected[0])[0]) + } + }, + resetSelected: function () { + this.selected = [] + this.firstSelected = -1 + }, + click: function (name) { + if (this.multiple) event.preventDefault() + if (this.selected.indexOf(name) !== -1) { + this.removeSelected(name) + return + } + + let index = this.file.items.indexOf(this.file.items.filter(item => item.name === name)[0]) + if (event.shiftKey && this.multiple) { + let fi = 0 + let la = 0 + + if (index > this.firstSelected) { + fi = this.firstSelected + 1 + la = index + } else { + fi = index + la = this.firstSelected - 1 + } + + for (; fi <= la; fi++) { + if (this.selected.indexOf(this.file.items[fi].name) === -1) { + this.addSelected(this.file.items[fi].name) + } + } + + return + } + + if (!event.ctrlKey && !this.multiple) this.resetSelected() + if (this.firstSelected === -1) this.firstSelected = index + this.addSelected(name) + }, + dbclick: function (name) { + this.$router.push({path: `/share/${this.hash}${name}`}) } } } diff --git a/http/http.go b/http/http.go index a4b3c2d2..8ed416f9 100644 --- a/http/http.go +++ b/http/http.go @@ -67,6 +67,7 @@ func NewHandler(imgSvc ImgService, fileCache FileCache, store *storage.Storage, public := api.PathPrefix("/public").Subrouter() public.PathPrefix("/dl").Handler(monkey(publicDlHandler, "/api/public/dl/")).Methods("GET") public.PathPrefix("/share").Handler(monkey(publicShareHandler, "/api/public/share/")).Methods("GET") + public.PathPrefix("/raw").Handler(monkey(publicRawHandler, "/api/public/raw/")).Methods("GET") return stripPrefix(server.BaseURL, r), nil } diff --git a/http/public.go b/http/public.go index a0398e28..77f18d20 100644 --- a/http/public.go +++ b/http/public.go @@ -74,3 +74,12 @@ var publicDlHandler = withHashFile(func(w http.ResponseWriter, r *http.Request, return rawDirHandler(w, r, d, file) }, true) + +var publicRawHandler = withHashFile(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { + file := d.raw.(*files.FileInfo) + if !file.IsDir { + return rawFileHandler(w, r, file) + } + + return rawDirHandler(w, r, d, file) +}, false) \ No newline at end of file