rename _assets to assets
Former-commit-id: 3bb6cc662da9e9255bd61fef42430c271002fd49 [formerly eaf1785c4f85522e4eb66d00a6ae9dd9ecc4fcb4] [formerly addd3ffe1396e6df84cdc3e8787d57ffb2be3dc6 [formerly 800693ad49e76c880230eb8cd1bc4a95e8c39fff]] Former-commit-id: 6c24d30f26529457202f470620a0ea1d31772b13 [formerly 384d2af17fe100b9db91462eb41337f9dff855f4] Former-commit-id: 94f4933e12f97ee7468c884f041612498e07ba32
This commit is contained in:
71
assets/src/components/prompts/Delete.vue
Normal file
71
assets/src/components/prompts/Delete.vue
Normal file
@@ -0,0 +1,71 @@
|
||||
<template>
|
||||
<div class="prompt">
|
||||
<h3>Delete files</h3>
|
||||
<p v-show="req.kind !== 'listing'">Are you sure you want to delete this file/folder?</p>
|
||||
<p v-show="req.kind === 'listing'">Are you sure you want to delete {{ selectedCount }} file(s)?</p>
|
||||
<div>
|
||||
<button @click="submit" autofocus>Delete</button>
|
||||
<button @click="closeHovers" class="cancel">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapGetters, mapMutations, mapState} from 'vuex'
|
||||
import api from '@/utils/api'
|
||||
import url from '@/utils/url'
|
||||
import buttons from '@/utils/buttons'
|
||||
|
||||
export default {
|
||||
name: 'delete',
|
||||
computed: {
|
||||
...mapGetters(['selectedCount']),
|
||||
...mapState(['req', 'selected'])
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['closeHovers']),
|
||||
submit: function (event) {
|
||||
this.closeHovers()
|
||||
buttons.loading('delete')
|
||||
|
||||
if (this.req.kind !== 'listing') {
|
||||
api.delete(this.$route.path)
|
||||
.then(() => {
|
||||
buttons.done('delete')
|
||||
this.$router.push({path: url.removeLastDir(this.$route.path) + '/'})
|
||||
})
|
||||
.catch(error => {
|
||||
buttons.done('delete')
|
||||
// TODO: show error in prompt
|
||||
console.log(error)
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (this.selectedCount === 0) {
|
||||
// This shouldn't happen...
|
||||
return
|
||||
}
|
||||
|
||||
let promises = []
|
||||
|
||||
for (let index of this.selected) {
|
||||
promises.push(api.delete(this.req.items[index].url))
|
||||
}
|
||||
|
||||
Promise.all(promises)
|
||||
.then(() => {
|
||||
this.$store.commit('setReload', true)
|
||||
buttons.done('delete')
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error)
|
||||
this.$store.commit('setReload', true)
|
||||
buttons.done('delete')
|
||||
// TODO: show error in prompt
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
41
assets/src/components/prompts/Download.vue
Normal file
41
assets/src/components/prompts/Download.vue
Normal file
@@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<div class="prompt" id="download">
|
||||
<h3>Download files</h3>
|
||||
<p>Choose the format you want to download.</p>
|
||||
<button @click="download('zip')" autofocus>zip</button>
|
||||
<button @click="download('tar')" autofocus>tar</button>
|
||||
<button @click="download('targz')" autofocus>tar.gz</button>
|
||||
<button @click="download('tarbz2')" autofocus>tar.bz2</button>
|
||||
<button @click="download('tarxz')" autofocus>tar.xz</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapGetters, mapState} from 'vuex'
|
||||
import api from '@/utils/api'
|
||||
|
||||
export default {
|
||||
name: 'download',
|
||||
computed: {
|
||||
...mapState(['selected', 'req']),
|
||||
...mapGetters(['selectedCount'])
|
||||
},
|
||||
methods: {
|
||||
download: function (format) {
|
||||
if (this.selectedCount === 0) {
|
||||
api.download(format, this.$route.path)
|
||||
} else {
|
||||
let files = []
|
||||
|
||||
for (let i of this.selected) {
|
||||
files.push(this.req.items[i].url)
|
||||
}
|
||||
|
||||
api.download(format, ...files)
|
||||
}
|
||||
|
||||
this.$store.commit('closeHovers')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
23
assets/src/components/prompts/Error.vue
Normal file
23
assets/src/components/prompts/Error.vue
Normal file
@@ -0,0 +1,23 @@
|
||||
<template>
|
||||
<div class="prompt error">
|
||||
<i class="material-icons">error_outline</i>
|
||||
<h3>Something went wrong</h3>
|
||||
<pre>{{ error }}</pre>
|
||||
<div>
|
||||
<button @click="$store.commit('closeHovers')" autofocus>Close</button>
|
||||
<button @click="reportIssue" class="cancel">Report Issue</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'error',
|
||||
props: ['error'],
|
||||
methods: {
|
||||
reportIssue () {
|
||||
window.open('https://github.com/hacdias/filemanager/issues/new')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
31
assets/src/components/prompts/Help.vue
Normal file
31
assets/src/components/prompts/Help.vue
Normal file
@@ -0,0 +1,31 @@
|
||||
<template>
|
||||
<div class="prompt help">
|
||||
<h3>Help</h3>
|
||||
|
||||
<ul>
|
||||
<li><strong>F1</strong> - this information</li>
|
||||
<li><strong>F2</strong> - rename file</li>
|
||||
<li><strong>DEL</strong> - delete selected items</li>
|
||||
<li><strong>ESC</strong> - clear selection and/or close the prompt</li>
|
||||
<li><strong>CTRL + S</strong> - save a file or download the directory where you are</li>
|
||||
<li><strong>CTRL + Click</strong> - select multiple files or directories</li>
|
||||
<li><strong>Double click</strong> - open a file or directory</li>
|
||||
<li><strong>Click</strong> - select file or directory</li>
|
||||
</ul>
|
||||
|
||||
<p>Not available yet</p>
|
||||
|
||||
<ul>
|
||||
<li><strong>Alt + Click</strong> - select a group of files</li>
|
||||
</ul>
|
||||
|
||||
<div>
|
||||
<button type="submit" @click="$store.commit('closeHovers')" class="ok">OK</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {name: 'help'}
|
||||
</script>
|
||||
|
||||
102
assets/src/components/prompts/Info.vue
Normal file
102
assets/src/components/prompts/Info.vue
Normal file
@@ -0,0 +1,102 @@
|
||||
<template>
|
||||
<div class="prompt">
|
||||
<h3>File Information</h3>
|
||||
|
||||
<p v-show="selected.length > 1">{{ selected.length }} files selected.</p>
|
||||
|
||||
<p v-show="selected.length < 2"><strong>Display Name:</strong> {{ name() }}</p>
|
||||
<p><strong>Size:</strong> <span id="content_length"></span>{{ humanSize() }}</p>
|
||||
<p v-show="selected.length < 2"><strong>Last Modified:</strong> {{ humanTime() }}</p>
|
||||
|
||||
<section v-show="dir() && selected.length === 0">
|
||||
<p><strong>Number of files:</strong> {{ req.numFiles }}</p>
|
||||
<p><strong>Number of directories:</strong> {{ req.numDirs }}</p>
|
||||
</section>
|
||||
|
||||
<section v-show="!dir()">
|
||||
<p><strong>MD5:</strong> <code><a @click="checksum($event, 'md5')">show</a></code></p>
|
||||
<p><strong>SHA1:</strong> <code><a @click="checksum($event, 'sha1')">show</a></code></p>
|
||||
<p><strong>SHA256:</strong> <code><a @click="checksum($event, 'sha256')">show</a></code></p>
|
||||
<p><strong>SHA512:</strong> <code><a @click="checksum($event, 'sha512')">show</a></code></p>
|
||||
</section>
|
||||
|
||||
<div>
|
||||
<button type="submit" @click="$store.commit('closeHovers')" class="ok">OK</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState, mapGetters} from 'vuex'
|
||||
import filesize from 'filesize'
|
||||
import moment from 'moment'
|
||||
import api from '@/utils/api'
|
||||
|
||||
export default {
|
||||
name: 'info',
|
||||
computed: {
|
||||
...mapState(['req', 'selected']),
|
||||
...mapGetters(['selectedCount'])
|
||||
},
|
||||
methods: {
|
||||
humanSize: function () {
|
||||
if (this.selectedCount === 0 || this.req.kind !== 'listing') {
|
||||
return filesize(this.req.size)
|
||||
}
|
||||
|
||||
var sum = 0
|
||||
|
||||
for (let i = 0; i < this.selectedCount; i++) {
|
||||
sum += this.req.items[this.selected[i]].size
|
||||
}
|
||||
|
||||
return filesize(sum)
|
||||
},
|
||||
humanTime: function () {
|
||||
if (this.selectedCount === 0) {
|
||||
return moment(this.req.modified).fromNow()
|
||||
}
|
||||
|
||||
return moment(this.req.items[this.selected[0]]).fromNow()
|
||||
},
|
||||
name: function () {
|
||||
if (this.selectedCount === 0) {
|
||||
return this.req.name
|
||||
}
|
||||
|
||||
return this.req.items[this.selected[0]].name
|
||||
},
|
||||
dir: function () {
|
||||
if (this.selectedCount > 1) {
|
||||
// Don't show when multiple selected.
|
||||
return true
|
||||
}
|
||||
|
||||
if (this.selectedCount === 0) {
|
||||
return this.req.isDir
|
||||
}
|
||||
|
||||
return this.req.items[this.selected[0]].isDir
|
||||
},
|
||||
checksum: function (event, hash) {
|
||||
event.preventDefault()
|
||||
|
||||
let link
|
||||
|
||||
if (this.selectedCount) {
|
||||
link = this.req.items[this.selected[0]].url
|
||||
} else {
|
||||
link = this.$route.path
|
||||
}
|
||||
|
||||
api.checksum(link, hash)
|
||||
.then((hash) => {
|
||||
event.target.innerHTML = hash
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
150
assets/src/components/prompts/Move.vue
Normal file
150
assets/src/components/prompts/Move.vue
Normal file
@@ -0,0 +1,150 @@
|
||||
<template>
|
||||
<div class="prompt">
|
||||
<h3>Move</h3>
|
||||
<p>Choose new house for your file(s)/folder(s):</p>
|
||||
|
||||
<ul class="file-list">
|
||||
<li @click="select" @dblclick="next" :key="item.name" v-for="item in items" :data-url="item.url">{{ item.name }}</li>
|
||||
</ul>
|
||||
|
||||
<p>Currently navigating on: <code>{{ current }}</code>.</p>
|
||||
|
||||
<div>
|
||||
<button class="ok" @click="move">Move</button>
|
||||
<button class="cancel" @click="$store.commit('closeHovers')">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import url from '@/utils/url'
|
||||
import api from '@/utils/api'
|
||||
import buttons from '@/utils/buttons'
|
||||
|
||||
export default {
|
||||
name: 'move',
|
||||
data: function () {
|
||||
return {
|
||||
items: [],
|
||||
current: window.location.pathname
|
||||
}
|
||||
},
|
||||
computed: mapState(['req', 'selected', 'baseURL']),
|
||||
mounted: function () {
|
||||
if (this.$route.path !== '/files/') {
|
||||
this.items.push({
|
||||
name: '..',
|
||||
url: url.removeLastDir(this.$route.path) + '/'
|
||||
})
|
||||
}
|
||||
|
||||
if (this.req.kind === 'listing') {
|
||||
for (let item of this.req.items) {
|
||||
if (!item.isDir) continue
|
||||
|
||||
this.items.push({
|
||||
name: item.name,
|
||||
url: item.url
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
move: function (event) {
|
||||
event.preventDefault()
|
||||
|
||||
let el = event.currentTarget
|
||||
let promises = []
|
||||
let dest = this.current
|
||||
buttons.loading('move')
|
||||
|
||||
let selected = el.querySelector('li[aria-selected=true]')
|
||||
if (selected !== null) {
|
||||
dest = selected.dataset.url
|
||||
}
|
||||
|
||||
for (let item of this.selected) {
|
||||
let from = this.req.items[item].url
|
||||
let to = dest + '/' + encodeURIComponent(this.req.items[item].name)
|
||||
to = to.replace('//', '/')
|
||||
|
||||
promises.push(api.move(from, to))
|
||||
}
|
||||
|
||||
this.$store.commit('showMove', false)
|
||||
|
||||
Promise.all(promises)
|
||||
.then(() => {
|
||||
buttons.done('move')
|
||||
this.$router.push({page: dest})
|
||||
})
|
||||
.catch(e => {
|
||||
buttons.done('move')
|
||||
// TODO: show error in prompt
|
||||
console.log(e)
|
||||
})
|
||||
},
|
||||
next: function (event) {
|
||||
let uri = event.currentTarget.dataset.url
|
||||
this.json(uri)
|
||||
.then((data) => {
|
||||
this.current = uri
|
||||
this.items = []
|
||||
|
||||
if (uri !== this.baseURL + '/') {
|
||||
this.items.push({
|
||||
name: '..',
|
||||
url: url.removeLastDir(uri) + '/'
|
||||
})
|
||||
}
|
||||
|
||||
let req = JSON.parse(data)
|
||||
for (let item of req.items) {
|
||||
if (!item.isDir) continue
|
||||
|
||||
this.items.push({
|
||||
name: item.name,
|
||||
url: item.uri
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch(e => console.log(e))
|
||||
},
|
||||
json: function (url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let request = new XMLHttpRequest()
|
||||
request.open('GET', url)
|
||||
request.setRequestHeader('Accept', 'application/json')
|
||||
request.onload = () => {
|
||||
if (request.status === 200) {
|
||||
resolve(request.responseText)
|
||||
} else {
|
||||
reject(request.statusText)
|
||||
}
|
||||
}
|
||||
request.onerror = () => reject(request.statusText)
|
||||
request.send()
|
||||
})
|
||||
},
|
||||
select: function (event) {
|
||||
let el = event.currentTarget
|
||||
|
||||
if (el.getAttribute('aria-selected') === 'true') {
|
||||
el.setAttribute('aria-selected', false)
|
||||
return
|
||||
}
|
||||
|
||||
let el2 = this.$el.querySelector('li[aria-selected=true]')
|
||||
if (el2) {
|
||||
el2.setAttribute('aria-selected', false)
|
||||
}
|
||||
|
||||
el.setAttribute('aria-selected', true)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
51
assets/src/components/prompts/NewDir.vue
Normal file
51
assets/src/components/prompts/NewDir.vue
Normal file
@@ -0,0 +1,51 @@
|
||||
<template>
|
||||
<div class="prompt">
|
||||
<h3>New directory</h3>
|
||||
<p>Write the name of the new directory.</p>
|
||||
<input autofocus type="text" @keyup.enter="submit" v-model.trim="name">
|
||||
<div>
|
||||
<button class="ok" @click="submit">Create</button>
|
||||
<button class="cancel" @click="$store.commit('closeHovers')">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import url from '@/utils/url'
|
||||
import api from '@/utils/api'
|
||||
|
||||
export default {
|
||||
name: 'new-dir',
|
||||
data: function () {
|
||||
return {
|
||||
name: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
submit: function (event) {
|
||||
event.preventDefault()
|
||||
if (this.new === '') return
|
||||
|
||||
let uri = this.$route.path
|
||||
if (this.$store.state.req.kind !== 'listing') {
|
||||
uri = url.removeLastDir(uri) + '/'
|
||||
}
|
||||
|
||||
uri += this.name + '/'
|
||||
uri = uri.replace('//', '/')
|
||||
|
||||
api.post(uri)
|
||||
.then(() => {
|
||||
this.$router.push({ path: uri })
|
||||
})
|
||||
.catch(error => {
|
||||
// TODO: Show error message!
|
||||
console.log(error)
|
||||
})
|
||||
|
||||
this.$store.commit('closeHovers')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
51
assets/src/components/prompts/NewFile.vue
Normal file
51
assets/src/components/prompts/NewFile.vue
Normal file
@@ -0,0 +1,51 @@
|
||||
<template>
|
||||
<div class="prompt">
|
||||
<h3>New file</h3>
|
||||
<p>Write the name of the new file.</p>
|
||||
<input autofocus type="text" @keyup.enter="submit" v-model.trim="name">
|
||||
<div>
|
||||
<button class="ok" @click="submit">Create</button>
|
||||
<button class="cancel" @click="$store.commit('closeHovers')">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import url from '@/utils/url'
|
||||
import api from '@/utils/api'
|
||||
|
||||
export default {
|
||||
name: 'new-file',
|
||||
data: function () {
|
||||
return {
|
||||
name: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
submit: function (event) {
|
||||
event.preventDefault()
|
||||
if (this.new === '') return
|
||||
|
||||
let uri = this.$route.path
|
||||
if (this.$store.state.req.kind !== 'listing') {
|
||||
uri = url.removeLastDir(uri) + '/'
|
||||
}
|
||||
|
||||
uri += this.name
|
||||
uri = uri.replace('//', '/')
|
||||
|
||||
api.post(uri)
|
||||
.then(() => {
|
||||
this.$router.push({ path: uri })
|
||||
})
|
||||
.catch(error => {
|
||||
// TODO: show error message in a box
|
||||
console.log(error)
|
||||
})
|
||||
|
||||
this.$store.commit('closeHovers')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
63
assets/src/components/prompts/Prompts.vue
Normal file
63
assets/src/components/prompts/Prompts.vue
Normal file
@@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<div>
|
||||
<help v-if="showHelp" ></help>
|
||||
<download v-else-if="showDownload"></download>
|
||||
<new-file v-else-if="showNewFile"></new-file>
|
||||
<new-dir v-else-if="showNewDir"></new-dir>
|
||||
<rename v-else-if="showRename"></rename>
|
||||
<delete v-else-if="showDelete"></delete>
|
||||
<info v-else-if="showInfo"></info>
|
||||
<move v-else-if="showMove"></move>
|
||||
<error v-else-if="showError"></error>
|
||||
|
||||
<div v-show="showOverlay" @click="resetPrompts" class="overlay"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Help from './Help'
|
||||
import Info from './Info'
|
||||
import Delete from './Delete'
|
||||
import Rename from './Rename'
|
||||
import Download from './Download'
|
||||
import Move from './Move'
|
||||
import Error from './Error'
|
||||
import NewFile from './NewFile'
|
||||
import NewDir from './NewDir'
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'prompts',
|
||||
components: {
|
||||
Info,
|
||||
Delete,
|
||||
Rename,
|
||||
Error,
|
||||
Download,
|
||||
Move,
|
||||
NewFile,
|
||||
NewDir,
|
||||
Help
|
||||
},
|
||||
computed: {
|
||||
...mapState(['show']),
|
||||
showError: function () { return this.show === 'error' },
|
||||
showInfo: function () { return this.show === 'info' },
|
||||
showHelp: function () { return this.show === 'help' },
|
||||
showDelete: function () { return this.show === 'delete' },
|
||||
showRename: function () { return this.show === 'rename' },
|
||||
showMove: function () { return this.show === 'move' },
|
||||
showNewFile: function () { return this.show === 'newFile' },
|
||||
showNewDir: function () { return this.show === 'newDir' },
|
||||
showDownload: function () { return this.show === 'download' },
|
||||
showOverlay: function () {
|
||||
return (this.show !== null && this.show !== 'search')
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
resetPrompts () {
|
||||
this.$store.commit('closeHovers')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
73
assets/src/components/prompts/Rename.vue
Normal file
73
assets/src/components/prompts/Rename.vue
Normal file
@@ -0,0 +1,73 @@
|
||||
<template>
|
||||
<div class="prompt">
|
||||
<h3>Rename</h3>
|
||||
<p>Insert a new name for <code>{{ oldName() }}</code>:</p>
|
||||
<input autofocus type="text" @keyup.enter="submit" v-model.trim="name">
|
||||
<div>
|
||||
<button @click="submit" type="submit">Rename</button>
|
||||
<button @click="cancel" class="cancel">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import url from '@/utils/url'
|
||||
import api from '@/utils/api'
|
||||
|
||||
export default {
|
||||
name: 'rename',
|
||||
data: function () {
|
||||
return {
|
||||
name: ''
|
||||
}
|
||||
},
|
||||
computed: mapState(['req', 'selected', 'selectedCount']),
|
||||
methods: {
|
||||
cancel: function (event) {
|
||||
this.$store.commit('closeHovers')
|
||||
},
|
||||
oldName: function () {
|
||||
if (this.req.kind !== 'listing') {
|
||||
return this.req.name
|
||||
}
|
||||
|
||||
if (this.selectedCount === 0 || this.selectedCount > 1) {
|
||||
// This shouldn't happen.
|
||||
return
|
||||
}
|
||||
|
||||
return this.req.items[this.selected[0]].name
|
||||
},
|
||||
submit: function (event) {
|
||||
let oldLink = ''
|
||||
let newLink = ''
|
||||
|
||||
if (this.req.kind !== 'listing') {
|
||||
oldLink = this.req.url
|
||||
} else {
|
||||
oldLink = this.req.items[this.selected[0]].url
|
||||
}
|
||||
|
||||
this.name = encodeURIComponent(this.name)
|
||||
newLink = url.removeLastDir(oldLink) + '/' + this.name
|
||||
|
||||
api.move(oldLink, newLink)
|
||||
.then(() => {
|
||||
if (this.req.kind !== 'listing') {
|
||||
this.$router.push({ path: newLink })
|
||||
return
|
||||
}
|
||||
// TODO: keep selected after reload?
|
||||
this.$store.commit('setReload', true)
|
||||
}).catch(error => {
|
||||
// TODO: show error message
|
||||
console.log(error)
|
||||
})
|
||||
|
||||
this.$store.commit('closeHovers')
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user