diff --git a/_assets/index.html b/_assets/index.html
index 6b19b129..6c540a9f 100644
--- a/_assets/index.html
+++ b/_assets/index.html
@@ -99,17 +99,7 @@
user: JSON.parse('{{ Marshal .User }}'),
req: JSON.parse('{{ Marshal . }}'),
webdavURL: "{{ .WebDavURL }}",
- baseURL: "{{.BaseURL}}",
- ssl: (window.location.protocol === 'https:'),
- showInfo: false,
- showHelp: false,
- showDelete: false,
- showRename: false,
- showMove: false,
- showNewFile: false,
- showNewDir: false,
- selected: [],
- multiple: false
+ baseURL: "{{.BaseURL}}"
}
diff --git a/_assets/package.json b/_assets/package.json
index bac6a1fd..0ac07c70 100644
--- a/_assets/package.json
+++ b/_assets/package.json
@@ -12,7 +12,8 @@
"dependencies": {
"filesize": "^3.5.10",
"moment": "^2.18.1",
- "vue": "^2.3.3"
+ "vue": "^2.3.3",
+ "vuex": "^2.3.1"
},
"devDependencies": {
"autoprefixer": "^6.7.2",
diff --git a/_assets/src/App.vue b/_assets/src/App.vue
index 84121ede..b5811259 100644
--- a/_assets/src/App.vue
+++ b/_assets/src/App.vue
@@ -22,11 +22,11 @@
My Files
-
@@ -89,16 +88,6 @@ function updateColumnSizes () {
items.style.width = `calc(${100 / columns}% - 1em)`
}
-function resetPrompts () {
- $.showHelp = false
- $.showInfo = false
- $.showDelete = false
- $.showRename = false
- $.showMove = false
- $.showNewFile = false
- $.showNewDir = false
-}
-
function showRenameButton () {
if ($.req.kind === 'listing') {
if ($.selected.length === 1) {
@@ -123,78 +112,6 @@ function showDeleteButton () {
return $.user.allowEdit
}
-function keydown (event) {
- // Esc!
- if (event.keyCode === 27) {
- resetPrompts()
-
- // Unselect all files and folders.
- if ($.req.kind === 'listing') {
- let items = document.getElementsByClassName('item')
- Array.from(items).forEach(link => {
- link.setAttribute('aria-selected', false)
- })
-
- $.selected = []
- }
-
- return
- }
-
- // Del!
- if (event.keyCode === 46) {
- if (showDeleteButton()) {
- $.showDelete = true
- }
- }
-
- // F1!
- if (event.keyCode === 112) {
- event.preventDefault()
- $.showHelp = true
- }
-
- // F2!
- if (event.keyCode === 113) {
- if (showRenameButton()) {
- $.showRename = true
- }
- }
-
- // CTRL + S
- if (event.ctrlKey || event.metaKey) {
- switch (String.fromCharCode(event.which).toLowerCase()) {
- case 's':
- event.preventDefault()
-
- if ($.req.kind !== 'editor') {
- window.location = '?download=true'
- return
- }
-
- // TODO: save file on editor!
- }
- }
-}
-
-function startup () {
- updateColumnSizes()
- window.addEventListener('resize', updateColumnSizes)
- window.history.replaceState({
- url: window.location.pathname,
- name: document.title
- }, document.title, window.location.pathname)
-
- window.addEventListener('keydown', keydown)
-
- let loading = document.getElementById('loading')
- loading.classList.add('done')
-
- setTimeout(function () {
- loading.parentNode.removeChild(loading)
- }, 1000)
-}
-
export default {
name: 'app',
components: {
@@ -218,21 +135,78 @@ export default {
NewDirPrompt
},
mounted: function () {
- startup()
+ updateColumnSizes()
+ window.addEventListener('resize', updateColumnSizes)
+ window.history.replaceState({
+ url: window.location.pathname,
+ name: document.title
+ }, document.title, window.location.pathname)
+
+ window.addEventListener('keydown', (event) => {
+ // Esc!
+ if (event.keyCode === 27) {
+ this.$store.commit('resetPrompts')
+
+ // Unselect all files and folders.
+ if ($.req.kind === 'listing') {
+ let items = document.getElementsByClassName('item')
+ Array.from(items).forEach(link => {
+ link.setAttribute('aria-selected', false)
+ })
+
+ $.selected = []
+ }
+
+ return
+ }
+
+ // Del!
+ if (event.keyCode === 46) {
+ if (showDeleteButton()) {
+ $.showDelete = true
+ }
+ }
+
+ // F1!
+ if (event.keyCode === 112) {
+ event.preventDefault()
+ $.showHelp = true
+ }
+
+ // F2!
+ if (event.keyCode === 113) {
+ if (showRenameButton()) {
+ $.showRename = true
+ }
+ }
+
+ // CTRL + S
+ if (event.ctrlKey || event.metaKey) {
+ switch (String.fromCharCode(event.which).toLowerCase()) {
+ case 's':
+ event.preventDefault()
+
+ if ($.req.kind !== 'editor') {
+ window.location = '?download=true'
+ return
+ }
+
+ // TODO: save file on editor!
+ }
+ }
+ })
+
+ let loading = document.getElementById('loading')
+ loading.classList.add('done')
+
+ setTimeout(function () {
+ loading.parentNode.removeChild(loading)
+ }, 1000)
},
data: function () {
return window.info
},
methods: {
- showOverlay: function () {
- return $.showInfo ||
- $.showHelp ||
- $.showDelete ||
- $.showRename ||
- $.showMove ||
- $.showNewFile ||
- $.showNewDir
- },
showUpload: function () {
if (this.req.kind === 'editor') return false
return $.user.allowNew
@@ -250,7 +224,9 @@ export default {
return false
},
- resetPrompts: resetPrompts
+ resetPrompts: function () {
+ this.$store.commit('resetPrompts')
+ }
}
}
diff --git a/_assets/src/components/DeleteButton.vue b/_assets/src/components/DeleteButton.vue
index 559b6fb4..9624110e 100644
--- a/_assets/src/components/DeleteButton.vue
+++ b/_assets/src/components/DeleteButton.vue
@@ -10,7 +10,7 @@ export default {
name: 'delete-button',
methods: {
show: function (event) {
- window.info.showDelete = true
+ this.$store.commit('showDelete', true)
}
}
}
diff --git a/_assets/src/components/DeletePrompt.vue b/_assets/src/components/DeletePrompt.vue
index 8c97dd14..ea99eb40 100644
--- a/_assets/src/components/DeletePrompt.vue
+++ b/_assets/src/components/DeletePrompt.vue
@@ -23,10 +23,10 @@ export default {
},
methods: {
cancel: function (event) {
- $.showDelete = false
+ this.$store.commit('showDelete', false)
},
submit: function (event) {
- $.showDelete = false
+ this.$store.commit('showDelete', false)
// buttons.setLoading('delete')
if ($.req.kind !== 'listing') {
diff --git a/_assets/src/components/InfoButton.vue b/_assets/src/components/InfoButton.vue
index 1704d887..0d821380 100644
--- a/_assets/src/components/InfoButton.vue
+++ b/_assets/src/components/InfoButton.vue
@@ -10,7 +10,7 @@ export default {
name: 'info-button',
methods: {
show: function (event) {
- window.info.showInfo = true
+ this.$store.commit('showInfo', true)
}
}
}
diff --git a/_assets/src/components/InfoPrompt.vue b/_assets/src/components/InfoPrompt.vue
index c552e737..e43875ec 100644
--- a/_assets/src/components/InfoPrompt.vue
+++ b/_assets/src/components/InfoPrompt.vue
@@ -102,7 +102,7 @@ export default {
request.send()
},
close: function () {
- this.showInfo = false
+ this.$store.commit('showInfo', false)
}
}
}
diff --git a/_assets/src/components/MoveButton.vue b/_assets/src/components/MoveButton.vue
index d15ef264..3b6c100b 100644
--- a/_assets/src/components/MoveButton.vue
+++ b/_assets/src/components/MoveButton.vue
@@ -10,7 +10,7 @@ export default {
name: 'move-button',
methods: {
show: function (event) {
- window.info.showMove = true
+ this.$store.commit('showMove', true)
}
}
}
diff --git a/_assets/src/components/MovePrompt.vue b/_assets/src/components/MovePrompt.vue
index 60a58369..30dd7b7b 100644
--- a/_assets/src/components/MovePrompt.vue
+++ b/_assets/src/components/MovePrompt.vue
@@ -53,7 +53,7 @@ export default {
},
methods: {
cancel: function (event) {
- $.showMove = false
+ this.$store.commit('showMove', false)
},
move: function (event) {
event.preventDefault()
@@ -76,7 +76,7 @@ export default {
promises.push(webdav.move(from, to))
}
- $.showMove = false
+ this.$store.commit('showMove', false)
Promise.all(promises)
.then(() => {
diff --git a/_assets/src/components/NewDirPrompt.vue b/_assets/src/components/NewDirPrompt.vue
index acf23e24..4b4fa271 100644
--- a/_assets/src/components/NewDirPrompt.vue
+++ b/_assets/src/components/NewDirPrompt.vue
@@ -14,8 +14,6 @@
import page from '../page'
import webdav from '../webdav'
-var $ = window.info
-
export default {
name: 'new-dir-prompt',
data: function () {
@@ -25,7 +23,7 @@ export default {
},
methods: {
cancel: function () {
- $.showNewDir = false
+ this.$store.commit('showNewDir', false)
},
submit: function (event) {
event.preventDefault()
@@ -45,7 +43,7 @@ export default {
console.log(e)
})
- $.showNewDir = false
+ this.$store.commit('showNewDir', false)
}
}
}
diff --git a/_assets/src/components/NewFilePrompt.vue b/_assets/src/components/NewFilePrompt.vue
index 173dd738..da89b4d8 100644
--- a/_assets/src/components/NewFilePrompt.vue
+++ b/_assets/src/components/NewFilePrompt.vue
@@ -14,8 +14,6 @@
import page from '../page'
import webdav from '../webdav'
-var $ = window.info
-
export default {
name: 'new-file-prompt',
data: function () {
@@ -25,7 +23,7 @@ export default {
},
methods: {
cancel: function () {
- $.showNewFile = false
+ this.$store.commit('showNewFile', false)
},
submit: function (event) {
event.preventDefault()
@@ -42,7 +40,7 @@ export default {
console.log(e)
})
- $.showNewFile = false
+ this.$store.commit('showNewFile', false)
}
}
}
diff --git a/_assets/src/components/RenameButton.vue b/_assets/src/components/RenameButton.vue
index 875dd5fa..db8bb44d 100644
--- a/_assets/src/components/RenameButton.vue
+++ b/_assets/src/components/RenameButton.vue
@@ -10,7 +10,7 @@ export default {
name: 'rename-button',
methods: {
show: function (event) {
- window.info.showRename = true
+ this.$store.commit('showRename', true)
}
}
}
diff --git a/_assets/src/components/RenamePrompt.vue b/_assets/src/components/RenamePrompt.vue
index c51c3f45..898d2d67 100644
--- a/_assets/src/components/RenamePrompt.vue
+++ b/_assets/src/components/RenamePrompt.vue
@@ -25,7 +25,7 @@ export default {
},
methods: {
cancel: function (event) {
- $.showRename = false
+ this.$store.commit('showRename', false)
},
oldName: function () {
if ($.req.kind !== 'listing') {
@@ -68,7 +68,7 @@ export default {
})
this.name = ''
- $.showRename = false
+ this.$store.commit('showRename', false)
return
}
}
diff --git a/_assets/src/components/Search.vue b/_assets/src/components/Search.vue
index 9fd17783..b8d5bfb9 100644
--- a/_assets/src/components/Search.vue
+++ b/_assets/src/components/Search.vue
@@ -85,7 +85,7 @@ export default {
url = page.removeLastDir(url)
}
- let protocol = $.ssl ? 'wss:' : 'ws:'
+ let protocol = this.$store.state.ssl ? 'wss:' : 'ws:'
if (this.supported() && $.user.allowCommands) {
let conn = new window.WebSocket(`${protocol}//${url}?command=true`)
diff --git a/_assets/src/main.js b/_assets/src/main.js
index eb848086..91e337d2 100644
--- a/_assets/src/main.js
+++ b/_assets/src/main.js
@@ -2,6 +2,7 @@
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
+import store from './store/store'
// simport page from './page.js'
Vue.config.productionTip = false
@@ -46,6 +47,7 @@ window.addEventListener('popstate', (event) => {
/* eslint-disable no-new */
new Vue({
el: '#app',
+ store,
template: '',
components: { App }
})
diff --git a/_assets/src/mixins/buttons.js b/_assets/src/mixins/buttons.js
new file mode 100644
index 00000000..57a4c57c
--- /dev/null
+++ b/_assets/src/mixins/buttons.js
@@ -0,0 +1,50 @@
+export default {
+ data: function () {
+ return {
+ buttonState: ''
+ }
+ },
+ methods: {
+ setLoading: function () {
+ let i = this.$el.querySelector('i')
+ i.style.opacity = 0
+
+ this.buttonState = i.innerHTML
+
+ setTimeout(() => {
+ i.classList.add('spin')
+ i.innerHTML = 'autorenew'
+ i.style.opacity = 1
+ }, 200)
+ },
+ setDone: function (success = true) {
+ let i = this.$el.querySelector('i')
+ i.style.opacity = 0
+
+ let thirdStep = () => {
+ i.innerHTML = this.buttonState
+ i.style.opacity = null
+ }
+
+ let secondStep = () => {
+ i.style.opacity = 0
+ setTimeout(thirdStep, 200)
+ }
+
+ let firstStep = () => {
+ i.classList.remove('spin')
+ i.innerHTML = success
+ ? 'done'
+ : 'close'
+ i.style.opacity = 1
+ setTimeout(secondStep, 1000)
+ }
+
+ setTimeout(firstStep, 200)
+ }
+ }
+}
+/* // third step ?
+if (selectedItems.length === 0 && document.getElementById('listing')) {
+ document.sendCostumEvent('changed-selected')
+} */
diff --git a/_assets/src/store/store.js b/_assets/src/store/store.js
new file mode 100644
index 00000000..03903c02
--- /dev/null
+++ b/_assets/src/store/store.js
@@ -0,0 +1,59 @@
+import Vue from 'vue'
+import Vuex from 'vuex'
+
+Vue.use(Vuex)
+
+const state = {
+ ssl: (window.location.protocol === 'https:'),
+ selected: [],
+ multiple: false,
+ showInfo: false,
+ showHelp: false,
+ showDelete: false,
+ showRename: false,
+ showMove: false,
+ showNewFile: false,
+ showNewDir: false
+}
+
+const getters = {
+ showOverlay: state => {
+ return state.showInfo ||
+ state.showHelp ||
+ state.showDelete ||
+ state.showRename ||
+ state.showMove ||
+ state.showNewFile ||
+ state.showNewDir
+ }
+}
+
+const mutations = {
+ showInfo: (state, value) => (state.showInfo = value),
+ showHelp: (state, value) => (state.showHelp = value),
+ showDelete: (state, value) => (state.showDelete = value),
+ showRename: (state, value) => (state.showRename = value),
+ showMove: (state, value) => (state.showMove = value),
+ showNewFile: (state, value) => (state.showNewFile = value),
+ showNewDir: (state, value) => (state.showNewDir = value),
+ resetPrompts: (state) => {
+ state.showHelp = false
+ state.showInfo = false
+ state.showDelete = false
+ state.showRename = false
+ state.showMove = false
+ state.showNewFile = false
+ state.showNewDir = false
+ },
+ multiple: (state, value) => (state.multiple = value),
+ resetSelected: (state) => {
+ state.selected.length = 0
+ }
+}
+
+export default new Vuex.Store({
+ strict: process.env.NODE_ENV !== 'production',
+ state,
+ getters,
+ mutations
+})
diff --git a/_assets/src/utils/array.js b/_assets/src/utils/array.js
new file mode 100644
index 00000000..b06b5f7a
--- /dev/null
+++ b/_assets/src/utils/array.js
@@ -0,0 +1,24 @@
+// Removes an element, if exists, from an array
+function removeElement (array, element) {
+ var i = array.indexOf(element)
+ if (i !== -1) {
+ array.splice(i, 1)
+ }
+
+ return array
+}
+
+// Replaces an element inside an array by another
+function replaceElement (array, oldElement, newElement) {
+ var i = array.indexOf(oldElement)
+ if (i !== -1) {
+ array[i] = newElement
+ }
+
+ return array
+}
+
+export default {
+ remove: removeElement,
+ replace: replaceElement
+}
diff --git a/_assets/src/utils/css.js b/_assets/src/utils/css.js
new file mode 100644
index 00000000..15ab99fe
--- /dev/null
+++ b/_assets/src/utils/css.js
@@ -0,0 +1,28 @@
+export default function getRule (rules) {
+ for (let i = 0; i < rules.length; i++) {
+ rules[i] = rules[i].toLowerCase()
+ }
+
+ let result = null
+ let find = Array.prototype.find
+
+ find.call(document.styleSheets, styleSheet => {
+ result = find.call(styleSheet.cssRules, cssRule => {
+ let found = false
+
+ if (cssRule instanceof window.CSSStyleRule) {
+ for (let i = 0; i < rules.length; i++) {
+ if (cssRule.selectorText.toLowerCase() === rules[i]) {
+ found = true
+ }
+ }
+ }
+
+ return found
+ })
+
+ return result != null
+ })
+
+ return result
+}
diff --git a/_assets/src/utils/page.js b/_assets/src/utils/page.js
new file mode 100644
index 00000000..344995a9
--- /dev/null
+++ b/_assets/src/utils/page.js
@@ -0,0 +1,50 @@
+var $ = window.info
+
+function open (url, history) {
+ // Reset info
+ $.selected = []
+ $.multiple = false
+ $.req.kind = ''
+
+ let request = new window.XMLHttpRequest()
+ request.open('GET', url, true)
+ request.setRequestHeader('Accept', 'application/json')
+
+ request.onload = () => {
+ if (request.status === 200) {
+ $.req = JSON.parse(request.responseText)
+
+ if (history) {
+ window.history.pushState({
+ name: $.req.data.name,
+ url: url
+ }, $.req.data.name, url)
+
+ document.title = $.req.data.name
+ }
+ } else {
+ console.log(request.responseText)
+ }
+ }
+
+ request.onerror = (error) => { console.log(error) }
+ request.send()
+}
+
+function removeLastDir (url) {
+ var arr = url.split('/')
+ if (arr.pop() === '') {
+ arr.pop()
+ }
+ return (arr.join('/'))
+}
+
+export default {
+ reload: () => {
+ open(window.location.pathname, false)
+ },
+ open: (url) => {
+ open(url, true)
+ },
+ removeLastDir: removeLastDir
+}
diff --git a/_assets/src/utils/webdav.js b/_assets/src/utils/webdav.js
new file mode 100644
index 00000000..bd40f3a4
--- /dev/null
+++ b/_assets/src/utils/webdav.js
@@ -0,0 +1,109 @@
+var $ = window.info
+
+function convertURL (url) {
+ return window.location.origin + url.replace($.baseURL + '/', $.webdavURL + '/')
+}
+
+function move (oldLink, newLink) {
+ return new Promise((resolve, reject) => {
+ let request = new window.XMLHttpRequest()
+
+ oldLink = convertURL(oldLink)
+ newLink = newLink.replace($.baseURL + '/', $.webdavURL + '/')
+ newLink = window.location.origin + newLink.substring($.baseURL.length)
+
+ request.open('MOVE', oldLink, true)
+ request.setRequestHeader('Destination', newLink)
+ request.onload = () => {
+ if (request.status === 201 || request.status === 204) {
+ resolve()
+ } else {
+ reject(request.statusText)
+ }
+ }
+ request.onerror = () => reject(request.statusText)
+ request.send()
+ })
+}
+
+function put (link, body, headers = {}) {
+ return new Promise((resolve, reject) => {
+ let request = new window.XMLHttpRequest()
+ request.open('PUT', convertURL(link), true)
+
+ for (let key in headers) {
+ request.setRequestHeader(key, headers[key])
+ }
+
+ request.onload = () => {
+ if (request.status === 201) {
+ resolve()
+ } else {
+ reject(request.statusText)
+ }
+ }
+ request.onerror = () => reject(request.statusText)
+ request.send(body)
+ })
+}
+
+function propfind (link, body, headers = {}) {
+ return new Promise((resolve, reject) => {
+ let request = new window.XMLHttpRequest()
+ request.open('PROPFIND', convertURL(link), true)
+
+ for (let key in headers) {
+ request.setRequestHeader(key, headers[key])
+ }
+
+ request.onload = () => {
+ if (request.status < 300) {
+ resolve(request.responseText)
+ } else {
+ reject(request.statusText)
+ }
+ }
+ request.onerror = () => reject(request.statusText)
+ request.send(body)
+ })
+}
+
+function trash (link) {
+ return new Promise((resolve, reject) => {
+ let request = new window.XMLHttpRequest()
+ request.open('DELETE', convertURL(link), true)
+ request.onload = () => {
+ if (request.status === 204) {
+ resolve()
+ } else {
+ reject(request.statusText)
+ }
+ }
+ request.onerror = () => reject(request.statusText)
+ request.send()
+ })
+}
+
+function create (link) {
+ return new Promise((resolve, reject) => {
+ let request = new window.XMLHttpRequest()
+ request.open((link.endsWith('/') ? 'MKCOL' : 'PUT'), convertURL(link), true)
+ request.onload = () => {
+ if (request.status === 201) {
+ resolve()
+ } else {
+ reject(request.statusText)
+ }
+ }
+ request.onerror = () => reject(request.statusText)
+ request.send()
+ })
+}
+
+export default {
+ create: create,
+ trash: trash,
+ propfind: propfind,
+ put: put,
+ move: move
+}