Merge pull request #1026 from ramiresviana/fixes
This commit is contained in:
commit
1790df2090
|
@ -2,6 +2,7 @@ package fileutils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
|
@ -25,7 +26,7 @@ func CopyFile(fs afero.Fs, source, dest string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the destination file.
|
// Create the destination file.
|
||||||
dst, err := fs.Create(dest)
|
dst, err := fs.OpenFile(dest, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0775)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
:root {
|
:root {
|
||||||
--background: #121212;
|
--background: #141D24;
|
||||||
--surfacePrimary: #171819;
|
--surfacePrimary: #20292F;
|
||||||
--surfaceSecondary: #212528;
|
--surfaceSecondary: #3A4147;
|
||||||
--divider: rgba(255, 255, 255, 0.12);
|
--divider: rgba(255, 255, 255, 0.12);
|
||||||
--icon: #ffffff;
|
--icon: #ffffff;
|
||||||
--textPrimary: rgba(255, 255, 255, 0.87);
|
--textPrimary: rgba(255, 255, 255, 0.87);
|
||||||
|
@ -16,7 +16,7 @@ body {
|
||||||
#loading {
|
#loading {
|
||||||
background: var(--background);
|
background: var(--background);
|
||||||
}
|
}
|
||||||
#loading .spinner div {
|
#loading .spinner div, #previewer .loading .spinner div {
|
||||||
background: var(--icon);
|
background: var(--icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,25 +30,34 @@ header {
|
||||||
|
|
||||||
#search #input {
|
#search #input {
|
||||||
background: var(--surfaceSecondary);
|
background: var(--surfaceSecondary);
|
||||||
|
border-color: var(--surfacePrimary);
|
||||||
}
|
}
|
||||||
#search.active #input,
|
#search #input input::placeholder {
|
||||||
#search.active .boxes {
|
color: var(--textSecondary);
|
||||||
|
}
|
||||||
|
#search.active #input {
|
||||||
background: var(--surfacePrimary);
|
background: var(--surfacePrimary);
|
||||||
}
|
}
|
||||||
#search.active input {
|
#search.active input {
|
||||||
color: var(--textPrimary);
|
color: var(--textPrimary);
|
||||||
}
|
}
|
||||||
#search.active #result {
|
#search #result {
|
||||||
background: var(--background);
|
background: var(--background);
|
||||||
color: var(--textPrimary);
|
color: var(--textPrimary);
|
||||||
}
|
}
|
||||||
#search.active .boxes h3 {
|
#search .boxes {
|
||||||
|
background: var(--surfaceSecondary);
|
||||||
|
}
|
||||||
|
#search .boxes h3 {
|
||||||
color: var(--textPrimary);
|
color: var(--textPrimary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.action {
|
.action {
|
||||||
color: var(--textPrimary) !important;
|
color: var(--textPrimary) !important;
|
||||||
}
|
}
|
||||||
|
.action:hover {
|
||||||
|
background-color: rgba(255, 255, 255, .1);
|
||||||
|
}
|
||||||
.action i {
|
.action i {
|
||||||
color: var(--icon) !important;
|
color: var(--icon) !important;
|
||||||
}
|
}
|
||||||
|
@ -93,6 +102,10 @@ nav > div {
|
||||||
background: var(--background);
|
background: var(--background);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.message {
|
||||||
|
color: var(--textPrimary);
|
||||||
|
}
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
background: var(--surfacePrimary);
|
background: var(--surfacePrimary);
|
||||||
color: var(--textPrimary);
|
color: var(--textPrimary);
|
||||||
|
@ -106,9 +119,23 @@ nav > div {
|
||||||
.dashboard p label {
|
.dashboard p label {
|
||||||
color: var(--textPrimary);
|
color: var(--textPrimary);
|
||||||
}
|
}
|
||||||
|
.card#share ul li input,
|
||||||
|
.card#share ul li select,
|
||||||
.input {
|
.input {
|
||||||
background: var(--surfaceSecondary);
|
background: var(--surfaceSecondary);
|
||||||
color: var(--textPrimary);
|
color: var(--textPrimary);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.05);
|
||||||
|
}
|
||||||
|
.input:hover,
|
||||||
|
.input:focus {
|
||||||
|
border-color: rgba(255, 255, 255, 0.15);
|
||||||
|
}
|
||||||
|
.input--red {
|
||||||
|
background: #73302D;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input--green {
|
||||||
|
background: #147A41;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dashboard #nav li,
|
.dashboard #nav li,
|
||||||
|
@ -119,10 +146,27 @@ nav > div {
|
||||||
color: var(--textPrimary);
|
color: var(--textPrimary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table th {
|
||||||
|
color: var(--textSecondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-list li:hover {
|
||||||
|
background: var(--surfaceSecondary);
|
||||||
|
}
|
||||||
|
.file-list li:before {
|
||||||
|
color: var(--textSecondary);
|
||||||
|
}
|
||||||
|
.file-list li[aria-selected=true]:before {
|
||||||
|
color: var(--icon);
|
||||||
|
}
|
||||||
|
|
||||||
.shell {
|
.shell {
|
||||||
background: var(--surfacePrimary);
|
background: var(--surfacePrimary);
|
||||||
color: var(--textPrimary);
|
color: var(--textPrimary);
|
||||||
}
|
}
|
||||||
|
.shell__result {
|
||||||
|
border-top: 1px solid var(--divider);
|
||||||
|
}
|
||||||
|
|
||||||
#editor-container {
|
#editor-container {
|
||||||
background: var(--background);
|
background: var(--background);
|
||||||
|
@ -146,3 +190,11 @@ nav > div {
|
||||||
background: var(--surfaceSecondary) !important;
|
background: var(--surfaceSecondary) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.share__box, .share__box__download {
|
||||||
|
background: var(--surfaceSecondary) !important;
|
||||||
|
color: var(--textPrimary);
|
||||||
|
}
|
||||||
|
.share__box__download {
|
||||||
|
border-bottom-color: var(--divider);
|
||||||
|
}
|
|
@ -94,9 +94,6 @@ export async function post (url, content = '', overwrite = false, onupload) {
|
||||||
request.upload.onprogress = onupload
|
request.upload.onprogress = onupload
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send a message to user before closing the tab during file upload
|
|
||||||
window.onbeforeunload = () => "Files are being uploaded."
|
|
||||||
|
|
||||||
request.onload = () => {
|
request.onload = () => {
|
||||||
if (request.status === 200) {
|
if (request.status === 200) {
|
||||||
resolve(request.responseText)
|
resolve(request.responseText)
|
||||||
|
@ -112,29 +109,28 @@ export async function post (url, content = '', overwrite = false, onupload) {
|
||||||
}
|
}
|
||||||
|
|
||||||
request.send(content)
|
request.send(content)
|
||||||
// Upload is done no more message before closing the tab
|
})
|
||||||
}).finally(() => { window.onbeforeunload = null })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function moveCopy (items, copy = false) {
|
function moveCopy (items, copy = false, overwrite = false, rename = false) {
|
||||||
let promises = []
|
let promises = []
|
||||||
|
|
||||||
for (let item of items) {
|
for (let item of items) {
|
||||||
const from = removePrefix(item.from)
|
const from = removePrefix(item.from)
|
||||||
const to = encodeURIComponent(removePrefix(item.to))
|
const to = encodeURIComponent(removePrefix(item.to))
|
||||||
const url = `${from}?action=${copy ? 'copy' : 'rename'}&destination=${to}`
|
const url = `${from}?action=${copy ? 'copy' : 'rename'}&destination=${to}&override=${overwrite}&rename=${rename}`
|
||||||
promises.push(resourceAction(url, 'PATCH'))
|
promises.push(resourceAction(url, 'PATCH'))
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.all(promises)
|
return Promise.all(promises)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function move (items) {
|
export function move (items, overwrite = false, rename = false) {
|
||||||
return moveCopy(items)
|
return moveCopy(items, false, overwrite, rename)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function copy (items) {
|
export function copy (items, overwrite = false, rename = false) {
|
||||||
return moveCopy(items, true)
|
return moveCopy(items, true, overwrite, rename)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function checksum (url, algo) {
|
export async function checksum (url, algo) {
|
||||||
|
|
|
@ -10,10 +10,12 @@
|
||||||
@mouseup="mouseUp"
|
@mouseup="mouseUp"
|
||||||
@wheel="wheelMove"
|
@wheel="wheelMove"
|
||||||
>
|
>
|
||||||
<img :src="src" class="image-ex-img" ref="imgex" @load="setCenter">
|
<img :src="src" class="image-ex-img image-ex-img-center" ref="imgex" @load="onLoad">
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
import throttle from 'lodash.throttle'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
src: String,
|
src: String,
|
||||||
|
@ -50,7 +52,12 @@ export default {
|
||||||
inDrag: false,
|
inDrag: false,
|
||||||
lastTouchDistance: 0,
|
lastTouchDistance: 0,
|
||||||
moveDisabled: false,
|
moveDisabled: false,
|
||||||
disabledTimer: null
|
disabledTimer: null,
|
||||||
|
imageLoaded: false,
|
||||||
|
position: {
|
||||||
|
center: { x: 0, y: 0 },
|
||||||
|
relative: { x: 0, y: 0 }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
@ -63,24 +70,47 @@ export default {
|
||||||
if (getComputedStyle(container).height === "0px") {
|
if (getComputedStyle(container).height === "0px") {
|
||||||
container.style.height = "100%"
|
container.style.height = "100%"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.addEventListener('resize', this.onResize)
|
||||||
|
},
|
||||||
|
beforeDestroy () {
|
||||||
|
window.removeEventListener('resize', this.onResize)
|
||||||
|
document.removeEventListener('mouseup', this.onMouseUp)
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
onLoad() {
|
||||||
|
let img = this.$refs.imgex
|
||||||
|
|
||||||
|
this.imageLoaded = true
|
||||||
|
|
||||||
|
if (img === undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
img.classList.remove('image-ex-img-center')
|
||||||
|
this.setCenter()
|
||||||
|
img.classList.add('image-ex-img-ready')
|
||||||
|
|
||||||
|
document.addEventListener('mouseup', this.onMouseUp)
|
||||||
|
},
|
||||||
|
onMouseUp() {
|
||||||
|
this.inDrag = false
|
||||||
|
},
|
||||||
|
onResize: throttle(function() {
|
||||||
|
if (this.imageLoaded) {
|
||||||
|
this.setCenter()
|
||||||
|
this.doMove(this.position.relative.x, this.position.relative.y)
|
||||||
|
}
|
||||||
|
}, 100),
|
||||||
setCenter() {
|
setCenter() {
|
||||||
let container = this.$refs.container
|
let container = this.$refs.container
|
||||||
let img = this.$refs.imgex
|
let img = this.$refs.imgex
|
||||||
|
|
||||||
let rate = Math.min(
|
this.position.center.x = Math.floor((container.clientWidth - img.clientWidth) / 2)
|
||||||
container.clientWidth / img.clientWidth,
|
this.position.center.y = Math.floor((container.clientHeight - img.clientHeight) / 2)
|
||||||
container.clientHeight / img.clientHeight
|
|
||||||
)
|
img.style.left = this.position.center.x + 'px'
|
||||||
if (!this.autofill && rate > 1) {
|
img.style.top = this.position.center.y + 'px'
|
||||||
rate = 1
|
|
||||||
}
|
|
||||||
// height will be auto set
|
|
||||||
img.width = Math.floor(img.clientWidth * rate)
|
|
||||||
img.style.top = `${Math.floor((container.clientHeight - img.clientHeight) / 2)}px`
|
|
||||||
img.style.left = `${Math.floor((container.clientWidth - img.clientWidth) / 2)}px`
|
|
||||||
document.addEventListener('mouseup', () => this.inDrag = false )
|
|
||||||
},
|
},
|
||||||
mousedownStart(event) {
|
mousedownStart(event) {
|
||||||
this.lastX = null
|
this.lastX = null
|
||||||
|
@ -159,8 +189,22 @@ export default {
|
||||||
},
|
},
|
||||||
doMove(x, y) {
|
doMove(x, y) {
|
||||||
let style = this.$refs.imgex.style
|
let style = this.$refs.imgex.style
|
||||||
style.left = `${this.pxStringToNumber(style.left) + x}px`
|
let posX = this.pxStringToNumber(style.left) + x
|
||||||
style.top = `${this.pxStringToNumber(style.top) + y}px`
|
let posY = this.pxStringToNumber(style.top) + y
|
||||||
|
|
||||||
|
style.left = posX + 'px'
|
||||||
|
style.top = posY + 'px'
|
||||||
|
|
||||||
|
this.position.relative.x = Math.abs(this.position.center.x - posX)
|
||||||
|
this.position.relative.y = Math.abs(this.position.center.y - posY)
|
||||||
|
|
||||||
|
if (posX < this.position.center.x) {
|
||||||
|
this.position.relative.x = this.position.relative.x * -1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (posY < this.position.center.y) {
|
||||||
|
this.position.relative.y = this.position.relative.y * -1
|
||||||
|
}
|
||||||
},
|
},
|
||||||
wheelMove(event) {
|
wheelMove(event) {
|
||||||
this.scale += (event.wheelDeltaY / 100) * this.zoomStep
|
this.scale += (event.wheelDeltaY / 100) * this.zoomStep
|
||||||
|
@ -185,9 +229,20 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
.image-ex-img {
|
.image-ex-img {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-ex-img-center {
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
position: absolute;
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-ex-img-ready {
|
||||||
left: 0;
|
left: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
position: absolute;
|
|
||||||
transition: transform 0.1s ease;
|
transition: transform 0.1s ease;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -248,7 +248,8 @@ export default {
|
||||||
|
|
||||||
this.$store.commit('updateClipboard', {
|
this.$store.commit('updateClipboard', {
|
||||||
key: key,
|
key: key,
|
||||||
items: items
|
items: items,
|
||||||
|
path: this.$route.path
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
paste (event) {
|
paste (event) {
|
||||||
|
@ -261,23 +262,56 @@ export default {
|
||||||
for (let item of this.$store.state.clipboard.items) {
|
for (let item of this.$store.state.clipboard.items) {
|
||||||
const from = item.from.endsWith('/') ? item.from.slice(0, -1) : item.from
|
const from = item.from.endsWith('/') ? item.from.slice(0, -1) : item.from
|
||||||
const to = this.$route.path + item.name
|
const to = this.$route.path + item.name
|
||||||
items.push({ from, to })
|
items.push({ from, to, name: item.name })
|
||||||
}
|
}
|
||||||
|
|
||||||
if (items.length === 0) {
|
if (items.length === 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.$store.state.clipboard.key === 'x') {
|
let action = (overwrite, rename) => {
|
||||||
api.move(items).then(() => {
|
api.copy(items, overwrite, rename).then(() => {
|
||||||
this.$store.commit('setReload', true)
|
this.$store.commit('setReload', true)
|
||||||
}).catch(this.$showError)
|
}).catch(this.$showError)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.$store.state.clipboard.key === 'x') {
|
||||||
|
action = (overwrite, rename) => {
|
||||||
|
api.move(items, overwrite, rename).then(() => {
|
||||||
|
this.$store.commit('resetClipboard')
|
||||||
|
this.$store.commit('setReload', true)
|
||||||
|
}).catch(this.$showError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.$store.state.clipboard.path == this.$route.path) {
|
||||||
|
action(false, true)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
api.copy(items).then(() => {
|
let conflict = upload.checkConflict(items, this.req.items)
|
||||||
this.$store.commit('setReload', true)
|
|
||||||
}).catch(this.$showError)
|
let overwrite = false
|
||||||
|
let rename = false
|
||||||
|
|
||||||
|
if (conflict) {
|
||||||
|
this.$store.commit('showHover', {
|
||||||
|
prompt: 'replace-rename',
|
||||||
|
confirm: (event, option) => {
|
||||||
|
overwrite = option == 'overwrite'
|
||||||
|
rename = option == 'rename'
|
||||||
|
|
||||||
|
event.preventDefault()
|
||||||
|
this.$store.commit('closeHovers')
|
||||||
|
action(overwrite, rename)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
action(overwrite, rename)
|
||||||
},
|
},
|
||||||
resizeEvent () {
|
resizeEvent () {
|
||||||
// Update the columns size based on the window width.
|
// Update the columns size based on the window width.
|
||||||
|
|
|
@ -36,6 +36,7 @@ import { mapMutations, mapGetters, mapState } from 'vuex'
|
||||||
import filesize from 'filesize'
|
import filesize from 'filesize'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import { files as api } from '@/api'
|
import { files as api } from '@/api'
|
||||||
|
import * as upload from '@/utils/upload'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'item',
|
name: 'item',
|
||||||
|
@ -110,26 +111,61 @@ export default {
|
||||||
|
|
||||||
el.style.opacity = 1
|
el.style.opacity = 1
|
||||||
},
|
},
|
||||||
drop: function (event) {
|
drop: async function (event) {
|
||||||
if (!this.canDrop) return
|
if (!this.canDrop) return
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|
||||||
if (this.selectedCount === 0) return
|
if (this.selectedCount === 0) return
|
||||||
|
|
||||||
|
let el = event.target
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
if (el !== null && !el.classList.contains('item')) {
|
||||||
|
el = el.parentElement
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let items = []
|
let items = []
|
||||||
|
|
||||||
for (let i of this.selected) {
|
for (let i of this.selected) {
|
||||||
items.push({
|
items.push({
|
||||||
from: this.req.items[i].url,
|
from: this.req.items[i].url,
|
||||||
to: this.url + this.req.items[i].name
|
to: this.url + this.req.items[i].name,
|
||||||
|
name: this.req.items[i].name
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let base = el.querySelector('.name').innerHTML + '/'
|
||||||
|
let path = this.$route.path + base
|
||||||
|
let baseItems = (await api.fetch(path)).items
|
||||||
|
|
||||||
|
let action = (overwrite, rename) => {
|
||||||
|
api.move(items, overwrite, rename).then(() => {
|
||||||
|
this.$store.commit('setReload', true)
|
||||||
|
}).catch(this.$showError)
|
||||||
}
|
}
|
||||||
|
|
||||||
api.move(items)
|
let conflict = upload.checkConflict(items, baseItems)
|
||||||
.then(() => {
|
|
||||||
this.$store.commit('setReload', true)
|
let overwrite = false
|
||||||
|
let rename = false
|
||||||
|
|
||||||
|
if (conflict) {
|
||||||
|
this.$store.commit('showHover', {
|
||||||
|
prompt: 'replace-rename',
|
||||||
|
confirm: (event, option) => {
|
||||||
|
overwrite = option == 'overwrite'
|
||||||
|
rename = option == 'rename'
|
||||||
|
|
||||||
|
event.preventDefault()
|
||||||
|
this.$store.commit('closeHovers')
|
||||||
|
action(overwrite, rename)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch(this.$showError)
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
action(overwrite, rename)
|
||||||
},
|
},
|
||||||
click: function (event) {
|
click: function (event) {
|
||||||
if (this.selectedCount !== 0) event.preventDefault()
|
if (this.selectedCount !== 0) event.preventDefault()
|
||||||
|
|
|
@ -5,10 +5,22 @@
|
||||||
<i class="material-icons">close</i>
|
<i class="material-icons">close</i>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<rename-button v-if="user.perm.rename"></rename-button>
|
<div class="title">
|
||||||
<delete-button v-if="user.perm.delete"></delete-button>
|
<span>{{ this.name }}</span>
|
||||||
<download-button v-if="user.perm.download"></download-button>
|
</div>
|
||||||
<info-button></info-button>
|
|
||||||
|
<rename-button :disabled="loading" v-if="user.perm.rename"></rename-button>
|
||||||
|
<delete-button :disabled="loading" v-if="user.perm.delete"></delete-button>
|
||||||
|
<download-button :disabled="loading" v-if="user.perm.download"></download-button>
|
||||||
|
<info-button :disabled="loading"></info-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="loading" v-if="loading">
|
||||||
|
<div class="spinner">
|
||||||
|
<div class="bounce1"></div>
|
||||||
|
<div class="bounce2"></div>
|
||||||
|
<div class="bounce3"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button class="action" @click="prev" v-show="hasPrevious" :aria-label="$t('buttons.previous')" :title="$t('buttons.previous')">
|
<button class="action" @click="prev" v-show="hasPrevious" :aria-label="$t('buttons.previous')" :title="$t('buttons.previous')">
|
||||||
|
@ -18,25 +30,27 @@
|
||||||
<i class="material-icons">chevron_right</i>
|
<i class="material-icons">chevron_right</i>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div class="preview">
|
<template v-if="!loading">
|
||||||
<ExtendedImage v-if="req.type == 'image'" :src="raw"></ExtendedImage>
|
<div class="preview">
|
||||||
<audio v-else-if="req.type == 'audio'" :src="raw" autoplay controls></audio>
|
<ExtendedImage v-if="req.type == 'image'" :src="raw"></ExtendedImage>
|
||||||
<video v-else-if="req.type == 'video'" :src="raw" autoplay controls>
|
<audio v-else-if="req.type == 'audio'" :src="raw" autoplay controls></audio>
|
||||||
<track
|
<video v-else-if="req.type == 'video'" :src="raw" autoplay controls>
|
||||||
kind="captions"
|
<track
|
||||||
v-for="(sub, index) in subtitles"
|
kind="captions"
|
||||||
:key="index"
|
v-for="(sub, index) in subtitles"
|
||||||
:src="sub"
|
:key="index"
|
||||||
:label="'Subtitle ' + index" :default="index === 0">
|
:src="sub"
|
||||||
Sorry, your browser doesn't support embedded videos,
|
:label="'Subtitle ' + index" :default="index === 0">
|
||||||
but don't worry, you can <a :href="download">download it</a>
|
Sorry, your browser doesn't support embedded videos,
|
||||||
and watch it with your favorite video player!
|
but don't worry, you can <a :href="download">download it</a>
|
||||||
</video>
|
and watch it with your favorite video player!
|
||||||
<object v-else-if="req.extension == '.pdf'" class="pdf" :data="raw"></object>
|
</video>
|
||||||
<a v-else-if="req.type == 'blob'" :href="download">
|
<object v-else-if="req.extension == '.pdf'" class="pdf" :data="raw"></object>
|
||||||
<h2 class="message">{{ $t('buttons.download') }} <i class="material-icons">file_download</i></h2>
|
<a v-else-if="req.type == 'blob'" :href="download">
|
||||||
</a>
|
<h2 class="message">{{ $t('buttons.download') }} <i class="material-icons">file_download</i></h2>
|
||||||
</div>
|
</a>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -72,11 +86,12 @@ export default {
|
||||||
previousLink: '',
|
previousLink: '',
|
||||||
nextLink: '',
|
nextLink: '',
|
||||||
listing: null,
|
listing: null,
|
||||||
|
name: '',
|
||||||
subtitles: []
|
subtitles: []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['req', 'user', 'oldReq', 'jwt']),
|
...mapState(['req', 'user', 'oldReq', 'jwt', 'loading']),
|
||||||
hasPrevious () {
|
hasPrevious () {
|
||||||
return (this.previousLink !== '')
|
return (this.previousLink !== '')
|
||||||
},
|
},
|
||||||
|
@ -96,30 +111,24 @@ export default {
|
||||||
return `${this.previewUrl}&inline=true`
|
return `${this.previewUrl}&inline=true`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
$route: function () {
|
||||||
|
this.updatePreview()
|
||||||
|
}
|
||||||
|
},
|
||||||
async mounted () {
|
async mounted () {
|
||||||
window.addEventListener('keyup', this.key)
|
window.addEventListener('keyup', this.key)
|
||||||
|
this.$store.commit('setPreviewMode', true)
|
||||||
if (this.req.subtitles) {
|
this.listing = this.oldReq.items
|
||||||
this.subtitles = this.req.subtitles.map(sub => `${baseURL}/api/raw${sub}?auth=${this.jwt}&inline=true`)
|
this.updatePreview()
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (this.oldReq.items) {
|
|
||||||
this.updateLinks(this.oldReq.items)
|
|
||||||
} else {
|
|
||||||
const path = url.removeLastDir(this.$route.path)
|
|
||||||
const res = await api.fetch(path)
|
|
||||||
this.updateLinks(res.items)
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
this.$showError(e)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
beforeDestroy () {
|
beforeDestroy () {
|
||||||
window.removeEventListener('keyup', this.key)
|
window.removeEventListener('keyup', this.key)
|
||||||
|
this.$store.commit('setPreviewMode', false)
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
back () {
|
back () {
|
||||||
|
this.$store.commit('setPreviewMode', false)
|
||||||
let uri = url.removeLastDir(this.$route.path) + '/'
|
let uri = url.removeLastDir(this.$route.path) + '/'
|
||||||
this.$router.push({ path: uri })
|
this.$router.push({ path: uri })
|
||||||
},
|
},
|
||||||
|
@ -138,22 +147,42 @@ export default {
|
||||||
if (this.hasPrevious) this.prev()
|
if (this.hasPrevious) this.prev()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
updateLinks (items) {
|
async updatePreview () {
|
||||||
for (let i = 0; i < items.length; i++) {
|
if (this.req.subtitles) {
|
||||||
if (items[i].name !== this.req.name) {
|
this.subtitles = this.req.subtitles.map(sub => `${baseURL}/api/raw${sub}?auth=${this.jwt}&inline=true`)
|
||||||
|
}
|
||||||
|
|
||||||
|
let dirs = this.$route.fullPath.split("/")
|
||||||
|
this.name = decodeURIComponent(dirs[dirs.length - 1])
|
||||||
|
|
||||||
|
if (!this.listing) {
|
||||||
|
try {
|
||||||
|
const path = url.removeLastDir(this.$route.path)
|
||||||
|
const res = await api.fetch(path)
|
||||||
|
this.listing = res.items
|
||||||
|
} catch (e) {
|
||||||
|
this.$showError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.previousLink = ''
|
||||||
|
this.nextLink = ''
|
||||||
|
|
||||||
|
for (let i = 0; i < this.listing.length; i++) {
|
||||||
|
if (this.listing[i].name !== this.name) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let j = i - 1; j >= 0; j--) {
|
for (let j = i - 1; j >= 0; j--) {
|
||||||
if (mediaTypes.includes(items[j].type)) {
|
if (mediaTypes.includes(this.listing[j].type)) {
|
||||||
this.previousLink = items[j].url
|
this.previousLink = this.listing[j].url
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let j = i + 1; j < items.length; j++) {
|
for (let j = i + 1; j < this.listing.length; j++) {
|
||||||
if (mediaTypes.includes(items[j].type)) {
|
if (mediaTypes.includes(this.listing[j].type)) {
|
||||||
this.nextLink = items[j].url
|
this.nextLink = this.listing[j].url
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
:title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
|
:title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
|
||||||
<button class="button button--flat"
|
<button class="button button--flat"
|
||||||
@click="copy"
|
@click="copy"
|
||||||
:disabled="$route.path === dest"
|
|
||||||
:aria-label="$t('buttons.copy')"
|
:aria-label="$t('buttons.copy')"
|
||||||
:title="$t('buttons.copy')">{{ $t('buttons.copy') }}</button>
|
:title="$t('buttons.copy')">{{ $t('buttons.copy') }}</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -28,6 +27,7 @@ import { mapState } from 'vuex'
|
||||||
import FileList from './FileList'
|
import FileList from './FileList'
|
||||||
import { files as api } from '@/api'
|
import { files as api } from '@/api'
|
||||||
import buttons from '@/utils/buttons'
|
import buttons from '@/utils/buttons'
|
||||||
|
import * as upload from '@/utils/upload'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'copy',
|
name: 'copy',
|
||||||
|
@ -42,25 +42,66 @@ export default {
|
||||||
methods: {
|
methods: {
|
||||||
copy: async function (event) {
|
copy: async function (event) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
buttons.loading('copy')
|
|
||||||
let items = []
|
let items = []
|
||||||
|
|
||||||
// Create a new promise for each file.
|
// Create a new promise for each file.
|
||||||
for (let item of this.selected) {
|
for (let item of this.selected) {
|
||||||
items.push({
|
items.push({
|
||||||
from: this.req.items[item].url,
|
from: this.req.items[item].url,
|
||||||
to: this.dest + encodeURIComponent(this.req.items[item].name)
|
to: this.dest + encodeURIComponent(this.req.items[item].name),
|
||||||
|
name: this.req.items[item].name
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
let action = async (overwrite, rename) => {
|
||||||
await api.copy(items)
|
buttons.loading('copy')
|
||||||
buttons.success('copy')
|
|
||||||
this.$router.push({ path: this.dest })
|
await api.copy(items, overwrite, rename).then(() => {
|
||||||
} catch (e) {
|
buttons.success('copy')
|
||||||
buttons.done('copy')
|
|
||||||
this.$showError(e)
|
if (this.$route.path === this.dest) {
|
||||||
|
this.$store.commit('setReload', true)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$router.push({ path: this.dest })
|
||||||
|
}).catch((e) => {
|
||||||
|
buttons.done('copy')
|
||||||
|
this.$showError(e)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.$route.path === this.dest) {
|
||||||
|
this.$store.commit('closeHovers')
|
||||||
|
action(false, true)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let dstItems = (await api.fetch(this.dest)).items
|
||||||
|
let conflict = upload.checkConflict(items, dstItems)
|
||||||
|
|
||||||
|
let overwrite = false
|
||||||
|
let rename = false
|
||||||
|
|
||||||
|
if (conflict) {
|
||||||
|
this.$store.commit('showHover', {
|
||||||
|
prompt: 'replace-rename',
|
||||||
|
confirm: (event, option) => {
|
||||||
|
overwrite = option == 'overwrite'
|
||||||
|
rename = option == 'rename'
|
||||||
|
|
||||||
|
event.preventDefault()
|
||||||
|
this.$store.commit('closeHovers')
|
||||||
|
action(overwrite, rename)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
action(overwrite, rename)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,19 +41,7 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
// If we're showing this on a listing,
|
this.fillOptions(this.req)
|
||||||
// we can use the current request object
|
|
||||||
// to fill the move options.
|
|
||||||
if (this.req.kind === 'listing') {
|
|
||||||
this.fillOptions(this.req)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, we must be on a preview or editor
|
|
||||||
// so we fetch the data from the previous directory.
|
|
||||||
files.fetch(url.removeLastDir(this.$route.path))
|
|
||||||
.then(this.fillOptions)
|
|
||||||
.catch(this.$showError)
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
fillOptions (req) {
|
fillOptions (req) {
|
||||||
|
|
|
@ -27,6 +27,7 @@ import { mapState } from 'vuex'
|
||||||
import FileList from './FileList'
|
import FileList from './FileList'
|
||||||
import { files as api } from '@/api'
|
import { files as api } from '@/api'
|
||||||
import buttons from '@/utils/buttons'
|
import buttons from '@/utils/buttons'
|
||||||
|
import * as upload from '@/utils/upload'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'move',
|
name: 'move',
|
||||||
|
@ -41,26 +42,51 @@ export default {
|
||||||
methods: {
|
methods: {
|
||||||
move: async function (event) {
|
move: async function (event) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
buttons.loading('move')
|
|
||||||
let items = []
|
let items = []
|
||||||
|
|
||||||
for (let item of this.selected) {
|
for (let item of this.selected) {
|
||||||
items.push({
|
items.push({
|
||||||
from: this.req.items[item].url,
|
from: this.req.items[item].url,
|
||||||
to: this.dest + encodeURIComponent(this.req.items[item].name)
|
to: this.dest + encodeURIComponent(this.req.items[item].name),
|
||||||
|
name: this.req.items[item].name
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
let action = async (overwrite, rename) => {
|
||||||
api.move(items)
|
buttons.loading('move')
|
||||||
buttons.success('move')
|
|
||||||
this.$router.push({ path: this.dest })
|
await api.move(items, overwrite, rename).then(() => {
|
||||||
} catch (e) {
|
buttons.success('move')
|
||||||
buttons.done('move')
|
this.$router.push({ path: this.dest })
|
||||||
this.$showError(e)
|
}).catch((e) => {
|
||||||
|
buttons.done('move')
|
||||||
|
this.$showError(e)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
event.preventDefault()
|
let dstItems = (await api.fetch(this.dest)).items
|
||||||
|
let conflict = upload.checkConflict(items, dstItems)
|
||||||
|
|
||||||
|
let overwrite = false
|
||||||
|
let rename = false
|
||||||
|
|
||||||
|
if (conflict) {
|
||||||
|
this.$store.commit('showHover', {
|
||||||
|
prompt: 'replace-rename',
|
||||||
|
confirm: (event, option) => {
|
||||||
|
overwrite = option == 'overwrite'
|
||||||
|
rename = option == 'rename'
|
||||||
|
|
||||||
|
event.preventDefault()
|
||||||
|
this.$store.commit('closeHovers')
|
||||||
|
action(overwrite, rename)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
action(overwrite, rename)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ import Copy from './Copy'
|
||||||
import NewFile from './NewFile'
|
import NewFile from './NewFile'
|
||||||
import NewDir from './NewDir'
|
import NewDir from './NewDir'
|
||||||
import Replace from './Replace'
|
import Replace from './Replace'
|
||||||
|
import ReplaceRename from './ReplaceRename'
|
||||||
import Share from './Share'
|
import Share from './Share'
|
||||||
import Upload from './Upload'
|
import Upload from './Upload'
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from 'vuex'
|
||||||
|
@ -35,6 +36,7 @@ export default {
|
||||||
NewDir,
|
NewDir,
|
||||||
Help,
|
Help,
|
||||||
Replace,
|
Replace,
|
||||||
|
ReplaceRename,
|
||||||
Upload
|
Upload
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
|
@ -52,7 +54,7 @@ export default {
|
||||||
return
|
return
|
||||||
|
|
||||||
let prompt = this.$refs.currentComponent;
|
let prompt = this.$refs.currentComponent;
|
||||||
|
|
||||||
// Enter
|
// Enter
|
||||||
if (event.keyCode == 13) {
|
if (event.keyCode == 13) {
|
||||||
switch (this.show) {
|
switch (this.show) {
|
||||||
|
@ -87,6 +89,7 @@ export default {
|
||||||
'newDir',
|
'newDir',
|
||||||
'download',
|
'download',
|
||||||
'replace',
|
'replace',
|
||||||
|
'replace-rename',
|
||||||
'share',
|
'share',
|
||||||
'upload'
|
'upload'
|
||||||
].indexOf(this.show) >= 0;
|
].indexOf(this.show) >= 0;
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
<template>
|
||||||
|
<div class="card floating">
|
||||||
|
<div class="card-title">
|
||||||
|
<h2>{{ $t('prompts.replace') }}</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-content">
|
||||||
|
<p>{{ $t('prompts.replaceMessage') }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-action">
|
||||||
|
<button class="button button--flat button--grey"
|
||||||
|
@click="$store.commit('closeHovers')"
|
||||||
|
:aria-label="$t('buttons.cancel')"
|
||||||
|
:title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
|
||||||
|
<button class="button button--flat button--blue"
|
||||||
|
@click="(event) => showConfirm(event, 'rename')"
|
||||||
|
:aria-label="$t('buttons.rename')"
|
||||||
|
:title="$t('buttons.rename')">{{ $t('buttons.rename') }}</button>
|
||||||
|
<button class="button button--flat button--red"
|
||||||
|
@click="(event) => showConfirm(event, 'overwrite')"
|
||||||
|
:aria-label="$t('buttons.replace')"
|
||||||
|
:title="$t('buttons.replace')">{{ $t('buttons.replace') }}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapState } from 'vuex'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'replace-rename',
|
||||||
|
computed: mapState(['showConfirm'])
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -25,8 +25,8 @@
|
||||||
background: var(--red);
|
background: var(--red);
|
||||||
}
|
}
|
||||||
|
|
||||||
.button--red:hover {
|
.button--blue {
|
||||||
background: var(--dark-red);
|
background: var(--blue);
|
||||||
}
|
}
|
||||||
|
|
||||||
.button--flat {
|
.button--flat {
|
||||||
|
|
|
@ -125,8 +125,13 @@
|
||||||
height: 3.7em;
|
height: 3.7em;
|
||||||
}
|
}
|
||||||
|
|
||||||
#previewer .action:first-of-type {
|
#previewer .bar .title {
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
|
padding: 0 1em;
|
||||||
|
line-height: 2.7em;
|
||||||
|
overflow: hidden;
|
||||||
|
word-break: break-word;
|
||||||
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
#previewer .action i {
|
#previewer .action i {
|
||||||
|
@ -219,6 +224,11 @@
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#previewer .loading {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
#editor-container #editor {
|
#editor-container #editor {
|
||||||
height: calc(100vh - 8.2em);
|
height: calc(100vh - 8.2em);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,8 @@ const state = {
|
||||||
show: null,
|
show: null,
|
||||||
showShell: false,
|
showShell: false,
|
||||||
showMessage: null,
|
showMessage: null,
|
||||||
showConfirm: null
|
showConfirm: null,
|
||||||
|
previewMode: false
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new Vuex.Store({
|
export default new Vuex.Store({
|
||||||
|
|
|
@ -37,6 +37,11 @@ const mutations = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const beforeUnload = (event) => {
|
||||||
|
event.preventDefault()
|
||||||
|
event.returnValue = ''
|
||||||
|
}
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
upload: (context, item) => {
|
upload: (context, item) => {
|
||||||
let uploadsCount = Object.keys(context.state.uploads).length;
|
let uploadsCount = Object.keys(context.state.uploads).length;
|
||||||
|
@ -45,6 +50,7 @@ const actions = {
|
||||||
let isUploadsEmpty = uploadsCount == 0
|
let isUploadsEmpty = uploadsCount == 0
|
||||||
|
|
||||||
if (isQueueEmpty && isUploadsEmpty) {
|
if (isQueueEmpty && isUploadsEmpty) {
|
||||||
|
window.addEventListener('beforeunload', beforeUnload)
|
||||||
buttons.loading('upload')
|
buttons.loading('upload')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,6 +73,7 @@ const actions = {
|
||||||
let canProcess = isBellowLimit && !isQueueEmpty
|
let canProcess = isBellowLimit && !isQueueEmpty
|
||||||
|
|
||||||
if (isFinished) {
|
if (isFinished) {
|
||||||
|
window.removeEventListener('beforeunload', beforeUnload)
|
||||||
buttons.success('upload')
|
buttons.success('upload')
|
||||||
context.commit('reset')
|
context.commit('reset')
|
||||||
context.commit('setReload', true, { root: true })
|
context.commit('setReload', true, { root: true })
|
||||||
|
|
|
@ -78,10 +78,14 @@ const mutations = {
|
||||||
updateClipboard: (state, value) => {
|
updateClipboard: (state, value) => {
|
||||||
state.clipboard.key = value.key
|
state.clipboard.key = value.key
|
||||||
state.clipboard.items = value.items
|
state.clipboard.items = value.items
|
||||||
|
state.clipboard.path = value.path
|
||||||
},
|
},
|
||||||
resetClipboard: (state) => {
|
resetClipboard: (state) => {
|
||||||
state.clipboard.key = ''
|
state.clipboard.key = ''
|
||||||
state.clipboard.items = []
|
state.clipboard.items = []
|
||||||
|
},
|
||||||
|
setPreviewMode(state, value) {
|
||||||
|
state.previewMode = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,7 @@ export function checkConflict(files, items) {
|
||||||
items = []
|
items = []
|
||||||
}
|
}
|
||||||
|
|
||||||
let folder_upload = false
|
let folder_upload = files[0].fullPath !== undefined
|
||||||
if (files[0].fullPath !== undefined) {
|
|
||||||
folder_upload = true
|
|
||||||
}
|
|
||||||
|
|
||||||
let conflict = false
|
let conflict = false
|
||||||
for (let i = 0; i < files.length; i++) {
|
for (let i = 0; i < files.length; i++) {
|
||||||
|
@ -69,7 +66,7 @@ export function scanFiles(dt) {
|
||||||
const dir = {
|
const dir = {
|
||||||
isDir: true,
|
isDir: true,
|
||||||
size: 0,
|
size: 0,
|
||||||
path: `${directory}${entry.name}`
|
fullPath: `${directory}${entry.name}`
|
||||||
}
|
}
|
||||||
|
|
||||||
contents.push(dir)
|
contents.push(dir)
|
||||||
|
@ -112,7 +109,7 @@ export function handleFiles(files, path, overwrite = false) {
|
||||||
|
|
||||||
if (file.isDir) {
|
if (file.isDir) {
|
||||||
itemPath = path
|
itemPath = path
|
||||||
let folders = file.path.split("/")
|
let folders = file.fullPath.split("/")
|
||||||
|
|
||||||
for (let i = 0; i < folders.length; i++) {
|
for (let i = 0; i < folders.length; i++) {
|
||||||
let folder = folders[i]
|
let folder = folders[i]
|
||||||
|
|
|
@ -10,14 +10,15 @@
|
||||||
<router-link :to="link.url">{{ link.name }}</router-link>
|
<router-link :to="link.url">{{ link.name }}</router-link>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="error">
|
<div v-if="error">
|
||||||
<not-found v-if="error.message === '404'"></not-found>
|
<not-found v-if="error.message === '404'"></not-found>
|
||||||
<forbidden v-else-if="error.message === '403'"></forbidden>
|
<forbidden v-else-if="error.message === '403'"></forbidden>
|
||||||
<internal-error v-else></internal-error>
|
<internal-error v-else></internal-error>
|
||||||
</div>
|
</div>
|
||||||
|
<preview v-else-if="isPreview"></preview>
|
||||||
<editor v-else-if="isEditor"></editor>
|
<editor v-else-if="isEditor"></editor>
|
||||||
<listing :class="{ multiple }" v-else-if="isListing"></listing>
|
<listing :class="{ multiple }" v-else-if="isListing"></listing>
|
||||||
<preview v-else-if="isPreview"></preview>
|
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<h2 class="message">
|
<h2 class="message">
|
||||||
<span>{{ $t('files.loading') }}</span>
|
<span>{{ $t('files.loading') }}</span>
|
||||||
|
@ -65,7 +66,7 @@ export default {
|
||||||
'show'
|
'show'
|
||||||
]),
|
]),
|
||||||
isPreview () {
|
isPreview () {
|
||||||
return !this.loading && !this.isListing && !this.isEditor
|
return !this.loading && !this.isListing && !this.isEditor || this.loading && this.$store.state.previewMode
|
||||||
},
|
},
|
||||||
breadcrumbs () {
|
breadcrumbs () {
|
||||||
let parts = this.$route.path.split('/')
|
let parts = this.$route.path.split('/')
|
||||||
|
|
|
@ -127,6 +127,10 @@ var resourcePostPutHandler = withUser(func(w http.ResponseWriter, r *http.Reques
|
||||||
return nil
|
return nil
|
||||||
}, action, r.URL.Path, "", d.user)
|
}, action, r.URL.Path, "", d.user)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
_ = d.user.Fs.RemoveAll(r.URL.Path)
|
||||||
|
}
|
||||||
|
|
||||||
return errToStatus(err), err
|
return errToStatus(err), err
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -144,6 +148,31 @@ var resourcePatchHandler = withUser(func(w http.ResponseWriter, r *http.Request,
|
||||||
return http.StatusForbidden, nil
|
return http.StatusForbidden, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override := r.URL.Query().Get("override") == "true"
|
||||||
|
rename := r.URL.Query().Get("rename") == "true"
|
||||||
|
|
||||||
|
if !override && !rename {
|
||||||
|
if _, err = d.user.Fs.Stat(dst); err == nil {
|
||||||
|
return http.StatusConflict, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rename {
|
||||||
|
counter := 1
|
||||||
|
dir, name := filepath.Split(dst)
|
||||||
|
ext := filepath.Ext(name)
|
||||||
|
base := strings.TrimSuffix(name, ext)
|
||||||
|
|
||||||
|
for {
|
||||||
|
if _, err = d.user.Fs.Stat(dst); err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
new := fmt.Sprintf("%s(%d)%s", base, counter, ext)
|
||||||
|
dst = filepath.Join(dir, new)
|
||||||
|
counter++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = d.RunHook(func() error {
|
err = d.RunHook(func() error {
|
||||||
switch action {
|
switch action {
|
||||||
// TODO: use enum
|
// TODO: use enum
|
||||||
|
|
Loading…
Reference in New Issue