mirror of
https://github.com/filebrowser/filebrowser.git
synced 2024-06-07 23:00:43 +00:00
vue updates ^_^
This commit is contained in:
parent
2d33b664b5
commit
e2077efbc6
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,6 +1,6 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
node_modules/
|
node_modules/
|
||||||
dist/
|
dist_dev/
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
|
@ -9,21 +9,7 @@ var selectedItems = []
|
|||||||
var overlay
|
var overlay
|
||||||
var clickOverlay
|
var clickOverlay
|
||||||
|
|
||||||
// Removes an element, if exists, from an array
|
|
||||||
Array.prototype.removeElement = function (element) {
|
|
||||||
var i = this.indexOf(element)
|
|
||||||
if (i !== -1) {
|
|
||||||
this.splice(i, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replaces an element inside an array by another
|
|
||||||
Array.prototype.replaceElement = function (oldElement, newElement) {
|
|
||||||
var i = this.indexOf(oldElement)
|
|
||||||
if (i !== -1) {
|
|
||||||
this[i] = newElement
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sends a costum event to itself
|
// Sends a costum event to itself
|
||||||
Document.prototype.sendCostumEvent = function (text) {
|
Document.prototype.sendCostumEvent = function (text) {
|
||||||
@ -37,34 +23,6 @@ Document.prototype.getCookie = function (name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function getCSSRule (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 CSSStyleRule) {
|
|
||||||
for (let i = 0; i < rules.length; i++) {
|
|
||||||
if (cssRule.selectorText.toLowerCase() === rules[i]) {
|
|
||||||
found = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return found
|
|
||||||
})
|
|
||||||
|
|
||||||
return result != null
|
|
||||||
})
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
/* * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * *
|
||||||
* *
|
* *
|
||||||
@ -127,106 +85,7 @@ buttons.setDone = function (name, success = true) {
|
|||||||
* WEBDAV *
|
* WEBDAV *
|
||||||
* *
|
* *
|
||||||
* * * * * * * * * * * * * * * */
|
* * * * * * * * * * * * * * * */
|
||||||
var webdav = {}
|
|
||||||
|
|
||||||
webdav.convertURL = function (url) {
|
|
||||||
return window.location.origin + url.replace(data.baseURL + '/', data.webdavURL + '/')
|
|
||||||
}
|
|
||||||
|
|
||||||
webdav.move = function (oldLink, newLink) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
let request = new window.XMLHttpRequest()
|
|
||||||
let destination = newLink.replace(data.baseURL + '/', data.webdavURL + '/')
|
|
||||||
|
|
||||||
destination = window.location.origin + destination.substring(data.baseURL.length)
|
|
||||||
|
|
||||||
request.open('MOVE', webdav.convertURL(oldLink), true)
|
|
||||||
request.setRequestHeader('Destination', destination)
|
|
||||||
request.onload = () => {
|
|
||||||
if (request.status === 201 || request.status === 204) {
|
|
||||||
resolve()
|
|
||||||
} else {
|
|
||||||
reject(request.statusText)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
request.onerror = () => reject(request.statusText)
|
|
||||||
request.send()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
webdav.put = function (link, body, headers = {}) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
let request = new window.XMLHttpRequest()
|
|
||||||
request.open('PUT', webdav.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)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
webdav.propfind = function (link, body, headers = {}) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
let request = new window.XMLHttpRequest()
|
|
||||||
request.open('PROPFIND', webdav.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)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
webdav.delete = function (link) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
let request = new window.XMLHttpRequest()
|
|
||||||
request.open('DELETE', webdav.convertURL(link), true)
|
|
||||||
request.onload = () => {
|
|
||||||
if (request.status === 204) {
|
|
||||||
resolve()
|
|
||||||
} else {
|
|
||||||
reject(request.statusText)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
request.onerror = () => reject(request.statusText)
|
|
||||||
request.send()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
webdav.new = function (link) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
let request = new window.XMLHttpRequest()
|
|
||||||
request.open((link.endsWith('/') ? 'MKCOL' : 'PUT'), webdav.convertURL(link), true)
|
|
||||||
request.onload = () => {
|
|
||||||
if (request.status === 201) {
|
|
||||||
resolve()
|
|
||||||
} else {
|
|
||||||
reject(request.statusText)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
request.onerror = () => reject(request.statusText)
|
|
||||||
request.send()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/* * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * *
|
||||||
* *
|
* *
|
||||||
|
@ -21,80 +21,6 @@ var listing = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
itemDragStart: function (event) {
|
|
||||||
let el = event.target
|
|
||||||
|
|
||||||
for (let i = 0; i < 5; i++) {
|
|
||||||
if (!el.classList.contains('item')) {
|
|
||||||
el = el.parentElement
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
event.dataTransfer.setData('id', el.id)
|
|
||||||
event.dataTransfer.setData('name', el.querySelector('.name').innerHTML)
|
|
||||||
},
|
|
||||||
itemDragOver: function (event) {
|
|
||||||
event.preventDefault()
|
|
||||||
let el = event.target
|
|
||||||
|
|
||||||
for (let i = 0; i < 5; i++) {
|
|
||||||
if (!el.classList.contains('item')) {
|
|
||||||
el = el.parentElement
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
el.style.opacity = 1
|
|
||||||
},
|
|
||||||
itemDrop: function (e) {
|
|
||||||
e.preventDefault()
|
|
||||||
|
|
||||||
let el = e.target,
|
|
||||||
id = e.dataTransfer.getData('id'),
|
|
||||||
name = e.dataTransfer.getData('name')
|
|
||||||
|
|
||||||
if (id == '' || name == '') return
|
|
||||||
|
|
||||||
for (let i = 0; i < 5; i++) {
|
|
||||||
if (!el.classList.contains('item')) {
|
|
||||||
el = el.parentElement
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (el.id === id) return
|
|
||||||
|
|
||||||
let oldLink = document.getElementById(id).dataset.url,
|
|
||||||
newLink = el.dataset.url + name
|
|
||||||
|
|
||||||
webdav.move(oldLink, newLink)
|
|
||||||
.then(() => listing.reload())
|
|
||||||
.catch(e => console.log(e))
|
|
||||||
},
|
|
||||||
documentDrop: function (event) {
|
|
||||||
event.preventDefault()
|
|
||||||
let dt = event.dataTransfer,
|
|
||||||
files = dt.files,
|
|
||||||
el = event.target,
|
|
||||||
items = document.getElementsByClassName('item')
|
|
||||||
|
|
||||||
for (let i = 0; i < 5; i++) {
|
|
||||||
if (el != null && !el.classList.contains('item')) {
|
|
||||||
el = el.parentElement
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (files.length > 0) {
|
|
||||||
if (el != null && el.classList.contains('item') && el.dataset.dir == 'true') {
|
|
||||||
listing.handleFiles(files, el.querySelector('.name').innerHTML + '/')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
listing.handleFiles(files, '')
|
|
||||||
} else {
|
|
||||||
Array.from(items).forEach(file => {
|
|
||||||
file.style.opacity = 1
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
rename: function (event) {
|
rename: function (event) {
|
||||||
if (!selectedItems.length || selectedItems.length > 1) {
|
if (!selectedItems.length || selectedItems.length > 1) {
|
||||||
return false
|
return false
|
||||||
@ -150,67 +76,9 @@ var listing = {
|
|||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
handleFiles: function (files, base) {
|
handleFiles: function (files, base) {
|
||||||
buttons.setLoading('upload')
|
|
||||||
|
|
||||||
let promises = []
|
|
||||||
|
|
||||||
for (let file of files) {
|
|
||||||
promises.push(webdav.put(window.location.pathname + base + file.name, file))
|
|
||||||
}
|
|
||||||
|
|
||||||
Promise.all(promises)
|
|
||||||
.then(() => {
|
|
||||||
listing.reload()
|
|
||||||
buttons.setDone('upload')
|
|
||||||
})
|
|
||||||
.catch(e => {
|
|
||||||
console.log(e)
|
|
||||||
buttons.setDone('upload', false)
|
|
||||||
})
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
listing.unselectAll = function () {
|
|
||||||
let items = document.getElementsByClassName('item')
|
|
||||||
Array.from(items).forEach(link => {
|
|
||||||
link.setAttribute('aria-selected', false)
|
|
||||||
})
|
|
||||||
|
|
||||||
selectedItems = []
|
|
||||||
|
|
||||||
listing.handleSelectionChange()
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
listing.handleSelectionChange = function (event) {
|
|
||||||
listing.redefineDownloadURLs()
|
|
||||||
|
|
||||||
let selectedNumber = selectedItems.length,
|
|
||||||
fileAction = document.getElementById('file-only')
|
|
||||||
|
|
||||||
if (selectedNumber) {
|
|
||||||
fileAction.classList.remove('disabled')
|
|
||||||
|
|
||||||
if (selectedNumber > 1) {
|
|
||||||
buttons.rename.classList.add('disabled')
|
|
||||||
buttons.info.classList.add('disabled')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectedNumber == 1) {
|
|
||||||
buttons.info.classList.remove('disabled')
|
|
||||||
buttons.rename.classList.remove('disabled')
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
buttons.info.classList.remove('disabled')
|
|
||||||
fileAction.classList.add('disabled')
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
listing.redefineDownloadURLs = function () {
|
listing.redefineDownloadURLs = function () {
|
||||||
let files = ''
|
let files = ''
|
||||||
|
|
||||||
@ -228,28 +96,6 @@ listing.redefineDownloadURLs = function () {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
listing.openItem = function (event) {
|
|
||||||
window.location = event.currentTarget.dataset.url
|
|
||||||
}
|
|
||||||
|
|
||||||
listing.selectItem = function (event) {
|
|
||||||
let el = event.currentTarget
|
|
||||||
|
|
||||||
if (selectedItems.length != 0) event.preventDefault()
|
|
||||||
if (selectedItems.indexOf(el.id) == -1) {
|
|
||||||
if (!event.ctrlKey && !listing.selectMultiple) listing.unselectAll()
|
|
||||||
|
|
||||||
el.setAttribute('aria-selected', true)
|
|
||||||
selectedItems.push(el.id)
|
|
||||||
} else {
|
|
||||||
el.setAttribute('aria-selected', false)
|
|
||||||
selectedItems.removeElement(el.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
listing.handleSelectionChange()
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
listing.newFileButton = function (event) {
|
listing.newFileButton = function (event) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|
||||||
@ -284,13 +130,6 @@ listing.newFilePrompt = function (event) {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
listing.updateColumns = function (event) {
|
|
||||||
let columns = Math.floor(document.getElementById('listing').offsetWidth / 300),
|
|
||||||
items = getCSSRule(['#listing.mosaic .item', '.mosaic#listing .item'])
|
|
||||||
|
|
||||||
items.style.width = `calc(${100/columns}% - 1em)`
|
|
||||||
}
|
|
||||||
|
|
||||||
listing.addDoubleTapEvent = function () {
|
listing.addDoubleTapEvent = function () {
|
||||||
let items = document.getElementsByClassName('item'),
|
let items = document.getElementsByClassName('item'),
|
||||||
touches = {
|
touches = {
|
||||||
@ -343,10 +182,6 @@ window.addEventListener('keydown', (event) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
window.addEventListener('resize', () => {
|
|
||||||
listing.updateColumns()
|
|
||||||
})
|
|
||||||
|
|
||||||
listing.selectMoveFolder = function (event) {
|
listing.selectMoveFolder = function (event) {
|
||||||
if (event.target.getAttribute('aria-selected') === 'true') {
|
if (event.target.getAttribute('aria-selected') === 'true') {
|
||||||
event.target.setAttribute('aria-selected', false)
|
event.target.setAttribute('aria-selected', false)
|
||||||
@ -542,25 +377,6 @@ document.addEventListener('DOMContentLoaded', event => {
|
|||||||
document.getElementById('upload-input').click()
|
document.getElementById('upload-input').click()
|
||||||
})
|
})
|
||||||
|
|
||||||
buttons.new.addEventListener('click', listing.newFileButton)
|
buttons.new.addEventListener('click', listing.newFileButton)
|
||||||
|
|
||||||
// Drag and Drop
|
|
||||||
document.addEventListener('dragover', function (event) {
|
|
||||||
event.preventDefault()
|
|
||||||
}, false)
|
|
||||||
|
|
||||||
document.addEventListener('dragenter', (event) => {
|
|
||||||
Array.from(items).forEach(file => {
|
|
||||||
file.style.opacity = 0.5
|
|
||||||
})
|
|
||||||
}, false)
|
|
||||||
|
|
||||||
document.addEventListener('dragend', (event) => {
|
|
||||||
Array.from(items).forEach(file => {
|
|
||||||
file.style.opacity = 1
|
|
||||||
})
|
|
||||||
}, false)
|
|
||||||
|
|
||||||
document.addEventListener('drop', listing.documentDrop, false)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
{{ define "item" }}
|
|
||||||
<div ondragstart="listing.itemDragStart(event)"
|
|
||||||
{{ if .IsDir}}ondragover="listing.itemDragOver(event)" ondrop="listing.itemDrop(event)"{{ end }}
|
|
||||||
|
|
||||||
onclick="listing.selectItem(event)"
|
|
||||||
ondblclick="listing.openItem(event)"
|
|
||||||
data-dir="{{ .IsDir }}"
|
|
||||||
data-url="{{ .URL }}">
|
|
||||||
|
|
||||||
<div>
|
|
||||||
|
|
||||||
<p class="modified">
|
|
||||||
<time datetime="{{.HumanModTime "2006-01-02T15:04:05Z"}}">{{.HumanModTime "2 Jan 2006 03:04 PM"}}</time>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{ end }}
|
|
@ -21,9 +21,9 @@
|
|||||||
<meta name="msapplication-TileImage" content="{{ .BaseURL }}/_/img/icons/msapplication-icon-144x144.png">
|
<meta name="msapplication-TileImage" content="{{ .BaseURL }}/_/img/icons/msapplication-icon-144x144.png">
|
||||||
<meta name="msapplication-TileColor" content="#000000">
|
<meta name="msapplication-TileColor" content="#000000">
|
||||||
|
|
||||||
<link rel="preload" href="{{ .BaseURL }}/_/js/app.3746baae0d5525e95c4e.js" as="script">
|
<link rel="preload" href="{{ .BaseURL }}/_/js/vendor.429043e9736e4450f715.js" as="script">
|
||||||
<link rel="preload" href="{{ .BaseURL }}/_/js/vendor.89d687258dcaf46efc29.js" as="script">
|
<link rel="preload" href="{{ .BaseURL }}/_/js/app.fcde30b3eb6e988cd456.js" as="script">
|
||||||
<link rel="preload" href="{{ .BaseURL }}/_/js/manifest.83ada933c74b4b19b61c.js" as="script">
|
<link rel="preload" href="{{ .BaseURL }}/_/js/manifest.f2713ae24188290498c4.js" as="script">
|
||||||
|
|
||||||
|
|
||||||
{{- if ne .User.StyleSheet "" -}}
|
{{- if ne .User.StyleSheet "" -}}
|
||||||
@ -32,13 +32,12 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script>
|
<script>
|
||||||
var data = {
|
var info = {
|
||||||
user: JSON.parse('{{ Marshal .User }}'),
|
user: JSON.parse('{{ Marshal .User }}'),
|
||||||
|
page: JSON.parse('{{ Marshal . }}'),
|
||||||
webdavURL: "{{ .WebDavURL }}",
|
webdavURL: "{{ .WebDavURL }}",
|
||||||
baseURL: "{{.BaseURL}}"
|
baseURL: "{{.BaseURL}}"
|
||||||
}
|
}
|
||||||
|
|
||||||
var page = JSON.parse('{{ Marshal . }}')
|
|
||||||
</script>
|
</script>
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<!-- TODO: loading -->
|
<!-- TODO: loading -->
|
||||||
@ -61,5 +60,5 @@ self.addEventListener('activate', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});</script>
|
});</script>
|
||||||
<script type="text/javascript" src="{{ .BaseURL }}/_/js/manifest.83ada933c74b4b19b61c.js"></script><script type="text/javascript" src="{{ .BaseURL }}/_/js/vendor.89d687258dcaf46efc29.js"></script><script type="text/javascript" src="{{ .BaseURL }}/_/js/app.3746baae0d5525e95c4e.js"></script></body>
|
<script type="text/javascript" src="{{ .BaseURL }}/_/js/manifest.f2713ae24188290498c4.js"></script><script type="text/javascript" src="{{ .BaseURL }}/_/js/vendor.429043e9736e4450f715.js"></script><script type="text/javascript" src="{{ .BaseURL }}/_/js/app.fcde30b3eb6e988cd456.js"></script></body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -32,13 +32,12 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script>
|
<script>
|
||||||
var data = {
|
var info = {
|
||||||
user: JSON.parse('{{ Marshal .User }}'),
|
user: JSON.parse('{{ Marshal .User }}'),
|
||||||
|
page: JSON.parse('{{ Marshal . }}'),
|
||||||
webdavURL: "{{ .WebDavURL }}",
|
webdavURL: "{{ .WebDavURL }}",
|
||||||
baseURL: "{{.BaseURL}}"
|
baseURL: "{{.BaseURL}}"
|
||||||
}
|
}
|
||||||
|
|
||||||
var page = JSON.parse('{{ Marshal . }}')
|
|
||||||
</script>
|
</script>
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<!-- TODO: loading -->
|
<!-- TODO: loading -->
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<div id="click-overlay"></div>
|
<div id="click-overlay"></div>
|
||||||
</header>
|
</header>
|
||||||
<nav id="sidebar">
|
<nav id="sidebar">
|
||||||
<a class="action" :href="baseURL()">
|
<a class="action" :href="baseURL + '/'">
|
||||||
<i class="material-icons">folder</i>
|
<i class="material-icons">folder</i>
|
||||||
<span>My Files</span>
|
<span>My Files</span>
|
||||||
</a>
|
</a>
|
||||||
@ -21,10 +21,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<main>
|
<main>
|
||||||
<listing v-if="Kind == 'listing'"></listing>
|
<listing v-if="page.kind == 'listing'"></listing>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<preview v-if="Kind == 'preview'"></preview>
|
<preview v-if="page.kind == 'preview'"></preview>
|
||||||
|
|
||||||
<div class="overlay"></div>
|
<div class="overlay"></div>
|
||||||
<!-- TODO: show on listing and allowedit -->
|
<!-- TODO: show on listing and allowedit -->
|
||||||
@ -50,17 +50,24 @@
|
|||||||
import Search from './components/Search'
|
import Search from './components/Search'
|
||||||
import Preview from './components/Preview'
|
import Preview from './components/Preview'
|
||||||
import Listing from './components/Listing'
|
import Listing from './components/Listing'
|
||||||
|
import css from './css.js'
|
||||||
|
|
||||||
|
function updateColumnSizes () {
|
||||||
|
let columns = Math.floor(document.querySelector('main').offsetWidth / 300)
|
||||||
|
let items = css(['#listing.mosaic .item', '.mosaic#listing .item'])
|
||||||
|
|
||||||
|
items.style.width = `calc(${100 / columns}% - 1em)`
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'app',
|
name: 'app',
|
||||||
components: { Search, Preview, Listing },
|
components: { Search, Preview, Listing },
|
||||||
data: function () {
|
mounted: function () {
|
||||||
return window.page
|
updateColumnSizes()
|
||||||
|
window.addEventListener('resize', updateColumnSizes)
|
||||||
},
|
},
|
||||||
methods: {
|
data: function () {
|
||||||
baseURL: function () {
|
return window.info
|
||||||
return window.data.baseURL + '/'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
24
_assets/src/array.js
Normal file
24
_assets/src/array.js
Normal file
@ -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
|
||||||
|
}
|
@ -1,16 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="listing" :class="Data.Display">
|
<div id="listing"
|
||||||
|
:class="data.display"
|
||||||
|
@drop="drop"
|
||||||
|
@dragenter="dragEnter"
|
||||||
|
@dragend="dragEnd">
|
||||||
<div>
|
<div>
|
||||||
<div class="item header">
|
<div class="item header">
|
||||||
<div></div>
|
<div></div>
|
||||||
<div>
|
<div>
|
||||||
<p v-bind:class="{ active: Data.Sort === 'name' }" class="name"><span>Name</span>
|
<p v-bind:class="{ active: data.sort === 'name' }" class="name"><span>Name</span>
|
||||||
<a v-if="Data.Sort === 'name' && Data.Order != 'asc'" href="?sort=name&order=asc"><i class="material-icons">arrow_upward</i></a>
|
<a v-if="data.sort === 'name' && data.order != 'asc'" href="?sort=name&order=asc"><i class="material-icons">arrow_upward</i></a>
|
||||||
<a v-else href="?sort=name&order=desc"><i class="material-icons">arrow_downward</i></a>
|
<a v-else href="?sort=name&order=desc"><i class="material-icons">arrow_downward</i></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p v-bind:class="{ active: Data.Sort === 'size' }" class="size"><span>Size</span>
|
<p v-bind:class="{ active: data.sort === 'size' }" class="size"><span>Size</span>
|
||||||
<a v-if="Data.Sort === 'size' && Data.Order != 'asc'" href="?sort=size&order=asc"><i class="material-icons">arrow_upward</i></a>
|
<a v-if="data.sort === 'size' && data.order != 'asc'" href="?sort=size&order=asc"><i class="material-icons">arrow_upward</i></a>
|
||||||
<a v-else href="?sort=size&order=desc"><i class="material-icons">arrow_downward</i></a>
|
<a v-else href="?sort=size&order=desc"><i class="material-icons">arrow_downward</i></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@ -19,37 +23,39 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2 v-if="(Data.NumDirs + Data.NumFiles) == 0" class="message">It feels lonely here :'(</h2>
|
<h2 v-if="(data.numDirs + data.numFiles) == 0" class="message">It feels lonely here :'(</h2>
|
||||||
|
|
||||||
<h2 v-if="Data.NumDirs !== 0">Folders</h2>
|
<h2 v-if="data.numDirs > 0">Folders</h2>
|
||||||
<div v-if="Data.NumDirs !== 0">
|
<div v-if="data.numDirs > 0">
|
||||||
<item
|
<item
|
||||||
v-for="(item, index) in Data.Items"
|
v-for="(item, index) in data.items"
|
||||||
v-if="item.IsDir"
|
v-if="item.isDir"
|
||||||
:key="base64(item.Name)"
|
:key="base64(item.name)"
|
||||||
:id="base64(item.Name)"
|
:id="base64(item.name)"
|
||||||
v-bind:name="item.Name"
|
v-bind:selected="selected"
|
||||||
v-bind:isDir="item.IsDir"
|
v-bind:name="item.name"
|
||||||
v-bind:url="item.URL"
|
v-bind:isDir="item.isDir"
|
||||||
v-bind:modified="item.ModTime"
|
v-bind:url="item.url"
|
||||||
v-bind:type="item.Type"
|
v-bind:modified="item.modified"
|
||||||
v-bind:size="item.Size">
|
v-bind:type="item.type"
|
||||||
|
v-bind:size="item.size">
|
||||||
</item>
|
</item>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2 v-if="Data.NumItems !== 0">Files</h2>
|
<h2 v-if="data.numFiles > 0">Files</h2>
|
||||||
<div v-if="Data.NumItems !== 0">
|
<div v-if="data.numFiles > 0">
|
||||||
<item
|
<item
|
||||||
v-for="(item, index) in Data.Items"
|
v-for="(item, index) in data.items"
|
||||||
v-if="!item.IsDir"
|
v-if="!item.isDir"
|
||||||
:key="base64(item.Name)"
|
:key="base64(item.name)"
|
||||||
:id="base64(item.Name)"
|
:id="base64(item.name)"
|
||||||
v-bind:name="item.Name"
|
v-bind:selected="selected"
|
||||||
v-bind:isDir="item.IsDir"
|
v-bind:name="item.name"
|
||||||
v-bind:modified="item.ModTime"
|
v-bind:isDir="item.isDir"
|
||||||
v-bind:url="item.URL"
|
v-bind:url="item.url"
|
||||||
v-bind:type="item.Type"
|
v-bind:modified="item.modified"
|
||||||
v-bind:size="item.Size">
|
v-bind:type="item.type"
|
||||||
|
v-bind:size="item.size">
|
||||||
</item>
|
</item>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -61,16 +67,119 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Item from './ListingItem'
|
import Item from './ListingItem'
|
||||||
|
import webdav from '../webdav.js'
|
||||||
|
import page from '../page.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'preview',
|
name: 'preview',
|
||||||
components: { Item },
|
|
||||||
data: function () {
|
data: function () {
|
||||||
return window.page
|
return {
|
||||||
|
data: window.info.page.data,
|
||||||
|
selected: [],
|
||||||
|
multiple: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: { Item },
|
||||||
|
mounted: function () {
|
||||||
|
document.addEventListener('dragover', function (event) {
|
||||||
|
event.preventDefault()
|
||||||
|
}, false)
|
||||||
|
|
||||||
|
document.addEventListener('drop', this.drop, false)
|
||||||
|
},
|
||||||
|
beforeUpdate: function () {
|
||||||
|
/*
|
||||||
|
listing.redefineDownloadURLs()
|
||||||
|
|
||||||
|
let selectedNumber = selectedItems.length,
|
||||||
|
fileAction = document.getElementById('file-only')
|
||||||
|
|
||||||
|
if (selectedNumber) {
|
||||||
|
fileAction.classList.remove('disabled')
|
||||||
|
|
||||||
|
if (selectedNumber > 1) {
|
||||||
|
buttons.rename.classList.add('disabled')
|
||||||
|
buttons.info.classList.add('disabled')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedNumber == 1) {
|
||||||
|
buttons.info.classList.remove('disabled')
|
||||||
|
buttons.rename.classList.remove('disabled')
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
buttons.info.classList.remove('disabled')
|
||||||
|
fileAction.classList.add('disabled')
|
||||||
|
*/
|
||||||
|
console.log('before upding')
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
base64: function (name) {
|
base64: function (name) {
|
||||||
return window.btoa(name)
|
return window.btoa(name)
|
||||||
|
},
|
||||||
|
dragEnter: function (event) {
|
||||||
|
let items = document.getElementsByClassName('item')
|
||||||
|
|
||||||
|
Array.from(items).forEach(file => {
|
||||||
|
file.style.opacity = 0.5
|
||||||
|
})
|
||||||
|
},
|
||||||
|
dragEnd: function (event) {
|
||||||
|
let items = document.getElementsByClassName('item')
|
||||||
|
|
||||||
|
Array.from(items).forEach(file => {
|
||||||
|
file.style.opacity = 1
|
||||||
|
})
|
||||||
|
},
|
||||||
|
drop: function (event) {
|
||||||
|
event.preventDefault()
|
||||||
|
|
||||||
|
let dt = event.dataTransfer
|
||||||
|
let files = dt.files
|
||||||
|
let el = event.target
|
||||||
|
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
if (el !== null && !el.classList.contains('item')) {
|
||||||
|
el = el.parentElement
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (files.length > 0) {
|
||||||
|
if (el !== null && el.classList.contains('item') && el.dataset.dir === 'true') {
|
||||||
|
this.handleFiles(files, el.querySelector('.name').innerHTML + '/')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.handleFiles(files, '')
|
||||||
|
} else {
|
||||||
|
let items = document.getElementsByClassName('item')
|
||||||
|
|
||||||
|
Array.from(items).forEach(file => {
|
||||||
|
file.style.opacity = 1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleFiles: function (files, base) {
|
||||||
|
// buttons.setLoading('upload')
|
||||||
|
let promises = []
|
||||||
|
|
||||||
|
for (let file of files) {
|
||||||
|
promises.push(webdav.put(window.location.pathname + base + file.name, file))
|
||||||
|
}
|
||||||
|
|
||||||
|
Promise.all(promises)
|
||||||
|
.then(() => {
|
||||||
|
page.reload()
|
||||||
|
// buttons.setDone('upload')
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
console.log(e)
|
||||||
|
// buttons.setDone('upload', false)
|
||||||
|
})
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="item"
|
<div class="item"
|
||||||
draggable="true"
|
draggable="true"
|
||||||
:id="base64()"
|
@dragstart="dragStart"
|
||||||
:data-dir="isDir"
|
@dragover="dragOver"
|
||||||
:data-url="url" >
|
@drop="drop"
|
||||||
|
@click="click"
|
||||||
|
@dblclick="open"
|
||||||
|
:id="base64()">
|
||||||
<div>
|
<div>
|
||||||
<i class="material-icons">{{ icon() }}</i>
|
<i class="material-icons">{{ icon() }}</i>
|
||||||
</div>
|
</div>
|
||||||
@ -24,10 +27,13 @@
|
|||||||
<script>
|
<script>
|
||||||
import filesize from 'filesize'
|
import filesize from 'filesize'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
|
import webdav from '../webdav.js'
|
||||||
|
import page from '../page.js'
|
||||||
|
import array from '../array.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'item',
|
name: 'item',
|
||||||
props: ['name', 'isDir', 'url', 'type', 'size', 'modified'],
|
props: ['name', 'isDir', 'url', 'type', 'size', 'modified', 'selected'],
|
||||||
methods: {
|
methods: {
|
||||||
icon: function () {
|
icon: function () {
|
||||||
if (this.isDir) return 'folder'
|
if (this.isDir) return 'folder'
|
||||||
@ -44,6 +50,76 @@ export default {
|
|||||||
},
|
},
|
||||||
base64: function () {
|
base64: function () {
|
||||||
return window.btoa(this.name)
|
return window.btoa(this.name)
|
||||||
|
},
|
||||||
|
dragStart: function (event) {
|
||||||
|
let el = event.target
|
||||||
|
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
if (!el.classList.contains('item')) {
|
||||||
|
el = el.parentElement
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event.dataTransfer.setData('name', el.querySelector('.name').innerHTML)
|
||||||
|
event.dataTransfer.setData('obj-url', this.url)
|
||||||
|
},
|
||||||
|
dragOver: function (event) {
|
||||||
|
if (!this.isDir) return
|
||||||
|
|
||||||
|
event.preventDefault()
|
||||||
|
let el = event.target
|
||||||
|
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
if (!el.classList.contains('item')) {
|
||||||
|
el = el.parentElement
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
el.style.opacity = 1
|
||||||
|
},
|
||||||
|
drop: function (event) {
|
||||||
|
if (!this.isDir) return
|
||||||
|
event.preventDefault()
|
||||||
|
|
||||||
|
let url = event.dataTransfer.getData('obj-url')
|
||||||
|
let name = event.dataTransfer.getData('name')
|
||||||
|
|
||||||
|
if (name === '' || url === '' || url === this.url) return
|
||||||
|
|
||||||
|
webdav.move(url, this.url + name)
|
||||||
|
.then(() => page.reload())
|
||||||
|
.catch(error => console.log(error))
|
||||||
|
},
|
||||||
|
unselectAll: function () {
|
||||||
|
let items = document.getElementsByClassName('item')
|
||||||
|
Array.from(items).forEach(link => {
|
||||||
|
link.setAttribute('aria-selected', false)
|
||||||
|
})
|
||||||
|
|
||||||
|
this.selected.length = 0
|
||||||
|
|
||||||
|
// listing.handleSelectionChange()
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
click: function (event) {
|
||||||
|
let el = event.currentTarget
|
||||||
|
|
||||||
|
if (this.selected.length !== 0) event.preventDefault()
|
||||||
|
if (this.selected.indexOf(el.id) === -1) {
|
||||||
|
if (!event.ctrlKey && !this.multiple) this.unselectAll()
|
||||||
|
|
||||||
|
el.setAttribute('aria-selected', true)
|
||||||
|
this.selected.push(el.id)
|
||||||
|
} else {
|
||||||
|
el.setAttribute('aria-selected', false)
|
||||||
|
this.selected = array.remove(this.selected, el.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// this.handleSelectionChange()
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
open: function (event) {
|
||||||
|
page.open(this.url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="previewer">
|
<div id="previewer">
|
||||||
<div class="bar">
|
<div class="bar">
|
||||||
<button class="action" aria-label="Close Preview" id="close">
|
<button @click="back" class="action" aria-label="Close Preview" id="close">
|
||||||
<i class="material-icons">close</i>
|
<i class="material-icons">close</i>
|
||||||
</button>
|
</button>
|
||||||
<!-- TODO: add more buttons -->
|
<!-- TODO: add more buttons -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="preview">
|
<div class="preview">
|
||||||
<img v-if="Data.Type == 'image'" :src="raw()">
|
<img v-if="type == 'image'" :src="raw()">
|
||||||
<audio v-else-if="Data.Type == 'audio'" :src="raw()" controls></audio>
|
<audio v-else-if="type == 'audio'" :src="raw()" controls></audio>
|
||||||
<video v-else-if="Data.Type == 'video'" :src="raw()" controls>
|
<video v-else-if="type == 'video'" :src="raw()" controls>
|
||||||
Sorry, your browser doesn't support embedded videos,
|
Sorry, your browser doesn't support embedded videos,
|
||||||
but don't worry, you can <a href="?download=true">download it</a>
|
but don't worry, you can <a href="?download=true">download it</a>
|
||||||
and watch it with your favorite video player!
|
and watch it with your favorite video player!
|
||||||
</video>
|
</video>
|
||||||
<object v-else-if="Data.Extension == '.pdf'" class="pdf" :data="raw()"></object>
|
<object v-else-if="extension == '.pdf'" class="pdf" :data="raw()"></object>
|
||||||
<a v-else-if="Data.Type == 'blob'" href="?download=true"><h2 class="message">Download <i class="material-icons">file_download</i></h2></a>
|
<a v-else-if="type == 'blob'" href="?download=true"><h2 class="message">Download <i class="material-icons">file_download</i></h2></a>
|
||||||
<pre v-else >{{ Data.Content }}</pre>
|
<pre v-else >{{ content }}</pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -26,11 +26,14 @@
|
|||||||
export default {
|
export default {
|
||||||
name: 'preview',
|
name: 'preview',
|
||||||
data: function () {
|
data: function () {
|
||||||
return window.page
|
return window.info.page.data
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
raw: function () {
|
raw: function () {
|
||||||
return this.Data.URL + '?raw=true'
|
return this.url + '?raw=true'
|
||||||
|
},
|
||||||
|
back: function (event) {
|
||||||
|
window.history.back()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
// Remove the last directory of an url
|
// Remove the last directory of an url
|
||||||
var removeLastDirectoryPartOf = function (url) {
|
var removeLastDirectoryPartOf = function (url) {
|
||||||
var arr = url.split('/')
|
var arr = url.split('/')
|
||||||
@ -26,7 +25,7 @@ var removeLastDirectoryPartOf = function (url) {
|
|||||||
return (arr.join('/'))
|
return (arr.join('/'))
|
||||||
}
|
}
|
||||||
|
|
||||||
var data = window.data
|
var user = window.info.user
|
||||||
var ssl = window.ssl
|
var ssl = window.ssl
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -48,8 +47,8 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
reset: function () {
|
reset: function () {
|
||||||
if (data.user.AllowCommands && data.user.Commands.length > 0) {
|
if (user.allowCommands && user.commands.length > 0) {
|
||||||
this.box.innerHTML = `Search or use one of your supported commands: ${data.user.Commands.join(', ')}.`
|
this.box.innerHTML = `Search or use one of your supported commands: ${user.commands.join(', ')}.`
|
||||||
} else {
|
} else {
|
||||||
this.box.innerHTML = 'Type and press enter to search.'
|
this.box.innerHTML = 'Type and press enter to search.'
|
||||||
}
|
}
|
||||||
@ -58,8 +57,8 @@ export default {
|
|||||||
let value = this.input.value
|
let value = this.input.value
|
||||||
let pieces = value.split(' ')
|
let pieces = value.split(' ')
|
||||||
|
|
||||||
for (let i = 0; i < data.user.Commands.length; i++) {
|
for (let i = 0; i < user.commands.length; i++) {
|
||||||
if (pieces[0] === data.user.Commands[0]) {
|
if (pieces[0] === user.commands[0]) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -78,7 +77,7 @@ export default {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.supported() || !data.user.AllowCommands) {
|
if (!this.supported() || !user.allowCommands) {
|
||||||
this.box.innerHTML = 'Press enter to search.'
|
this.box.innerHTML = 'Press enter to search.'
|
||||||
} else {
|
} else {
|
||||||
this.box.innerHTML = 'Press enter to execute.'
|
this.box.innerHTML = 'Press enter to execute.'
|
||||||
@ -96,7 +95,7 @@ export default {
|
|||||||
|
|
||||||
let protocol = ssl ? 'wss:' : 'ws:'
|
let protocol = ssl ? 'wss:' : 'ws:'
|
||||||
|
|
||||||
if (this.supported() && data.user.AllowCommands) {
|
if (this.supported() && user.allowCommands) {
|
||||||
let conn = new window.WebSocket(`${protocol}//${url}?command=true`)
|
let conn = new window.WebSocket(`${protocol}//${url}?command=true`)
|
||||||
|
|
||||||
conn.onopen = () => {
|
conn.onopen = () => {
|
||||||
|
28
_assets/src/css.js
Normal file
28
_assets/src/css.js
Normal file
@ -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
|
||||||
|
}
|
@ -2,12 +2,40 @@
|
|||||||
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
|
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import App from './App'
|
import App from './App'
|
||||||
|
// simport page from './page.js'
|
||||||
window.data = (window.data || window.alert('Something is wrong, please refresh!'))
|
|
||||||
window.ssl = (window.location.protocol === 'https:')
|
|
||||||
|
|
||||||
Vue.config.productionTip = false
|
Vue.config.productionTip = false
|
||||||
|
|
||||||
|
window.info = (window.info || window.alert('Something is wrong, please refresh!'))
|
||||||
|
window.ssl = (window.location.protocol === 'https:')
|
||||||
|
|
||||||
|
// TODO: keep this here?
|
||||||
|
document.title = window.info.page.name
|
||||||
|
|
||||||
|
// TODO: keep this here?
|
||||||
|
window.addEventListener('popstate', (event) => {
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
|
||||||
|
window.info.page.kind = ''
|
||||||
|
|
||||||
|
let request = new window.XMLHttpRequest()
|
||||||
|
request.open('GET', event.state.url, true)
|
||||||
|
request.setRequestHeader('Accept', 'application/json')
|
||||||
|
|
||||||
|
request.onload = () => {
|
||||||
|
if (request.status === 200) {
|
||||||
|
window.info.page = JSON.parse(request.responseText)
|
||||||
|
document.title = event.state.name
|
||||||
|
} else {
|
||||||
|
console.log(request.responseText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
request.onerror = (error) => { console.log(error) }
|
||||||
|
request.send()
|
||||||
|
})
|
||||||
|
|
||||||
/* eslint-disable no-new */
|
/* eslint-disable no-new */
|
||||||
new Vue({
|
new Vue({
|
||||||
el: '#app',
|
el: '#app',
|
||||||
|
36
_assets/src/page.js
Normal file
36
_assets/src/page.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
function open (url, history) {
|
||||||
|
window.info.page.kind = ''
|
||||||
|
|
||||||
|
let request = new window.XMLHttpRequest()
|
||||||
|
request.open('GET', url, true)
|
||||||
|
request.setRequestHeader('Accept', 'application/json')
|
||||||
|
|
||||||
|
request.onload = () => {
|
||||||
|
if (request.status === 200) {
|
||||||
|
window.info.page = JSON.parse(request.responseText)
|
||||||
|
|
||||||
|
if (history) {
|
||||||
|
window.history.pushState({
|
||||||
|
name: window.info.page.name,
|
||||||
|
url: url
|
||||||
|
}, window.info.page.name, url)
|
||||||
|
|
||||||
|
document.title = window.info.page.name
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log(request.responseText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
request.onerror = (error) => { console.log(error) }
|
||||||
|
request.send()
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
reload: () => {
|
||||||
|
open(window.location.pathname, false)
|
||||||
|
},
|
||||||
|
open: (url) => {
|
||||||
|
open(url, true)
|
||||||
|
}
|
||||||
|
}
|
109
_assets/src/webdav.js
Normal file
109
_assets/src/webdav.js
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
var info = window.info
|
||||||
|
|
||||||
|
function convertURL (url) {
|
||||||
|
return window.location.origin + url.replace(info.baseURL + '/', info.webdavURL + '/')
|
||||||
|
}
|
||||||
|
|
||||||
|
function move (oldLink, newLink) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let request = new window.XMLHttpRequest()
|
||||||
|
|
||||||
|
oldLink = convertURL(oldLink)
|
||||||
|
newLink = newLink.replace(info.baseURL + '/', info.webdavURL + '/')
|
||||||
|
newLink = window.location.origin + newLink.substring(info.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
|
||||||
|
}
|
@ -10,16 +10,21 @@ import (
|
|||||||
var m *filemanager.FileManager
|
var m *filemanager.FileManager
|
||||||
|
|
||||||
func handler(w http.ResponseWriter, r *http.Request) {
|
func handler(w http.ResponseWriter, r *http.Request) {
|
||||||
_, err := m.ServeHTTP(w, r)
|
// TODO: review return codes and return 0 when everything works.
|
||||||
|
|
||||||
|
code, err := m.ServeHTTP(w, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print(err)
|
log.Print(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if code != 0 {
|
||||||
|
w.WriteHeader(code)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
m = filemanager.New("D:\\TEST")
|
m = filemanager.New("D:\\TEST")
|
||||||
m.SetBaseURL("/vaca")
|
m.SetBaseURL("/vaca")
|
||||||
m.AllowEdit = false
|
|
||||||
m.Commands = []string{"git"}
|
m.Commands = []string{"git"}
|
||||||
http.HandleFunc("/", handler)
|
http.HandleFunc("/", handler)
|
||||||
http.ListenAndServe(":8080", nil)
|
http.ListenAndServe(":8080", nil)
|
||||||
|
40
file.go
40
file.go
@ -31,48 +31,48 @@ type fileInfo struct {
|
|||||||
// Used to store the file's content temporarily.
|
// Used to store the file's content temporarily.
|
||||||
content []byte
|
content []byte
|
||||||
// The name of the file.
|
// The name of the file.
|
||||||
Name string
|
Name string `json:"name"`
|
||||||
// The Size of the file.
|
// The Size of the file.
|
||||||
Size int64
|
Size int64 `json:"size"`
|
||||||
// The absolute URL.
|
// The absolute URL.
|
||||||
URL string
|
URL string `json:"url"`
|
||||||
// The extension of the file.
|
// The extension of the file.
|
||||||
Extension string
|
Extension string `json:"extension"`
|
||||||
// The last modified time.
|
// The last modified time.
|
||||||
ModTime time.Time
|
ModTime time.Time `json:"modified"`
|
||||||
// The File Mode.
|
// The File Mode.
|
||||||
Mode os.FileMode
|
Mode os.FileMode `json:"mode"`
|
||||||
// Indicates if this file is a directory.
|
// Indicates if this file is a directory.
|
||||||
IsDir bool
|
IsDir bool `json:"isDir"`
|
||||||
// Absolute path.
|
// Absolute path.
|
||||||
Path string
|
Path string `json:"path"`
|
||||||
// Relative path to user's virtual File System.
|
// Relative path to user's virtual File System.
|
||||||
VirtualPath string
|
VirtualPath string `json:"virtualPath"`
|
||||||
// Indicates the file content type: video, text, image, music or blob.
|
// Indicates the file content type: video, text, image, music or blob.
|
||||||
Type string
|
Type string `json:"type"`
|
||||||
// Stores the content of a text file.
|
// Stores the content of a text file.
|
||||||
Content string
|
Content string `json:"content"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// A listing is the context used to fill out a template.
|
// A listing is the context used to fill out a template.
|
||||||
type listing struct {
|
type listing struct {
|
||||||
// The name of the directory (the last element of the path).
|
// The name of the directory (the last element of the path).
|
||||||
Name string
|
Name string `json:"-"`
|
||||||
// The full path of the request relatively to a File System.
|
// The full path of the request relatively to a File System.
|
||||||
Path string
|
Path string `json:"-"`
|
||||||
// The items (files and folders) in the path.
|
// The items (files and folders) in the path.
|
||||||
Items []fileInfo
|
Items []fileInfo `json:"items"`
|
||||||
// The number of directories in the listing.
|
// The number of directories in the listing.
|
||||||
NumDirs int
|
NumDirs int `json:"numDirs"`
|
||||||
// The number of files (items that aren't directories) in the listing.
|
// The number of files (items that aren't directories) in the listing.
|
||||||
NumFiles int
|
NumFiles int `json:"numFiles"`
|
||||||
// Which sorting order is used.
|
// Which sorting order is used.
|
||||||
Sort string
|
Sort string `json:"sort"`
|
||||||
// And which order.
|
// And which order.
|
||||||
Order string
|
Order string `json:"order"`
|
||||||
// If ≠0 then Items have been limited to that many elements.
|
// If ≠0 then Items have been limited to that many elements.
|
||||||
ItemsLimitedTo int
|
ItemsLimitedTo int `json:"ItemsLimitedTo"`
|
||||||
Display string
|
Display string `json:"display"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// getInfo gets the file information and, in case of error, returns the
|
// getInfo gets the file information and, in case of error, returns the
|
||||||
|
@ -69,12 +69,12 @@ type User struct {
|
|||||||
StyleSheet string `json:"-"`
|
StyleSheet string `json:"-"`
|
||||||
|
|
||||||
// These indicate if the user can perform certain actions.
|
// These indicate if the user can perform certain actions.
|
||||||
AllowNew bool // Create files and folders
|
AllowNew bool `json:"allowNew"` // Create files and folders
|
||||||
AllowEdit bool // Edit/rename files
|
AllowEdit bool `json:"allowEdit"` // Edit/rename files
|
||||||
AllowCommands bool // Execute commands
|
AllowCommands bool `json:"allowCommands"` // Execute commands
|
||||||
|
|
||||||
// Commands is the list of commands the user can execute.
|
// Commands is the list of commands the user can execute.
|
||||||
Commands []string
|
Commands []string `json:"commands"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rule is a dissalow/allow rule.
|
// Rule is a dissalow/allow rule.
|
||||||
|
8
page.go
8
page.go
@ -35,10 +35,10 @@ type page struct {
|
|||||||
BaseURL string `json:"-"`
|
BaseURL string `json:"-"`
|
||||||
WebDavURL string `json:"-"`
|
WebDavURL string `json:"-"`
|
||||||
|
|
||||||
Name string
|
Name string `json:"name"`
|
||||||
Path string
|
Path string `json:"path"`
|
||||||
Kind string // listing, editor or preview
|
Kind string `json:"kind"` // listing, editor or preview
|
||||||
Data interface{}
|
Data interface{} `json:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// breadcrumbItem contains the Name and the URL of a breadcrumb piece.
|
// breadcrumbItem contains the Name and the URL of a breadcrumb piece.
|
||||||
|
6
serve.go
6
serve.go
@ -95,14 +95,14 @@ func serveListing(c *requestContext, w http.ResponseWriter, r *http.Request) (in
|
|||||||
listing.ItemsLimitedTo = limit
|
listing.ItemsLimitedTo = limit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
listing.Display = displayMode(w, r, cookieScope)
|
||||||
|
c.pg.Data = listing
|
||||||
|
|
||||||
// If it's a JSON request, print only the items... in JSON! (such a surprise -_-)
|
// If it's a JSON request, print only the items... in JSON! (such a surprise -_-)
|
||||||
if strings.Contains(r.Header.Get("Accept"), "application/json") {
|
if strings.Contains(r.Header.Get("Accept"), "application/json") {
|
||||||
c.pg.Data = listing.Items
|
|
||||||
return c.pg.PrintJSON(w)
|
return c.pg.PrintJSON(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
listing.Display = displayMode(w, r, cookieScope)
|
|
||||||
c.pg.Data = listing
|
|
||||||
return c.pg.PrintHTML(w, c.fm.templates)
|
return c.pg.PrintHTML(w, c.fm.templates)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user