chore: add prettier frontent linter
This commit is contained in:
parent
a721dc1f31
commit
c44b37c50c
|
@ -1,5 +1,3 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
presets: [
|
presets: ["@vue/app"],
|
||||||
'@vue/app'
|
};
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -5,8 +5,9 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"serve": "vue-cli-service serve",
|
"serve": "vue-cli-service serve",
|
||||||
"build": "find ./dist -maxdepth 1 -mindepth 1 ! -name '.gitignore' -exec rm -r {} + && vue-cli-service build --no-clean",
|
"build": "find ./dist -maxdepth 1 -mindepth 1 ! -name '.gitignore' -exec rm -r {} + && vue-cli-service build --no-clean",
|
||||||
"watch": "find ./dist -maxdepth 1 -mindepth 1 ! -name '.gitignore' -exec rm -r {} + && vue-cli-service build --watch --no-clean",
|
"lint": "npx vue-cli-service lint --no-fix",
|
||||||
"lint": "vue-cli-service lint --fix"
|
"fix": "npx vue-cli-service lint",
|
||||||
|
"watch": "find ./dist -maxdepth 1 -mindepth 1 ! -name '.gitignore' -exec rm -r {} + && vue-cli-service build --watch --no-clean"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ace-builds": "^1.4.7",
|
"ace-builds": "^1.4.7",
|
||||||
|
@ -29,11 +30,14 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vue/cli-plugin-babel": "^4.1.2",
|
"@vue/cli-plugin-babel": "^4.1.2",
|
||||||
"@vue/cli-plugin-eslint": "^4.1.1",
|
"@vue/cli-plugin-eslint": "~4.5.0",
|
||||||
"@vue/cli-service": "^4.1.2",
|
"@vue/cli-service": "^4.1.2",
|
||||||
"babel-eslint": "^10.0.3",
|
"@vue/eslint-config-prettier": "^6.0.0",
|
||||||
|
"babel-eslint": "^10.1.0",
|
||||||
"eslint": "^6.7.2",
|
"eslint": "^6.7.2",
|
||||||
"eslint-plugin-vue": "^6.1.2",
|
"eslint-plugin-prettier": "^3.3.1",
|
||||||
|
"eslint-plugin-vue": "^6.2.2",
|
||||||
|
"prettier": "^2.2.1",
|
||||||
"vue-template-compiler": "^2.6.10"
|
"vue-template-compiler": "^2.6.10"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
|
@ -43,7 +47,8 @@
|
||||||
},
|
},
|
||||||
"extends": [
|
"extends": [
|
||||||
"plugin:vue/essential",
|
"plugin:vue/essential",
|
||||||
"eslint:recommended"
|
"eslint:recommended",
|
||||||
|
"@vue/prettier"
|
||||||
],
|
],
|
||||||
"rules": {},
|
"rules": {},
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
|
|
|
@ -6,18 +6,18 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'app',
|
name: "app",
|
||||||
mounted () {
|
mounted() {
|
||||||
const loading = document.getElementById('loading')
|
const loading = document.getElementById("loading");
|
||||||
loading.classList.add('done')
|
loading.classList.add("done");
|
||||||
|
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
loading.parentNode.removeChild(loading)
|
loading.parentNode.removeChild(loading);
|
||||||
}, 200)
|
}, 200);
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@import './css/styles.css';
|
@import "./css/styles.css";
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
import { removePrefix } from './utils'
|
import { removePrefix } from "./utils";
|
||||||
import { baseURL } from '@/utils/constants'
|
import { baseURL } from "@/utils/constants";
|
||||||
import store from '@/store'
|
import store from "@/store";
|
||||||
|
|
||||||
const ssl = (window.location.protocol === 'https:')
|
const ssl = window.location.protocol === "https:";
|
||||||
const protocol = (ssl ? 'wss:' : 'ws:')
|
const protocol = ssl ? "wss:" : "ws:";
|
||||||
|
|
||||||
export default function command(url, command, onmessage, onclose) {
|
export default function command(url, command, onmessage, onclose) {
|
||||||
url = removePrefix(url)
|
url = removePrefix(url);
|
||||||
url = `${protocol}//${window.location.host}${baseURL}/api/command${url}?auth=${store.state.jwt}`
|
url = `${protocol}//${window.location.host}${baseURL}/api/command${url}?auth=${store.state.jwt}`;
|
||||||
|
|
||||||
let conn = new window.WebSocket(url)
|
let conn = new window.WebSocket(url);
|
||||||
conn.onopen = () => conn.send(command)
|
conn.onopen = () => conn.send(command);
|
||||||
conn.onmessage = onmessage
|
conn.onmessage = onmessage;
|
||||||
conn.onclose = onclose
|
conn.onclose = onclose;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,147 +1,156 @@
|
||||||
import { fetchURL, removePrefix } from './utils'
|
import { fetchURL, removePrefix } from "./utils";
|
||||||
import { baseURL } from '@/utils/constants'
|
import { baseURL } from "@/utils/constants";
|
||||||
import store from '@/store'
|
import store from "@/store";
|
||||||
|
|
||||||
export async function fetch (url) {
|
export async function fetch(url) {
|
||||||
url = removePrefix(url)
|
url = removePrefix(url);
|
||||||
|
|
||||||
const res = await fetchURL(`/api/resources${url}`, {})
|
const res = await fetchURL(`/api/resources${url}`, {});
|
||||||
|
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
let data = await res.json()
|
let data = await res.json();
|
||||||
data.url = `/files${url}`
|
data.url = `/files${url}`;
|
||||||
|
|
||||||
if (data.isDir) {
|
if (data.isDir) {
|
||||||
if (!data.url.endsWith('/')) data.url += '/'
|
if (!data.url.endsWith("/")) data.url += "/";
|
||||||
data.items = data.items.map((item, index) => {
|
data.items = data.items.map((item, index) => {
|
||||||
item.index = index
|
item.index = index;
|
||||||
item.url = `${data.url}${encodeURIComponent(item.name)}`
|
item.url = `${data.url}${encodeURIComponent(item.name)}`;
|
||||||
|
|
||||||
if (item.isDir) {
|
if (item.isDir) {
|
||||||
item.url += '/'
|
item.url += "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
return item
|
return item;
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return data
|
return data;
|
||||||
} else {
|
} else {
|
||||||
throw new Error(res.status)
|
throw new Error(res.status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function resourceAction (url, method, content) {
|
async function resourceAction(url, method, content) {
|
||||||
url = removePrefix(url)
|
url = removePrefix(url);
|
||||||
|
|
||||||
let opts = { method }
|
let opts = { method };
|
||||||
|
|
||||||
if (content) {
|
if (content) {
|
||||||
opts.body = content
|
opts.body = content;
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await fetchURL(`/api/resources${url}`, opts)
|
const res = await fetchURL(`/api/resources${url}`, opts);
|
||||||
|
|
||||||
if (res.status !== 200) {
|
if (res.status !== 200) {
|
||||||
throw new Error(await res.text())
|
throw new Error(await res.text());
|
||||||
} else {
|
} else {
|
||||||
return res
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function remove (url) {
|
export async function remove(url) {
|
||||||
return resourceAction(url, 'DELETE')
|
return resourceAction(url, "DELETE");
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function put (url, content = '') {
|
export async function put(url, content = "") {
|
||||||
return resourceAction(url, 'PUT', content)
|
return resourceAction(url, "PUT", content);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function download (format, ...files) {
|
export function download(format, ...files) {
|
||||||
let url = `${baseURL}/api/raw`
|
let url = `${baseURL}/api/raw`;
|
||||||
|
|
||||||
if (files.length === 1) {
|
if (files.length === 1) {
|
||||||
url += removePrefix(files[0]) + '?'
|
url += removePrefix(files[0]) + "?";
|
||||||
} else {
|
} else {
|
||||||
let arg = ''
|
let arg = "";
|
||||||
|
|
||||||
for (let file of files) {
|
for (let file of files) {
|
||||||
arg += removePrefix(file) + ','
|
arg += removePrefix(file) + ",";
|
||||||
}
|
}
|
||||||
|
|
||||||
arg = arg.substring(0, arg.length - 1)
|
arg = arg.substring(0, arg.length - 1);
|
||||||
arg = encodeURIComponent(arg)
|
arg = encodeURIComponent(arg);
|
||||||
url += `/?files=${arg}&`
|
url += `/?files=${arg}&`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format) {
|
if (format) {
|
||||||
url += `algo=${format}&`
|
url += `algo=${format}&`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (store.state.jwt){
|
if (store.state.jwt) {
|
||||||
url += `auth=${store.state.jwt}&`
|
url += `auth=${store.state.jwt}&`;
|
||||||
}
|
}
|
||||||
|
|
||||||
window.open(url)
|
window.open(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function post (url, content = '', overwrite = false, onupload) {
|
export async function post(url, content = "", overwrite = false, onupload) {
|
||||||
url = removePrefix(url)
|
url = removePrefix(url);
|
||||||
|
|
||||||
let bufferContent
|
let bufferContent;
|
||||||
if (content instanceof Blob && !['http:', 'https:'].includes(window.location.protocol)) {
|
if (
|
||||||
bufferContent = await new Response(content).arrayBuffer()
|
content instanceof Blob &&
|
||||||
|
!["http:", "https:"].includes(window.location.protocol)
|
||||||
|
) {
|
||||||
|
bufferContent = await new Response(content).arrayBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let request = new XMLHttpRequest()
|
let request = new XMLHttpRequest();
|
||||||
request.open('POST', `${baseURL}/api/resources${url}?override=${overwrite}`, true)
|
request.open(
|
||||||
request.setRequestHeader('X-Auth', store.state.jwt)
|
"POST",
|
||||||
|
`${baseURL}/api/resources${url}?override=${overwrite}`,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
request.setRequestHeader("X-Auth", store.state.jwt);
|
||||||
|
|
||||||
if (typeof onupload === 'function') {
|
if (typeof onupload === "function") {
|
||||||
request.upload.onprogress = onupload
|
request.upload.onprogress = onupload;
|
||||||
}
|
}
|
||||||
|
|
||||||
request.onload = () => {
|
request.onload = () => {
|
||||||
if (request.status === 200) {
|
if (request.status === 200) {
|
||||||
resolve(request.responseText)
|
resolve(request.responseText);
|
||||||
} else if (request.status === 409) {
|
} else if (request.status === 409) {
|
||||||
reject(request.status)
|
reject(request.status);
|
||||||
} else {
|
} else {
|
||||||
reject(request.responseText)
|
reject(request.responseText);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
request.onerror = (error) => {
|
request.onerror = (error) => {
|
||||||
reject(error)
|
reject(error);
|
||||||
}
|
};
|
||||||
|
|
||||||
request.send(bufferContent || content)
|
request.send(bufferContent || content);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function moveCopy (items, copy = false, overwrite = false, rename = 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 = item.from
|
const from = item.from;
|
||||||
const to = encodeURIComponent(removePrefix(item.to))
|
const to = encodeURIComponent(removePrefix(item.to));
|
||||||
const url = `${from}?action=${copy ? 'copy' : 'rename'}&destination=${to}&override=${overwrite}&rename=${rename}`
|
const url = `${from}?action=${
|
||||||
promises.push(resourceAction(url, 'PATCH'))
|
copy ? "copy" : "rename"
|
||||||
|
}&destination=${to}&override=${overwrite}&rename=${rename}`;
|
||||||
|
promises.push(resourceAction(url, "PATCH"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.all(promises)
|
return Promise.all(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function move (items, overwrite = false, rename = false) {
|
export function move(items, overwrite = false, rename = false) {
|
||||||
return moveCopy(items, false, overwrite, rename)
|
return moveCopy(items, false, overwrite, rename);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function copy (items, overwrite = false, rename = false) {
|
export function copy(items, overwrite = false, rename = false) {
|
||||||
return moveCopy(items, true, overwrite, rename)
|
return moveCopy(items, true, overwrite, rename);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function checksum (url, algo) {
|
export async function checksum(url, algo) {
|
||||||
const data = await resourceAction(`${url}?checksum=${algo}`, 'GET')
|
const data = await resourceAction(`${url}?checksum=${algo}`, "GET");
|
||||||
return (await data.json()).checksums[algo]
|
return (await data.json()).checksums[algo];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,9 @@
|
||||||
import * as files from './files'
|
import * as files from "./files";
|
||||||
import * as share from './share'
|
import * as share from "./share";
|
||||||
import * as users from './users'
|
import * as users from "./users";
|
||||||
import * as settings from './settings'
|
import * as settings from "./settings";
|
||||||
import * as pub from './pub'
|
import * as pub from "./pub";
|
||||||
import search from './search'
|
import search from "./search";
|
||||||
import commands from './commands'
|
import commands from "./commands";
|
||||||
|
|
||||||
export {
|
export { files, share, users, settings, pub, commands, search };
|
||||||
files,
|
|
||||||
share,
|
|
||||||
users,
|
|
||||||
settings,
|
|
||||||
pub,
|
|
||||||
commands,
|
|
||||||
search
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,61 +1,61 @@
|
||||||
import { fetchURL, removePrefix } from './utils'
|
import { fetchURL, removePrefix } from "./utils";
|
||||||
import { baseURL } from '@/utils/constants'
|
import { baseURL } from "@/utils/constants";
|
||||||
|
|
||||||
export async function fetch (url, password = "") {
|
export async function fetch(url, password = "") {
|
||||||
url = removePrefix(url)
|
url = removePrefix(url);
|
||||||
|
|
||||||
const res = await fetchURL(`/api/public/share${url}`, {
|
const res = await fetchURL(`/api/public/share${url}`, {
|
||||||
headers: {'X-SHARE-PASSWORD': password},
|
headers: { "X-SHARE-PASSWORD": password },
|
||||||
})
|
});
|
||||||
|
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
let data = await res.json()
|
let data = await res.json();
|
||||||
data.url = `/share${url}`
|
data.url = `/share${url}`;
|
||||||
|
|
||||||
if (data.isDir) {
|
if (data.isDir) {
|
||||||
if (!data.url.endsWith('/')) data.url += '/'
|
if (!data.url.endsWith("/")) data.url += "/";
|
||||||
data.items = data.items.map((item, index) => {
|
data.items = data.items.map((item, index) => {
|
||||||
item.index = index
|
item.index = index;
|
||||||
item.url = `${data.url}${encodeURIComponent(item.name)}`
|
item.url = `${data.url}${encodeURIComponent(item.name)}`;
|
||||||
|
|
||||||
if (item.isDir) {
|
if (item.isDir) {
|
||||||
item.url += '/'
|
item.url += "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
return item
|
return item;
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return data
|
return data;
|
||||||
} else {
|
} else {
|
||||||
throw new Error(res.status)
|
throw new Error(res.status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function download(format, hash, token, ...files) {
|
export function download(format, hash, token, ...files) {
|
||||||
let url = `${baseURL}/api/public/dl/${hash}`
|
let url = `${baseURL}/api/public/dl/${hash}`;
|
||||||
|
|
||||||
if (files.length === 1) {
|
if (files.length === 1) {
|
||||||
url += encodeURIComponent(files[0]) + '?'
|
url += encodeURIComponent(files[0]) + "?";
|
||||||
} else {
|
} else {
|
||||||
let arg = ''
|
let arg = "";
|
||||||
|
|
||||||
for (let file of files) {
|
for (let file of files) {
|
||||||
arg += encodeURIComponent(file) + ','
|
arg += encodeURIComponent(file) + ",";
|
||||||
}
|
}
|
||||||
|
|
||||||
arg = arg.substring(0, arg.length - 1)
|
arg = arg.substring(0, arg.length - 1);
|
||||||
arg = encodeURIComponent(arg)
|
arg = encodeURIComponent(arg);
|
||||||
url += `/?files=${arg}&`
|
url += `/?files=${arg}&`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format) {
|
if (format) {
|
||||||
url += `algo=${format}&`
|
url += `algo=${format}&`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (token) {
|
if (token) {
|
||||||
url += `token=${token}&`
|
url += `token=${token}&`;
|
||||||
}
|
}
|
||||||
|
|
||||||
window.open(url)
|
window.open(url);
|
||||||
}
|
}
|
|
@ -1,31 +1,31 @@
|
||||||
import { fetchURL, removePrefix } from './utils'
|
import { fetchURL, removePrefix } from "./utils";
|
||||||
import url from '../utils/url'
|
import url from "../utils/url";
|
||||||
|
|
||||||
export default async function search (base, query) {
|
export default async function search(base, query) {
|
||||||
base = removePrefix(base)
|
base = removePrefix(base);
|
||||||
query = encodeURIComponent(query)
|
query = encodeURIComponent(query);
|
||||||
|
|
||||||
if (!base.endsWith('/')) {
|
if (!base.endsWith("/")) {
|
||||||
base += '/'
|
base += "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = await fetchURL(`/api/search${base}?query=${query}`, {})
|
let res = await fetchURL(`/api/search${base}?query=${query}`, {});
|
||||||
|
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
let data = await res.json()
|
let data = await res.json();
|
||||||
|
|
||||||
data = data.map((item) => {
|
data = data.map((item) => {
|
||||||
item.url = `/files${base}` + url.encodePath(item.path)
|
item.url = `/files${base}` + url.encodePath(item.path);
|
||||||
|
|
||||||
if (item.dir) {
|
if (item.dir) {
|
||||||
item.url += '/'
|
item.url += "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
return item
|
return item;
|
||||||
})
|
});
|
||||||
|
|
||||||
return data
|
return data;
|
||||||
} else {
|
} else {
|
||||||
throw Error(res.status)
|
throw Error(res.status);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,16 +1,16 @@
|
||||||
import { fetchURL, fetchJSON } from './utils'
|
import { fetchURL, fetchJSON } from "./utils";
|
||||||
|
|
||||||
export function get () {
|
export function get() {
|
||||||
return fetchJSON(`/api/settings`, {})
|
return fetchJSON(`/api/settings`, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function update (settings) {
|
export async function update(settings) {
|
||||||
const res = await fetchURL(`/api/settings`, {
|
const res = await fetchURL(`/api/settings`, {
|
||||||
method: 'PUT',
|
method: "PUT",
|
||||||
body: JSON.stringify(settings)
|
body: JSON.stringify(settings),
|
||||||
})
|
});
|
||||||
|
|
||||||
if (res.status !== 200) {
|
if (res.status !== 200) {
|
||||||
throw new Error(res.status)
|
throw new Error(res.status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,36 +1,36 @@
|
||||||
import { fetchURL, fetchJSON, removePrefix } from './utils'
|
import { fetchURL, fetchJSON, removePrefix } from "./utils";
|
||||||
|
|
||||||
export async function list() {
|
export async function list() {
|
||||||
return fetchJSON('/api/shares')
|
return fetchJSON("/api/shares");
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function get(url) {
|
export async function get(url) {
|
||||||
url = removePrefix(url)
|
url = removePrefix(url);
|
||||||
return fetchJSON(`/api/share${url}`)
|
return fetchJSON(`/api/share${url}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function remove(hash) {
|
export async function remove(hash) {
|
||||||
const res = await fetchURL(`/api/share/${hash}`, {
|
const res = await fetchURL(`/api/share/${hash}`, {
|
||||||
method: 'DELETE'
|
method: "DELETE",
|
||||||
})
|
});
|
||||||
|
|
||||||
if (res.status !== 200) {
|
if (res.status !== 200) {
|
||||||
throw new Error(res.status)
|
throw new Error(res.status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function create(url, password = '', expires = '', unit = 'hours') {
|
export async function create(url, password = "", expires = "", unit = "hours") {
|
||||||
url = removePrefix(url)
|
url = removePrefix(url);
|
||||||
url = `/api/share${url}`
|
url = `/api/share${url}`;
|
||||||
if (expires !== '') {
|
if (expires !== "") {
|
||||||
url += `?expires=${expires}&unit=${unit}`
|
url += `?expires=${expires}&unit=${unit}`;
|
||||||
}
|
}
|
||||||
let body = '{}';
|
let body = "{}";
|
||||||
if (password != '' || expires !== '' || unit !== 'hours') {
|
if (password != "" || expires !== "" || unit !== "hours") {
|
||||||
body = JSON.stringify({password: password, expires: expires, unit: unit})
|
body = JSON.stringify({ password: password, expires: expires, unit: unit });
|
||||||
}
|
}
|
||||||
return fetchJSON(url, {
|
return fetchJSON(url, {
|
||||||
method: 'POST',
|
method: "POST",
|
||||||
body: body,
|
body: body,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,52 +1,51 @@
|
||||||
import { fetchURL, fetchJSON } from './utils'
|
import { fetchURL, fetchJSON } from "./utils";
|
||||||
|
|
||||||
export async function getAll () {
|
export async function getAll() {
|
||||||
return fetchJSON(`/api/users`, {})
|
return fetchJSON(`/api/users`, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function get (id) {
|
export async function get(id) {
|
||||||
return fetchJSON(`/api/users/${id}`, {})
|
return fetchJSON(`/api/users/${id}`, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function create (user) {
|
export async function create(user) {
|
||||||
const res = await fetchURL(`/api/users`, {
|
const res = await fetchURL(`/api/users`, {
|
||||||
method: 'POST',
|
method: "POST",
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
what: 'user',
|
what: "user",
|
||||||
which: [],
|
which: [],
|
||||||
data: user
|
data: user,
|
||||||
})
|
}),
|
||||||
})
|
});
|
||||||
|
|
||||||
if (res.status === 201) {
|
if (res.status === 201) {
|
||||||
return res.headers.get('Location')
|
return res.headers.get("Location");
|
||||||
} else {
|
} else {
|
||||||
throw new Error(res.status)
|
throw new Error(res.status);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function update (user, which = ['all']) {
|
export async function update(user, which = ["all"]) {
|
||||||
const res = await fetchURL(`/api/users/${user.id}`, {
|
const res = await fetchURL(`/api/users/${user.id}`, {
|
||||||
method: 'PUT',
|
method: "PUT",
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
what: 'user',
|
what: "user",
|
||||||
which: which,
|
which: which,
|
||||||
data: user
|
data: user,
|
||||||
})
|
}),
|
||||||
})
|
});
|
||||||
|
|
||||||
if (res.status !== 200) {
|
if (res.status !== 200) {
|
||||||
throw new Error(res.status)
|
throw new Error(res.status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function remove (id) {
|
export async function remove(id) {
|
||||||
const res = await fetchURL(`/api/users/${id}`, {
|
const res = await fetchURL(`/api/users/${id}`, {
|
||||||
method: 'DELETE'
|
method: "DELETE",
|
||||||
})
|
});
|
||||||
|
|
||||||
if (res.status !== 200) {
|
if (res.status !== 200) {
|
||||||
throw new Error(res.status)
|
throw new Error(res.status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,43 +1,42 @@
|
||||||
import store from '@/store'
|
import store from "@/store";
|
||||||
import { renew } from '@/utils/auth'
|
import { renew } from "@/utils/auth";
|
||||||
import { baseURL } from '@/utils/constants'
|
import { baseURL } from "@/utils/constants";
|
||||||
|
|
||||||
export async function fetchURL (url, opts) {
|
export async function fetchURL(url, opts) {
|
||||||
opts = opts || {}
|
opts = opts || {};
|
||||||
opts.headers = opts.headers || {}
|
opts.headers = opts.headers || {};
|
||||||
|
|
||||||
let { headers, ...rest } = opts
|
let { headers, ...rest } = opts;
|
||||||
|
|
||||||
const res = await fetch(`${baseURL}${url}`, {
|
const res = await fetch(`${baseURL}${url}`, {
|
||||||
headers: {
|
headers: {
|
||||||
'X-Auth': store.state.jwt,
|
"X-Auth": store.state.jwt,
|
||||||
...headers
|
...headers,
|
||||||
},
|
},
|
||||||
...rest
|
...rest,
|
||||||
})
|
});
|
||||||
|
|
||||||
if (res.headers.get('X-Renew-Token') === 'true') {
|
if (res.headers.get("X-Renew-Token") === "true") {
|
||||||
await renew(store.state.jwt)
|
await renew(store.state.jwt);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchJSON (url, opts) {
|
export async function fetchJSON(url, opts) {
|
||||||
const res = await fetchURL(url, opts)
|
const res = await fetchURL(url, opts);
|
||||||
|
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
return res.json()
|
return res.json();
|
||||||
} else {
|
} else {
|
||||||
throw new Error(res.status)
|
throw new Error(res.status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function removePrefix (url) {
|
export function removePrefix(url) {
|
||||||
url = url.split('/').splice(2).join('/')
|
url = url.split("/").splice(2).join("/");
|
||||||
|
|
||||||
if (url === '') url = '/'
|
if (url === "") url = "/";
|
||||||
if (url[0] !== '/') url = '/' + url
|
if (url[0] !== "/") url = "/" + url;
|
||||||
return url
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,18 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="breadcrumbs">
|
<div class="breadcrumbs">
|
||||||
<component :is="element" :to="base || ''" :aria-label="$t('files.home')" :title="$t('files.home')">
|
<component
|
||||||
|
:is="element"
|
||||||
|
:to="base || ''"
|
||||||
|
:aria-label="$t('files.home')"
|
||||||
|
:title="$t('files.home')"
|
||||||
|
>
|
||||||
<i class="material-icons">home</i>
|
<i class="material-icons">home</i>
|
||||||
</component>
|
</component>
|
||||||
|
|
||||||
<span v-for="(link, index) in items" :key="index">
|
<span v-for="(link, index) in items" :key="index">
|
||||||
<span class="chevron"><i class="material-icons">keyboard_arrow_right</i></span>
|
<span class="chevron"
|
||||||
|
><i class="material-icons">keyboard_arrow_right</i></span
|
||||||
|
>
|
||||||
<component :is="element" :to="link.url">{{ link.name }}</component>
|
<component :is="element" :to="link.url">{{ link.name }}</component>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -13,55 +20,56 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'breadcrumbs',
|
name: "breadcrumbs",
|
||||||
props: [
|
props: ["base", "noLink"],
|
||||||
'base',
|
|
||||||
'noLink'
|
|
||||||
],
|
|
||||||
computed: {
|
computed: {
|
||||||
items () {
|
items() {
|
||||||
const relativePath = this.$route.path.replace(this.base, '')
|
const relativePath = this.$route.path.replace(this.base, "");
|
||||||
let parts = relativePath.split('/')
|
let parts = relativePath.split("/");
|
||||||
|
|
||||||
if (parts[0] === '') {
|
if (parts[0] === "") {
|
||||||
parts.shift()
|
parts.shift();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parts[parts.length - 1] === '') {
|
if (parts[parts.length - 1] === "") {
|
||||||
parts.pop()
|
parts.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
let breadcrumbs = []
|
let breadcrumbs = [];
|
||||||
|
|
||||||
for (let i = 0; i < parts.length; i++) {
|
for (let i = 0; i < parts.length; i++) {
|
||||||
if (i === 0) {
|
if (i === 0) {
|
||||||
breadcrumbs.push({ name: decodeURIComponent(parts[i]), url: this.base + '/' + parts[i] + '/' })
|
breadcrumbs.push({
|
||||||
} else {
|
name: decodeURIComponent(parts[i]),
|
||||||
breadcrumbs.push({ name: decodeURIComponent(parts[i]), url: breadcrumbs[i - 1].url + parts[i] + '/' })
|
url: this.base + "/" + parts[i] + "/",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
breadcrumbs.push({
|
||||||
|
name: decodeURIComponent(parts[i]),
|
||||||
|
url: breadcrumbs[i - 1].url + parts[i] + "/",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (breadcrumbs.length > 3) {
|
if (breadcrumbs.length > 3) {
|
||||||
while (breadcrumbs.length !== 4) {
|
while (breadcrumbs.length !== 4) {
|
||||||
breadcrumbs.shift()
|
breadcrumbs.shift();
|
||||||
}
|
}
|
||||||
|
|
||||||
breadcrumbs[0].name = '...'
|
breadcrumbs[0].name = "...";
|
||||||
}
|
}
|
||||||
|
|
||||||
return breadcrumbs
|
return breadcrumbs;
|
||||||
},
|
},
|
||||||
element () {
|
element() {
|
||||||
if (this.noLink !== undefined) {
|
if (this.noLink !== undefined) {
|
||||||
return 'span'
|
return "span";
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'router-link'
|
return "router-link";
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style></style>
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div id="search" @click="open" v-bind:class="{ active , ongoing }">
|
<div id="search" @click="open" v-bind:class="{ active, ongoing }">
|
||||||
<div id="input">
|
<div id="input">
|
||||||
<button
|
<button
|
||||||
v-if="active"
|
v-if="active"
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
v-model.trim="value"
|
v-model.trim="value"
|
||||||
:aria-label="$t('search.search')"
|
:aria-label="$t('search.search')"
|
||||||
:placeholder="$t('search.search')"
|
:placeholder="$t('search.search')"
|
||||||
>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="result" ref="result">
|
<div id="result" ref="result">
|
||||||
|
@ -30,25 +30,25 @@
|
||||||
|
|
||||||
<template v-if="value.length === 0">
|
<template v-if="value.length === 0">
|
||||||
<div class="boxes">
|
<div class="boxes">
|
||||||
<h3>{{ $t('search.types') }}</h3>
|
<h3>{{ $t("search.types") }}</h3>
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
v-for="(v,k) in boxes"
|
v-for="(v, k) in boxes"
|
||||||
:key="k"
|
:key="k"
|
||||||
role="button"
|
role="button"
|
||||||
@click="init('type:'+k)"
|
@click="init('type:' + k)"
|
||||||
:aria-label="$t('search.'+v.label)"
|
:aria-label="$t('search.' + v.label)"
|
||||||
>
|
>
|
||||||
<i class="material-icons">{{v.icon}}</i>
|
<i class="material-icons">{{ v.icon }}</i>
|
||||||
<p>{{ $t('search.'+v.label) }}</p>
|
<p>{{ $t("search." + v.label) }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
<ul v-show="results.length > 0">
|
<ul v-show="results.length > 0">
|
||||||
<li v-for="(s,k) in filteredResults" :key="k">
|
<li v-for="(s, k) in filteredResults" :key="k">
|
||||||
<router-link @click.native="close" :to="s.url">
|
<router-link @click.native="close" :to="s.url">
|
||||||
<i v-if="s.dir" class="material-icons">folder</i>
|
<i v-if="s.dir" class="material-icons">folder</i>
|
||||||
<i v-else class="material-icons">insert_drive_file</i>
|
<i v-else class="material-icons">insert_drive_file</i>
|
||||||
|
@ -65,20 +65,20 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState, mapGetters, mapMutations } from "vuex"
|
import { mapState, mapGetters, mapMutations } from "vuex";
|
||||||
import url from "@/utils/url"
|
import url from "@/utils/url";
|
||||||
import { search } from "@/api"
|
import { search } from "@/api";
|
||||||
|
|
||||||
var boxes = {
|
var boxes = {
|
||||||
image: { label: "images", icon: "insert_photo" },
|
image: { label: "images", icon: "insert_photo" },
|
||||||
audio: { label: "music", icon: "volume_up" },
|
audio: { label: "music", icon: "volume_up" },
|
||||||
video: { label: "video", icon: "movie" },
|
video: { label: "video", icon: "movie" },
|
||||||
pdf: { label: "pdf", icon: "picture_as_pdf" }
|
pdf: { label: "pdf", icon: "picture_as_pdf" },
|
||||||
}
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "search",
|
name: "search",
|
||||||
data: function() {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
value: "",
|
value: "",
|
||||||
active: false,
|
active: false,
|
||||||
|
@ -86,111 +86,116 @@ export default {
|
||||||
results: [],
|
results: [],
|
||||||
reload: false,
|
reload: false,
|
||||||
resultsCount: 50,
|
resultsCount: 50,
|
||||||
scrollable: null
|
scrollable: null,
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
show (val, old) {
|
show(val, old) {
|
||||||
this.active = val === "search"
|
this.active = val === "search";
|
||||||
|
|
||||||
if (old === "search" && !this.active) {
|
if (old === "search" && !this.active) {
|
||||||
if (this.reload) {
|
if (this.reload) {
|
||||||
this.setReload(true)
|
this.setReload(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
document.body.style.overflow = "auto"
|
document.body.style.overflow = "auto";
|
||||||
this.reset()
|
this.reset();
|
||||||
this.value = ''
|
this.value = "";
|
||||||
this.active = false
|
this.active = false;
|
||||||
this.$refs.input.blur()
|
this.$refs.input.blur();
|
||||||
} else if (this.active) {
|
} else if (this.active) {
|
||||||
this.reload = false
|
this.reload = false;
|
||||||
this.$refs.input.focus()
|
this.$refs.input.focus();
|
||||||
document.body.style.overflow = "hidden"
|
document.body.style.overflow = "hidden";
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
value () {
|
value() {
|
||||||
if (this.results.length) {
|
if (this.results.length) {
|
||||||
this.reset()
|
this.reset();
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(["user", "show"]),
|
...mapState(["user", "show"]),
|
||||||
...mapGetters(["isListing"]),
|
...mapGetters(["isListing"]),
|
||||||
boxes() {
|
boxes() {
|
||||||
return boxes
|
return boxes;
|
||||||
},
|
},
|
||||||
isEmpty() {
|
isEmpty() {
|
||||||
return this.results.length === 0
|
return this.results.length === 0;
|
||||||
},
|
},
|
||||||
text() {
|
text() {
|
||||||
if (this.ongoing) {
|
if (this.ongoing) {
|
||||||
return ""
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.value === '' ? this.$t("search.typeToSearch") : this.$t("search.pressToSearch")
|
return this.value === ""
|
||||||
|
? this.$t("search.typeToSearch")
|
||||||
|
: this.$t("search.pressToSearch");
|
||||||
|
},
|
||||||
|
filteredResults() {
|
||||||
|
return this.results.slice(0, this.resultsCount);
|
||||||
},
|
},
|
||||||
filteredResults () {
|
|
||||||
return this.results.slice(0, this.resultsCount)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.$refs.result.addEventListener('scroll', event => {
|
this.$refs.result.addEventListener("scroll", (event) => {
|
||||||
if (event.target.offsetHeight + event.target.scrollTop >= event.target.scrollHeight - 100) {
|
if (
|
||||||
this.resultsCount += 50
|
event.target.offsetHeight + event.target.scrollTop >=
|
||||||
|
event.target.scrollHeight - 100
|
||||||
|
) {
|
||||||
|
this.resultsCount += 50;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapMutations(["showHover", "closeHovers", "setReload"]),
|
...mapMutations(["showHover", "closeHovers", "setReload"]),
|
||||||
open() {
|
open() {
|
||||||
this.showHover("search")
|
this.showHover("search");
|
||||||
},
|
},
|
||||||
close(event) {
|
close(event) {
|
||||||
event.stopPropagation()
|
event.stopPropagation();
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
this.closeHovers()
|
this.closeHovers();
|
||||||
},
|
},
|
||||||
keyup(event) {
|
keyup(event) {
|
||||||
if (event.keyCode === 27) {
|
if (event.keyCode === 27) {
|
||||||
this.close(event)
|
this.close(event);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.results.length = 0
|
this.results.length = 0;
|
||||||
},
|
},
|
||||||
init (string) {
|
init(string) {
|
||||||
this.value = `${string} `
|
this.value = `${string} `;
|
||||||
this.$refs.input.focus()
|
this.$refs.input.focus();
|
||||||
},
|
},
|
||||||
reset () {
|
reset() {
|
||||||
this.ongoing = false
|
this.ongoing = false;
|
||||||
this.resultsCount = 50
|
this.resultsCount = 50;
|
||||||
this.results = []
|
this.results = [];
|
||||||
},
|
},
|
||||||
async submit(event) {
|
async submit(event) {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
|
|
||||||
if (this.value === '') {
|
if (this.value === "") {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let path = this.$route.path
|
let path = this.$route.path;
|
||||||
if (!this.isListing) {
|
if (!this.isListing) {
|
||||||
path = url.removeLastDir(path) + "/"
|
path = url.removeLastDir(path) + "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
this.ongoing = true
|
this.ongoing = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.results = await search(path, this.value)
|
this.results = await search(path, this.value);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.$showError(error)
|
this.$showError(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.ongoing = false
|
this.ongoing = false;
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,12 +1,21 @@
|
||||||
<template>
|
<template>
|
||||||
<div @click="focus" class="shell" ref="scrollable" :class="{ ['shell--hidden']: !showShell}">
|
<div
|
||||||
<div v-for="(c, index) in content" :key="index" class="shell__result" >
|
@click="focus"
|
||||||
<div class="shell__prompt"><i class="material-icons">chevron_right</i></div>
|
class="shell"
|
||||||
|
ref="scrollable"
|
||||||
|
:class="{ ['shell--hidden']: !showShell }"
|
||||||
|
>
|
||||||
|
<div v-for="(c, index) in content" :key="index" class="shell__result">
|
||||||
|
<div class="shell__prompt">
|
||||||
|
<i class="material-icons">chevron_right</i>
|
||||||
|
</div>
|
||||||
<pre class="shell__text">{{ c.text }}</pre>
|
<pre class="shell__text">{{ c.text }}</pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="shell__result" :class="{ 'shell__result--hidden': !canInput }" >
|
<div class="shell__result" :class="{ 'shell__result--hidden': !canInput }">
|
||||||
<div class="shell__prompt"><i class="material-icons">chevron_right</i></div>
|
<div class="shell__prompt">
|
||||||
|
<i class="material-icons">chevron_right</i>
|
||||||
|
</div>
|
||||||
<pre
|
<pre
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
ref="input"
|
ref="input"
|
||||||
|
@ -14,102 +23,103 @@
|
||||||
contenteditable="true"
|
contenteditable="true"
|
||||||
@keydown.prevent.38="historyUp"
|
@keydown.prevent.38="historyUp"
|
||||||
@keydown.prevent.40="historyDown"
|
@keydown.prevent.40="historyDown"
|
||||||
@keypress.prevent.enter="submit" />
|
@keypress.prevent.enter="submit"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapMutations, mapState, mapGetters } from 'vuex'
|
import { mapMutations, mapState, mapGetters } from "vuex";
|
||||||
import { commands } from '@/api'
|
import { commands } from "@/api";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'shell',
|
name: "shell",
|
||||||
computed: {
|
computed: {
|
||||||
...mapState([ 'user', 'showShell' ]),
|
...mapState(["user", "showShell"]),
|
||||||
...mapGetters([ 'isFiles', 'isLogged' ]),
|
...mapGetters(["isFiles", "isLogged"]),
|
||||||
path: function () {
|
path: function () {
|
||||||
if (this.isFiles) {
|
if (this.isFiles) {
|
||||||
return this.$route.path
|
return this.$route.path;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ''
|
return "";
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
data: () => ({
|
data: () => ({
|
||||||
content: [],
|
content: [],
|
||||||
history: [],
|
history: [],
|
||||||
historyPos: 0,
|
historyPos: 0,
|
||||||
canInput: true
|
canInput: true,
|
||||||
}),
|
}),
|
||||||
methods: {
|
methods: {
|
||||||
...mapMutations([ 'toggleShell' ]),
|
...mapMutations(["toggleShell"]),
|
||||||
scroll: function () {
|
scroll: function () {
|
||||||
this.$refs.scrollable.scrollTop = this.$refs.scrollable.scrollHeight
|
this.$refs.scrollable.scrollTop = this.$refs.scrollable.scrollHeight;
|
||||||
},
|
},
|
||||||
focus: function () {
|
focus: function () {
|
||||||
this.$refs.input.focus()
|
this.$refs.input.focus();
|
||||||
},
|
},
|
||||||
historyUp () {
|
historyUp() {
|
||||||
if (this.historyPos > 0) {
|
if (this.historyPos > 0) {
|
||||||
this.$refs.input.innerText = this.history[--this.historyPos]
|
this.$refs.input.innerText = this.history[--this.historyPos];
|
||||||
this.focus()
|
this.focus();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
historyDown () {
|
historyDown() {
|
||||||
if (this.historyPos >= 0 && this.historyPos < this.history.length - 1) {
|
if (this.historyPos >= 0 && this.historyPos < this.history.length - 1) {
|
||||||
this.$refs.input.innerText = this.history[++this.historyPos]
|
this.$refs.input.innerText = this.history[++this.historyPos];
|
||||||
this.focus()
|
this.focus();
|
||||||
} else {
|
} else {
|
||||||
this.historyPos = this.history.length
|
this.historyPos = this.history.length;
|
||||||
this.$refs.input.innerText = ''
|
this.$refs.input.innerText = "";
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
submit: function (event) {
|
submit: function (event) {
|
||||||
const cmd = event.target.innerText.trim()
|
const cmd = event.target.innerText.trim();
|
||||||
|
|
||||||
if (cmd === '') {
|
if (cmd === "") {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmd === 'clear') {
|
if (cmd === "clear") {
|
||||||
this.content = []
|
this.content = [];
|
||||||
event.target.innerHTML = ''
|
event.target.innerHTML = "";
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmd === 'exit') {
|
if (cmd === "exit") {
|
||||||
event.target.innerHTML = ''
|
event.target.innerHTML = "";
|
||||||
this.toggleShell()
|
this.toggleShell();
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.canInput = false
|
this.canInput = false;
|
||||||
event.target.innerHTML = ''
|
event.target.innerHTML = "";
|
||||||
|
|
||||||
let results = {
|
let results = {
|
||||||
text: `${cmd}\n\n`
|
text: `${cmd}\n\n`,
|
||||||
}
|
};
|
||||||
|
|
||||||
this.history.push(cmd)
|
this.history.push(cmd);
|
||||||
this.historyPos = this.history.length
|
this.historyPos = this.history.length;
|
||||||
this.content.push(results)
|
this.content.push(results);
|
||||||
|
|
||||||
commands(
|
commands(
|
||||||
this.path,
|
this.path,
|
||||||
cmd,
|
cmd,
|
||||||
event => {
|
(event) => {
|
||||||
results.text += `${event.data}\n`
|
results.text += `${event.data}\n`;
|
||||||
this.scroll()
|
this.scroll();
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
results.text = results.text.trimEnd()
|
results.text = results.text.trimEnd();
|
||||||
this.canInput = true
|
this.canInput = true;
|
||||||
this.$refs.input.focus()
|
this.$refs.input.focus();
|
||||||
this.scroll()
|
this.scroll();
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,82 +1,134 @@
|
||||||
<template>
|
<template>
|
||||||
<nav :class="{active}">
|
<nav :class="{ active }">
|
||||||
<template v-if="isLogged">
|
<template v-if="isLogged">
|
||||||
<router-link class="action" to="/files/" :aria-label="$t('sidebar.myFiles')" :title="$t('sidebar.myFiles')">
|
<router-link
|
||||||
|
class="action"
|
||||||
|
to="/files/"
|
||||||
|
:aria-label="$t('sidebar.myFiles')"
|
||||||
|
:title="$t('sidebar.myFiles')"
|
||||||
|
>
|
||||||
<i class="material-icons">folder</i>
|
<i class="material-icons">folder</i>
|
||||||
<span>{{ $t('sidebar.myFiles') }}</span>
|
<span>{{ $t("sidebar.myFiles") }}</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<div v-if="user.perm.create">
|
<div v-if="user.perm.create">
|
||||||
<button @click="$store.commit('showHover', 'newDir')" class="action" :aria-label="$t('sidebar.newFolder')" :title="$t('sidebar.newFolder')">
|
<button
|
||||||
|
@click="$store.commit('showHover', 'newDir')"
|
||||||
|
class="action"
|
||||||
|
:aria-label="$t('sidebar.newFolder')"
|
||||||
|
:title="$t('sidebar.newFolder')"
|
||||||
|
>
|
||||||
<i class="material-icons">create_new_folder</i>
|
<i class="material-icons">create_new_folder</i>
|
||||||
<span>{{ $t('sidebar.newFolder') }}</span>
|
<span>{{ $t("sidebar.newFolder") }}</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button @click="$store.commit('showHover', 'newFile')" class="action" :aria-label="$t('sidebar.newFile')" :title="$t('sidebar.newFile')">
|
<button
|
||||||
|
@click="$store.commit('showHover', 'newFile')"
|
||||||
|
class="action"
|
||||||
|
:aria-label="$t('sidebar.newFile')"
|
||||||
|
:title="$t('sidebar.newFile')"
|
||||||
|
>
|
||||||
<i class="material-icons">note_add</i>
|
<i class="material-icons">note_add</i>
|
||||||
<span>{{ $t('sidebar.newFile') }}</span>
|
<span>{{ $t("sidebar.newFile") }}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<router-link class="action" to="/settings" :aria-label="$t('sidebar.settings')" :title="$t('sidebar.settings')">
|
<router-link
|
||||||
|
class="action"
|
||||||
|
to="/settings"
|
||||||
|
:aria-label="$t('sidebar.settings')"
|
||||||
|
:title="$t('sidebar.settings')"
|
||||||
|
>
|
||||||
<i class="material-icons">settings_applications</i>
|
<i class="material-icons">settings_applications</i>
|
||||||
<span>{{ $t('sidebar.settings') }}</span>
|
<span>{{ $t("sidebar.settings") }}</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<button v-if="authMethod == 'json'" @click="logout" class="action" id="logout" :aria-label="$t('sidebar.logout')" :title="$t('sidebar.logout')">
|
<button
|
||||||
|
v-if="authMethod == 'json'"
|
||||||
|
@click="logout"
|
||||||
|
class="action"
|
||||||
|
id="logout"
|
||||||
|
:aria-label="$t('sidebar.logout')"
|
||||||
|
:title="$t('sidebar.logout')"
|
||||||
|
>
|
||||||
<i class="material-icons">exit_to_app</i>
|
<i class="material-icons">exit_to_app</i>
|
||||||
<span>{{ $t('sidebar.logout') }}</span>
|
<span>{{ $t("sidebar.logout") }}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<router-link class="action" to="/login" :aria-label="$t('sidebar.login')" :title="$t('sidebar.login')">
|
<router-link
|
||||||
|
class="action"
|
||||||
|
to="/login"
|
||||||
|
:aria-label="$t('sidebar.login')"
|
||||||
|
:title="$t('sidebar.login')"
|
||||||
|
>
|
||||||
<i class="material-icons">exit_to_app</i>
|
<i class="material-icons">exit_to_app</i>
|
||||||
<span>{{ $t('sidebar.login') }}</span>
|
<span>{{ $t("sidebar.login") }}</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<router-link v-if="signup" class="action" to="/login" :aria-label="$t('sidebar.signup')" :title="$t('sidebar.signup')">
|
<router-link
|
||||||
|
v-if="signup"
|
||||||
|
class="action"
|
||||||
|
to="/login"
|
||||||
|
:aria-label="$t('sidebar.signup')"
|
||||||
|
:title="$t('sidebar.signup')"
|
||||||
|
>
|
||||||
<i class="material-icons">person_add</i>
|
<i class="material-icons">person_add</i>
|
||||||
<span>{{ $t('sidebar.signup') }}</span>
|
<span>{{ $t("sidebar.signup") }}</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<p class="credits">
|
<p class="credits">
|
||||||
<span>
|
<span>
|
||||||
<span v-if="disableExternal">File Browser</span>
|
<span v-if="disableExternal">File Browser</span>
|
||||||
<a v-else rel="noopener noreferrer" target="_blank" href="https://github.com/filebrowser/filebrowser">File Browser</a>
|
<a
|
||||||
|
v-else
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
href="https://github.com/filebrowser/filebrowser"
|
||||||
|
>File Browser</a
|
||||||
|
>
|
||||||
<span> {{ version }}</span>
|
<span> {{ version }}</span>
|
||||||
</span>
|
</span>
|
||||||
<span><a @click="help">{{ $t('sidebar.help') }}</a></span>
|
<span
|
||||||
|
><a @click="help">{{ $t("sidebar.help") }}</a></span
|
||||||
|
>
|
||||||
</p>
|
</p>
|
||||||
</nav>
|
</nav>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState, mapGetters } from 'vuex'
|
import { mapState, mapGetters } from "vuex";
|
||||||
import * as auth from '@/utils/auth'
|
import * as auth from "@/utils/auth";
|
||||||
import { version, signup, disableExternal, noAuth, authMethod } from '@/utils/constants'
|
import {
|
||||||
|
version,
|
||||||
|
signup,
|
||||||
|
disableExternal,
|
||||||
|
noAuth,
|
||||||
|
authMethod,
|
||||||
|
} from "@/utils/constants";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'sidebar',
|
name: "sidebar",
|
||||||
computed: {
|
computed: {
|
||||||
...mapState([ 'user' ]),
|
...mapState(["user"]),
|
||||||
...mapGetters([ 'isLogged' ]),
|
...mapGetters(["isLogged"]),
|
||||||
active () {
|
active() {
|
||||||
return this.$store.state.show === 'sidebar'
|
return this.$store.state.show === "sidebar";
|
||||||
},
|
},
|
||||||
signup: () => signup,
|
signup: () => signup,
|
||||||
version: () => version,
|
version: () => version,
|
||||||
disableExternal: () => disableExternal,
|
disableExternal: () => disableExternal,
|
||||||
noAuth: () => noAuth,
|
noAuth: () => noAuth,
|
||||||
authMethod: () => authMethod
|
authMethod: () => authMethod,
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
help () {
|
help() {
|
||||||
this.$store.commit('showHover', 'help')
|
this.$store.commit("showHover", "help");
|
||||||
},
|
},
|
||||||
logout: auth.logout
|
logout: auth.logout,
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -10,40 +10,45 @@
|
||||||
@mouseup="mouseUp"
|
@mouseup="mouseUp"
|
||||||
@wheel="wheelMove"
|
@wheel="wheelMove"
|
||||||
>
|
>
|
||||||
<img src="" class="image-ex-img image-ex-img-center" ref="imgex" @load="onLoad">
|
<img
|
||||||
|
src=""
|
||||||
|
class="image-ex-img image-ex-img-center"
|
||||||
|
ref="imgex"
|
||||||
|
@load="onLoad"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import throttle from 'lodash.throttle'
|
import throttle from "lodash.throttle";
|
||||||
import UTIF from 'utif'
|
import UTIF from "utif";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
src: String,
|
src: String,
|
||||||
moveDisabledTime: {
|
moveDisabledTime: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: () => 200
|
default: () => 200,
|
||||||
},
|
},
|
||||||
maxScale: {
|
maxScale: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: () => 4
|
default: () => 4,
|
||||||
},
|
},
|
||||||
minScale: {
|
minScale: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: () => 0.25
|
default: () => 0.25,
|
||||||
},
|
},
|
||||||
classList: {
|
classList: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => []
|
default: () => [],
|
||||||
},
|
},
|
||||||
zoomStep: {
|
zoomStep: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: () => 0.25
|
default: () => 0.25,
|
||||||
},
|
},
|
||||||
autofill: {
|
autofill: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: () => false
|
default: () => false,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -57,204 +62,208 @@ export default {
|
||||||
imageLoaded: false,
|
imageLoaded: false,
|
||||||
position: {
|
position: {
|
||||||
center: { x: 0, y: 0 },
|
center: { x: 0, y: 0 },
|
||||||
relative: { x: 0, y: 0 }
|
relative: { x: 0, y: 0 },
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
if (!this.decodeUTIF()) {
|
if (!this.decodeUTIF()) {
|
||||||
this.$refs.imgex.src = this.src
|
this.$refs.imgex.src = this.src;
|
||||||
}
|
}
|
||||||
let container = this.$refs.container
|
let container = this.$refs.container;
|
||||||
this.classList.forEach(className => container.classList.add(className))
|
this.classList.forEach((className) => container.classList.add(className));
|
||||||
// set width and height if they are zero
|
// set width and height if they are zero
|
||||||
if (getComputedStyle(container).width === "0px") {
|
if (getComputedStyle(container).width === "0px") {
|
||||||
container.style.width = "100%"
|
container.style.width = "100%";
|
||||||
}
|
}
|
||||||
if (getComputedStyle(container).height === "0px") {
|
if (getComputedStyle(container).height === "0px") {
|
||||||
container.style.height = "100%"
|
container.style.height = "100%";
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('resize', this.onResize)
|
window.addEventListener("resize", this.onResize);
|
||||||
},
|
},
|
||||||
beforeDestroy () {
|
beforeDestroy() {
|
||||||
window.removeEventListener('resize', this.onResize)
|
window.removeEventListener("resize", this.onResize);
|
||||||
document.removeEventListener('mouseup', this.onMouseUp)
|
document.removeEventListener("mouseup", this.onMouseUp);
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
src: function () {
|
src: function () {
|
||||||
this.scale = 1
|
this.scale = 1;
|
||||||
this.setZoom()
|
this.setZoom();
|
||||||
this.setCenter()
|
this.setCenter();
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// Modified from UTIF.replaceIMG
|
// Modified from UTIF.replaceIMG
|
||||||
decodeUTIF() {
|
decodeUTIF() {
|
||||||
const sufs = ["tif", "tiff", "dng", "cr2", "nef"]
|
const sufs = ["tif", "tiff", "dng", "cr2", "nef"];
|
||||||
let suff = document.location.pathname.split(".").pop().toLowerCase()
|
let suff = document.location.pathname.split(".").pop().toLowerCase();
|
||||||
if (sufs.indexOf(suff) == -1) return false
|
if (sufs.indexOf(suff) == -1) return false;
|
||||||
let xhr = new XMLHttpRequest()
|
let xhr = new XMLHttpRequest();
|
||||||
UTIF._xhrs.push(xhr)
|
UTIF._xhrs.push(xhr);
|
||||||
UTIF._imgs.push(this.$refs.imgex)
|
UTIF._imgs.push(this.$refs.imgex);
|
||||||
xhr.open("GET", this.src)
|
xhr.open("GET", this.src);
|
||||||
xhr.responseType = "arraybuffer"
|
xhr.responseType = "arraybuffer";
|
||||||
xhr.onload = UTIF._imgLoaded
|
xhr.onload = UTIF._imgLoaded;
|
||||||
xhr.send()
|
xhr.send();
|
||||||
return true
|
return true;
|
||||||
},
|
},
|
||||||
onLoad() {
|
onLoad() {
|
||||||
let img = this.$refs.imgex
|
let img = this.$refs.imgex;
|
||||||
|
|
||||||
this.imageLoaded = true
|
this.imageLoaded = true;
|
||||||
|
|
||||||
if (img === undefined) {
|
if (img === undefined) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
img.classList.remove('image-ex-img-center')
|
img.classList.remove("image-ex-img-center");
|
||||||
this.setCenter()
|
this.setCenter();
|
||||||
img.classList.add('image-ex-img-ready')
|
img.classList.add("image-ex-img-ready");
|
||||||
|
|
||||||
document.addEventListener('mouseup', this.onMouseUp)
|
document.addEventListener("mouseup", this.onMouseUp);
|
||||||
},
|
},
|
||||||
onMouseUp() {
|
onMouseUp() {
|
||||||
this.inDrag = false
|
this.inDrag = false;
|
||||||
},
|
},
|
||||||
onResize: throttle(function() {
|
onResize: throttle(function () {
|
||||||
if (this.imageLoaded) {
|
if (this.imageLoaded) {
|
||||||
this.setCenter()
|
this.setCenter();
|
||||||
this.doMove(this.position.relative.x, this.position.relative.y)
|
this.doMove(this.position.relative.x, this.position.relative.y);
|
||||||
}
|
}
|
||||||
}, 100),
|
}, 100),
|
||||||
setCenter() {
|
setCenter() {
|
||||||
let container = this.$refs.container
|
let container = this.$refs.container;
|
||||||
let img = this.$refs.imgex
|
let img = this.$refs.imgex;
|
||||||
|
|
||||||
this.position.center.x = Math.floor((container.clientWidth - img.clientWidth) / 2)
|
this.position.center.x = Math.floor(
|
||||||
this.position.center.y = Math.floor((container.clientHeight - img.clientHeight) / 2)
|
(container.clientWidth - img.clientWidth) / 2
|
||||||
|
);
|
||||||
|
this.position.center.y = Math.floor(
|
||||||
|
(container.clientHeight - img.clientHeight) / 2
|
||||||
|
);
|
||||||
|
|
||||||
img.style.left = this.position.center.x + 'px'
|
img.style.left = this.position.center.x + "px";
|
||||||
img.style.top = this.position.center.y + 'px'
|
img.style.top = this.position.center.y + "px";
|
||||||
},
|
},
|
||||||
mousedownStart(event) {
|
mousedownStart(event) {
|
||||||
this.lastX = null
|
this.lastX = null;
|
||||||
this.lastY = null
|
this.lastY = null;
|
||||||
this.inDrag = true
|
this.inDrag = true;
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
},
|
},
|
||||||
mouseMove(event) {
|
mouseMove(event) {
|
||||||
if (!this.inDrag) return
|
if (!this.inDrag) return;
|
||||||
this.doMove(event.movementX, event.movementY)
|
this.doMove(event.movementX, event.movementY);
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
},
|
},
|
||||||
mouseUp(event) {
|
mouseUp(event) {
|
||||||
this.inDrag = false
|
this.inDrag = false;
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
},
|
},
|
||||||
touchStart(event) {
|
touchStart(event) {
|
||||||
this.lastX = null
|
this.lastX = null;
|
||||||
this.lastY = null
|
this.lastY = null;
|
||||||
this.lastTouchDistance = null
|
this.lastTouchDistance = null;
|
||||||
if (event.targetTouches.length < 2) {
|
if (event.targetTouches.length < 2) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.touches = 0
|
this.touches = 0;
|
||||||
}, 300)
|
}, 300);
|
||||||
this.touches++
|
this.touches++;
|
||||||
if (this.touches > 1) {
|
if (this.touches > 1) {
|
||||||
this.zoomAuto(event)
|
this.zoomAuto(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
},
|
},
|
||||||
zoomAuto(event) {
|
zoomAuto(event) {
|
||||||
switch (this.scale) {
|
switch (this.scale) {
|
||||||
case 1:
|
case 1:
|
||||||
this.scale = 2
|
this.scale = 2;
|
||||||
break
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
this.scale = 4
|
this.scale = 4;
|
||||||
break
|
break;
|
||||||
default:
|
default:
|
||||||
case 4:
|
case 4:
|
||||||
this.scale = 1
|
this.scale = 1;
|
||||||
this.setCenter()
|
this.setCenter();
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
this.setZoom()
|
this.setZoom();
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
},
|
},
|
||||||
touchMove(event) {
|
touchMove(event) {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
if (this.lastX === null) {
|
if (this.lastX === null) {
|
||||||
this.lastX = event.targetTouches[0].pageX
|
this.lastX = event.targetTouches[0].pageX;
|
||||||
this.lastY = event.targetTouches[0].pageY
|
this.lastY = event.targetTouches[0].pageY;
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
let step = this.$refs.imgex.width / 5
|
let step = this.$refs.imgex.width / 5;
|
||||||
if (event.targetTouches.length === 2) {
|
if (event.targetTouches.length === 2) {
|
||||||
this.moveDisabled = true
|
this.moveDisabled = true;
|
||||||
clearTimeout(this.disabledTimer)
|
clearTimeout(this.disabledTimer);
|
||||||
this.disabledTimer = setTimeout(
|
this.disabledTimer = setTimeout(
|
||||||
() => (this.moveDisabled = false),
|
() => (this.moveDisabled = false),
|
||||||
this.moveDisabledTime
|
this.moveDisabledTime
|
||||||
)
|
);
|
||||||
|
|
||||||
let p1 = event.targetTouches[0]
|
let p1 = event.targetTouches[0];
|
||||||
let p2 = event.targetTouches[1]
|
let p2 = event.targetTouches[1];
|
||||||
let touchDistance = Math.sqrt(
|
let touchDistance = Math.sqrt(
|
||||||
Math.pow(p2.pageX - p1.pageX, 2) + Math.pow(p2.pageY - p1.pageY, 2)
|
Math.pow(p2.pageX - p1.pageX, 2) + Math.pow(p2.pageY - p1.pageY, 2)
|
||||||
)
|
);
|
||||||
if (!this.lastTouchDistance) {
|
if (!this.lastTouchDistance) {
|
||||||
this.lastTouchDistance = touchDistance
|
this.lastTouchDistance = touchDistance;
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
this.scale += (touchDistance - this.lastTouchDistance) / step
|
this.scale += (touchDistance - this.lastTouchDistance) / step;
|
||||||
this.lastTouchDistance = touchDistance
|
this.lastTouchDistance = touchDistance;
|
||||||
this.setZoom()
|
this.setZoom();
|
||||||
} else if (event.targetTouches.length === 1) {
|
} else if (event.targetTouches.length === 1) {
|
||||||
if (this.moveDisabled) return
|
if (this.moveDisabled) return;
|
||||||
let x = event.targetTouches[0].pageX - this.lastX
|
let x = event.targetTouches[0].pageX - this.lastX;
|
||||||
let y = event.targetTouches[0].pageY - this.lastY
|
let y = event.targetTouches[0].pageY - this.lastY;
|
||||||
if (Math.abs(x) >= step && Math.abs(y) >= step) return
|
if (Math.abs(x) >= step && Math.abs(y) >= step) return;
|
||||||
this.lastX = event.targetTouches[0].pageX
|
this.lastX = event.targetTouches[0].pageX;
|
||||||
this.lastY = event.targetTouches[0].pageY
|
this.lastY = event.targetTouches[0].pageY;
|
||||||
this.doMove(x, y)
|
this.doMove(x, y);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
doMove(x, y) {
|
doMove(x, y) {
|
||||||
let style = this.$refs.imgex.style
|
let style = this.$refs.imgex.style;
|
||||||
let posX = this.pxStringToNumber(style.left) + x
|
let posX = this.pxStringToNumber(style.left) + x;
|
||||||
let posY = this.pxStringToNumber(style.top) + y
|
let posY = this.pxStringToNumber(style.top) + y;
|
||||||
|
|
||||||
style.left = posX + 'px'
|
style.left = posX + "px";
|
||||||
style.top = posY + 'px'
|
style.top = posY + "px";
|
||||||
|
|
||||||
this.position.relative.x = Math.abs(this.position.center.x - posX)
|
this.position.relative.x = Math.abs(this.position.center.x - posX);
|
||||||
this.position.relative.y = Math.abs(this.position.center.y - posY)
|
this.position.relative.y = Math.abs(this.position.center.y - posY);
|
||||||
|
|
||||||
if (posX < this.position.center.x) {
|
if (posX < this.position.center.x) {
|
||||||
this.position.relative.x = this.position.relative.x * -1
|
this.position.relative.x = this.position.relative.x * -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (posY < this.position.center.y) {
|
if (posY < this.position.center.y) {
|
||||||
this.position.relative.y = this.position.relative.y * -1
|
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;
|
||||||
this.setZoom()
|
this.setZoom();
|
||||||
},
|
},
|
||||||
setZoom() {
|
setZoom() {
|
||||||
this.scale = this.scale < this.minScale ? this.minScale : this.scale
|
this.scale = this.scale < this.minScale ? this.minScale : this.scale;
|
||||||
this.scale = this.scale > this.maxScale ? this.maxScale : this.scale
|
this.scale = this.scale > this.maxScale ? this.maxScale : this.scale;
|
||||||
this.$refs.imgex.style.transform = `scale(${this.scale})`
|
this.$refs.imgex.style.transform = `scale(${this.scale})`;
|
||||||
},
|
},
|
||||||
pxStringToNumber(style) {
|
pxStringToNumber(style) {
|
||||||
return +style.replace("px", "")
|
return +style.replace("px", "");
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
.image-ex-container {
|
.image-ex-container {
|
||||||
|
|
|
@ -1,19 +1,24 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="item"
|
<div
|
||||||
role="button"
|
class="item"
|
||||||
tabindex="0"
|
role="button"
|
||||||
:draggable="isDraggable"
|
tabindex="0"
|
||||||
@dragstart="dragStart"
|
:draggable="isDraggable"
|
||||||
@dragover="dragOver"
|
@dragstart="dragStart"
|
||||||
@drop="drop"
|
@dragover="dragOver"
|
||||||
@click="itemClick"
|
@drop="drop"
|
||||||
@dblclick="dblclick"
|
@click="itemClick"
|
||||||
@touchstart="touchstart"
|
@dblclick="dblclick"
|
||||||
:data-dir="isDir"
|
@touchstart="touchstart"
|
||||||
:aria-label="name"
|
:data-dir="isDir"
|
||||||
:aria-selected="isSelected">
|
:aria-label="name"
|
||||||
|
:aria-selected="isSelected"
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<img v-if="readOnly == undefined && type==='image' && isThumbsEnabled" v-lazy="thumbnailUrl">
|
<img
|
||||||
|
v-if="readOnly == undefined && type === 'image' && isThumbsEnabled"
|
||||||
|
v-lazy="thumbnailUrl"
|
||||||
|
/>
|
||||||
<i v-else class="material-icons">{{ icon }}</i>
|
<i v-else class="material-icons">{{ icon }}</i>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -31,203 +36,221 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { baseURL, enableThumbs } from '@/utils/constants'
|
import { baseURL, enableThumbs } from "@/utils/constants";
|
||||||
import { mapMutations, mapGetters, mapState } from 'vuex'
|
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'
|
import * as upload from "@/utils/upload";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'item',
|
name: "item",
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
touches: 0
|
touches: 0,
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
props: ['name', 'isDir', 'url', 'type', 'size', 'modified', 'index', 'readOnly'],
|
props: [
|
||||||
|
"name",
|
||||||
|
"isDir",
|
||||||
|
"url",
|
||||||
|
"type",
|
||||||
|
"size",
|
||||||
|
"modified",
|
||||||
|
"index",
|
||||||
|
"readOnly",
|
||||||
|
],
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['user', 'selected', 'req', 'jwt']),
|
...mapState(["user", "selected", "req", "jwt"]),
|
||||||
...mapGetters(['selectedCount']),
|
...mapGetters(["selectedCount"]),
|
||||||
singleClick () {
|
singleClick() {
|
||||||
return this.readOnly == undefined && this.user.singleClick
|
return this.readOnly == undefined && this.user.singleClick;
|
||||||
},
|
},
|
||||||
isSelected () {
|
isSelected() {
|
||||||
return (this.selected.indexOf(this.index) !== -1)
|
return this.selected.indexOf(this.index) !== -1;
|
||||||
},
|
},
|
||||||
icon () {
|
icon() {
|
||||||
if (this.isDir) return 'folder'
|
if (this.isDir) return "folder";
|
||||||
if (this.type === 'image') return 'insert_photo'
|
if (this.type === "image") return "insert_photo";
|
||||||
if (this.type === 'audio') return 'volume_up'
|
if (this.type === "audio") return "volume_up";
|
||||||
if (this.type === 'video') return 'movie'
|
if (this.type === "video") return "movie";
|
||||||
return 'insert_drive_file'
|
return "insert_drive_file";
|
||||||
},
|
},
|
||||||
isDraggable () {
|
isDraggable() {
|
||||||
return this.readOnly == undefined && this.user.perm.rename
|
return this.readOnly == undefined && this.user.perm.rename;
|
||||||
},
|
},
|
||||||
canDrop () {
|
canDrop() {
|
||||||
if (!this.isDir || this.readOnly !== undefined) return false
|
if (!this.isDir || this.readOnly !== undefined) return false;
|
||||||
|
|
||||||
for (let i of this.selected) {
|
for (let i of this.selected) {
|
||||||
if (this.req.items[i].url === this.url) {
|
if (this.req.items[i].url === this.url) {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true;
|
||||||
},
|
},
|
||||||
thumbnailUrl () {
|
thumbnailUrl() {
|
||||||
const path = this.url.replace(/^\/files\//, '')
|
const path = this.url.replace(/^\/files\//, "");
|
||||||
|
|
||||||
// reload the image when the file is replaced
|
// reload the image when the file is replaced
|
||||||
const key = Date.parse(this.modified)
|
const key = Date.parse(this.modified);
|
||||||
|
|
||||||
return `${baseURL}/api/preview/thumb/${path}?auth=${this.jwt}&inline=true&k=${key}`
|
return `${baseURL}/api/preview/thumb/${path}?auth=${this.jwt}&inline=true&k=${key}`;
|
||||||
|
},
|
||||||
|
isThumbsEnabled() {
|
||||||
|
return enableThumbs;
|
||||||
},
|
},
|
||||||
isThumbsEnabled () {
|
|
||||||
return enableThumbs
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapMutations(['addSelected', 'removeSelected', 'resetSelected']),
|
...mapMutations(["addSelected", "removeSelected", "resetSelected"]),
|
||||||
humanSize: function () {
|
humanSize: function () {
|
||||||
return filesize(this.size)
|
return filesize(this.size);
|
||||||
},
|
},
|
||||||
humanTime: function () {
|
humanTime: function () {
|
||||||
return moment(this.modified).fromNow()
|
return moment(this.modified).fromNow();
|
||||||
},
|
},
|
||||||
dragStart: function () {
|
dragStart: function () {
|
||||||
if (this.selectedCount === 0) {
|
if (this.selectedCount === 0) {
|
||||||
this.addSelected(this.index)
|
this.addSelected(this.index);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.isSelected) {
|
if (!this.isSelected) {
|
||||||
this.resetSelected()
|
this.resetSelected();
|
||||||
this.addSelected(this.index)
|
this.addSelected(this.index);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
dragOver: function (event) {
|
dragOver: function (event) {
|
||||||
if (!this.canDrop) return
|
if (!this.canDrop) return;
|
||||||
|
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
let el = event.target
|
let el = event.target;
|
||||||
|
|
||||||
for (let i = 0; i < 5; i++) {
|
for (let i = 0; i < 5; i++) {
|
||||||
if (!el.classList.contains('item')) {
|
if (!el.classList.contains("item")) {
|
||||||
el = el.parentElement
|
el = el.parentElement;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
el.style.opacity = 1
|
el.style.opacity = 1;
|
||||||
},
|
},
|
||||||
drop: async 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
|
let el = event.target;
|
||||||
for (let i = 0; i < 5; i++) {
|
for (let i = 0; i < 5; i++) {
|
||||||
if (el !== null && !el.classList.contains('item')) {
|
if (el !== null && !el.classList.contains("item")) {
|
||||||
el = el.parentElement
|
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
|
name: this.req.items[i].name,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let base = el.querySelector('.name').innerHTML + '/'
|
let base = el.querySelector(".name").innerHTML + "/";
|
||||||
let path = this.$route.path + base
|
let path = this.$route.path + base;
|
||||||
let baseItems = (await api.fetch(path)).items
|
let baseItems = (await api.fetch(path)).items;
|
||||||
|
|
||||||
let action = (overwrite, rename) => {
|
let action = (overwrite, rename) => {
|
||||||
api.move(items, overwrite, rename).then(() => {
|
api
|
||||||
this.$store.commit('setReload', true)
|
.move(items, overwrite, rename)
|
||||||
}).catch(this.$showError)
|
.then(() => {
|
||||||
}
|
this.$store.commit("setReload", true);
|
||||||
|
})
|
||||||
|
.catch(this.$showError);
|
||||||
|
};
|
||||||
|
|
||||||
let conflict = upload.checkConflict(items, baseItems)
|
let conflict = upload.checkConflict(items, baseItems);
|
||||||
|
|
||||||
let overwrite = false
|
let overwrite = false;
|
||||||
let rename = false
|
let rename = false;
|
||||||
|
|
||||||
if (conflict) {
|
if (conflict) {
|
||||||
this.$store.commit('showHover', {
|
this.$store.commit("showHover", {
|
||||||
prompt: 'replace-rename',
|
prompt: "replace-rename",
|
||||||
confirm: (event, option) => {
|
confirm: (event, option) => {
|
||||||
overwrite = option == 'overwrite'
|
overwrite = option == "overwrite";
|
||||||
rename = option == 'rename'
|
rename = option == "rename";
|
||||||
|
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
this.$store.commit('closeHovers')
|
this.$store.commit("closeHovers");
|
||||||
action(overwrite, rename)
|
action(overwrite, rename);
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
action(overwrite, rename)
|
action(overwrite, rename);
|
||||||
},
|
},
|
||||||
itemClick: function(event) {
|
itemClick: function (event) {
|
||||||
if (this.singleClick && !this.$store.state.multiple) this.open()
|
if (this.singleClick && !this.$store.state.multiple) this.open();
|
||||||
else this.click(event)
|
else this.click(event);
|
||||||
},
|
},
|
||||||
click: function (event) {
|
click: function (event) {
|
||||||
if (!this.singleClick && this.selectedCount !== 0) event.preventDefault()
|
if (!this.singleClick && this.selectedCount !== 0) event.preventDefault();
|
||||||
if (this.$store.state.selected.indexOf(this.index) !== -1) {
|
if (this.$store.state.selected.indexOf(this.index) !== -1) {
|
||||||
this.removeSelected(this.index)
|
this.removeSelected(this.index);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.shiftKey && this.selected.length > 0) {
|
if (event.shiftKey && this.selected.length > 0) {
|
||||||
let fi = 0
|
let fi = 0;
|
||||||
let la = 0
|
let la = 0;
|
||||||
|
|
||||||
if (this.index > this.selected[0]) {
|
if (this.index > this.selected[0]) {
|
||||||
fi = this.selected[0] + 1
|
fi = this.selected[0] + 1;
|
||||||
la = this.index
|
la = this.index;
|
||||||
} else {
|
} else {
|
||||||
fi = this.index
|
fi = this.index;
|
||||||
la = this.selected[0] - 1
|
la = this.selected[0] - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; fi <= la; fi++) {
|
for (; fi <= la; fi++) {
|
||||||
if (this.$store.state.selected.indexOf(fi) == -1) {
|
if (this.$store.state.selected.indexOf(fi) == -1) {
|
||||||
this.addSelected(fi)
|
this.addSelected(fi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.singleClick && !event.ctrlKey && !event.metaKey && !this.$store.state.multiple) this.resetSelected()
|
if (
|
||||||
this.addSelected(this.index)
|
!this.singleClick &&
|
||||||
|
!event.ctrlKey &&
|
||||||
|
!event.metaKey &&
|
||||||
|
!this.$store.state.multiple
|
||||||
|
)
|
||||||
|
this.resetSelected();
|
||||||
|
this.addSelected(this.index);
|
||||||
},
|
},
|
||||||
dblclick: function () {
|
dblclick: function () {
|
||||||
if (!this.singleClick) this.open()
|
if (!this.singleClick) this.open();
|
||||||
},
|
},
|
||||||
touchstart () {
|
touchstart() {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.touches = 0
|
this.touches = 0;
|
||||||
}, 300)
|
}, 300);
|
||||||
|
|
||||||
this.touches++
|
this.touches++;
|
||||||
if (this.touches > 1) {
|
if (this.touches > 1) {
|
||||||
this.open()
|
this.open();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
open: function () {
|
open: function () {
|
||||||
this.$router.push({path: this.url})
|
this.$router.push({ path: this.url });
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<button @click="action" :aria-label="label" :title="label" class="action">
|
<button @click="action" :aria-label="label" :title="label" class="action">
|
||||||
<i class="material-icons">{{ icon }}</i>
|
<i class="material-icons">{{ icon }}</i>
|
||||||
<span>{{ label }}</span>
|
<span>{{ label }}</span>
|
||||||
<span v-if="counter > 0" class="counter">{{ counter }}</span>
|
<span v-if="counter > 0" class="counter">{{ counter }}</span>
|
||||||
|
@ -8,25 +8,18 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'action',
|
name: "action",
|
||||||
props: [
|
props: ["icon", "label", "counter", "show"],
|
||||||
'icon',
|
|
||||||
'label',
|
|
||||||
'counter',
|
|
||||||
'show'
|
|
||||||
],
|
|
||||||
methods: {
|
methods: {
|
||||||
action: function () {
|
action: function () {
|
||||||
if (this.show) {
|
if (this.show) {
|
||||||
this.$store.commit('showHover', this.show)
|
this.$store.commit("showHover", this.show);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$emit('action')
|
this.$emit("action");
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style></style>
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<header>
|
<header>
|
||||||
<img v-if="showLogo !== undefined" :src="logoURL" />
|
<img v-if="showLogo !== undefined" :src="logoURL" />
|
||||||
<action v-if="showMenu !== undefined" class="menu-button" icon="menu" :label="$t('buttons.toggleSidebar')" @action="openSidebar()" />
|
<action
|
||||||
|
v-if="showMenu !== undefined"
|
||||||
|
class="menu-button"
|
||||||
|
icon="menu"
|
||||||
|
:label="$t('buttons.toggleSidebar')"
|
||||||
|
@action="openSidebar()"
|
||||||
|
/>
|
||||||
|
|
||||||
<slot />
|
<slot />
|
||||||
|
|
||||||
|
@ -9,39 +15,44 @@
|
||||||
<slot name="actions" />
|
<slot name="actions" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<action v-if="this.$slots.actions" id="more" icon="more_vert" :label="$t('buttons.more')" @action="$store.commit('showHover', 'more')" />
|
<action
|
||||||
|
v-if="this.$slots.actions"
|
||||||
|
id="more"
|
||||||
|
icon="more_vert"
|
||||||
|
:label="$t('buttons.more')"
|
||||||
|
@action="$store.commit('showHover', 'more')"
|
||||||
|
/>
|
||||||
|
|
||||||
<div class="overlay" v-show="this.$store.state.show == 'more'" @click="$store.commit('closeHovers')" />
|
<div
|
||||||
|
class="overlay"
|
||||||
|
v-show="this.$store.state.show == 'more'"
|
||||||
|
@click="$store.commit('closeHovers')"
|
||||||
|
/>
|
||||||
</header>
|
</header>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { logoURL } from '@/utils/constants'
|
import { logoURL } from "@/utils/constants";
|
||||||
|
|
||||||
import Action from '@/components/header/Action'
|
import Action from "@/components/header/Action";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'header-bar',
|
name: "header-bar",
|
||||||
props: [
|
props: ["showLogo", "showMenu"],
|
||||||
'showLogo',
|
|
||||||
'showMenu',
|
|
||||||
],
|
|
||||||
components: {
|
components: {
|
||||||
Action
|
Action,
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
logoURL
|
logoURL,
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
openSidebar () {
|
openSidebar() {
|
||||||
this.$store.commit('showHover', 'sidebar')
|
this.$store.commit("showHover", "sidebar");
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style></style>
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -1,108 +1,119 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="card floating">
|
<div class="card floating">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
<h2>{{ $t('prompts.copy') }}</h2>
|
<h2>{{ $t("prompts.copy") }}</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<p>{{ $t('prompts.copyMessage') }}</p>
|
<p>{{ $t("prompts.copyMessage") }}</p>
|
||||||
<file-list @update:selected="val => dest = val"></file-list>
|
<file-list @update:selected="(val) => (dest = val)"></file-list>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-action">
|
<div class="card-action">
|
||||||
<button class="button button--flat button--grey"
|
<button
|
||||||
|
class="button button--flat button--grey"
|
||||||
@click="$store.commit('closeHovers')"
|
@click="$store.commit('closeHovers')"
|
||||||
:aria-label="$t('buttons.cancel')"
|
:aria-label="$t('buttons.cancel')"
|
||||||
:title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
|
:title="$t('buttons.cancel')"
|
||||||
<button class="button button--flat"
|
>
|
||||||
|
{{ $t("buttons.cancel") }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="button button--flat"
|
||||||
@click="copy"
|
@click="copy"
|
||||||
: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>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState } from 'vuex'
|
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'
|
import * as upload from "@/utils/upload";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'copy',
|
name: "copy",
|
||||||
components: { FileList },
|
components: { FileList },
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
current: window.location.pathname,
|
current: window.location.pathname,
|
||||||
dest: null
|
dest: null,
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
computed: mapState(['req', 'selected']),
|
computed: mapState(["req", "selected"]),
|
||||||
methods: {
|
methods: {
|
||||||
copy: async function (event) {
|
copy: async function (event) {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
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
|
name: this.req.items[item].name,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let action = async (overwrite, rename) => {
|
let action = async (overwrite, rename) => {
|
||||||
buttons.loading('copy')
|
buttons.loading("copy");
|
||||||
|
|
||||||
await api.copy(items, overwrite, rename).then(() => {
|
await api
|
||||||
buttons.success('copy')
|
.copy(items, overwrite, rename)
|
||||||
|
.then(() => {
|
||||||
|
buttons.success("copy");
|
||||||
|
|
||||||
if (this.$route.path === this.dest) {
|
if (this.$route.path === this.dest) {
|
||||||
this.$store.commit('setReload', true)
|
this.$store.commit("setReload", true);
|
||||||
|
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$router.push({ path: this.dest })
|
this.$router.push({ path: this.dest });
|
||||||
}).catch((e) => {
|
})
|
||||||
buttons.done('copy')
|
.catch((e) => {
|
||||||
this.$showError(e)
|
buttons.done("copy");
|
||||||
})
|
this.$showError(e);
|
||||||
}
|
});
|
||||||
|
};
|
||||||
|
|
||||||
if (this.$route.path === this.dest) {
|
if (this.$route.path === this.dest) {
|
||||||
this.$store.commit('closeHovers')
|
this.$store.commit("closeHovers");
|
||||||
action(false, true)
|
action(false, true);
|
||||||
|
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let dstItems = (await api.fetch(this.dest)).items
|
let dstItems = (await api.fetch(this.dest)).items;
|
||||||
let conflict = upload.checkConflict(items, dstItems)
|
let conflict = upload.checkConflict(items, dstItems);
|
||||||
|
|
||||||
let overwrite = false
|
let overwrite = false;
|
||||||
let rename = false
|
let rename = false;
|
||||||
|
|
||||||
if (conflict) {
|
if (conflict) {
|
||||||
this.$store.commit('showHover', {
|
this.$store.commit("showHover", {
|
||||||
prompt: 'replace-rename',
|
prompt: "replace-rename",
|
||||||
confirm: (event, option) => {
|
confirm: (event, option) => {
|
||||||
overwrite = option == 'overwrite'
|
overwrite = option == "overwrite";
|
||||||
rename = option == 'rename'
|
rename = option == "rename";
|
||||||
|
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
this.$store.commit('closeHovers')
|
this.$store.commit("closeHovers");
|
||||||
action(overwrite, rename)
|
action(overwrite, rename);
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
action(overwrite, rename)
|
action(overwrite, rename);
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,68 +1,80 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="card floating">
|
<div class="card floating">
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<p v-if="req.kind !== 'listing'">{{ $t('prompts.deleteMessageSingle') }}</p>
|
<p v-if="req.kind !== 'listing'">
|
||||||
<p v-else>{{ $t('prompts.deleteMessageMultiple', { count: selectedCount}) }}</p>
|
{{ $t("prompts.deleteMessageSingle") }}
|
||||||
|
</p>
|
||||||
|
<p v-else>
|
||||||
|
{{ $t("prompts.deleteMessageMultiple", { count: selectedCount }) }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-action">
|
<div class="card-action">
|
||||||
<button @click="$store.commit('closeHovers')"
|
<button
|
||||||
|
@click="$store.commit('closeHovers')"
|
||||||
class="button button--flat button--grey"
|
class="button button--flat button--grey"
|
||||||
:aria-label="$t('buttons.cancel')"
|
:aria-label="$t('buttons.cancel')"
|
||||||
:title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
|
:title="$t('buttons.cancel')"
|
||||||
<button @click="submit"
|
>
|
||||||
|
{{ $t("buttons.cancel") }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
@click="submit"
|
||||||
class="button button--flat button--red"
|
class="button button--flat button--red"
|
||||||
:aria-label="$t('buttons.delete')"
|
:aria-label="$t('buttons.delete')"
|
||||||
:title="$t('buttons.delete')">{{ $t('buttons.delete') }}</button>
|
:title="$t('buttons.delete')"
|
||||||
|
>
|
||||||
|
{{ $t("buttons.delete") }}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {mapGetters, mapMutations, mapState} from 'vuex'
|
import { mapGetters, mapMutations, mapState } from "vuex";
|
||||||
import { files as api } from '@/api'
|
import { files as api } from "@/api";
|
||||||
import buttons from '@/utils/buttons'
|
import buttons from "@/utils/buttons";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'delete',
|
name: "delete",
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters(['isListing', 'selectedCount']),
|
...mapGetters(["isListing", "selectedCount"]),
|
||||||
...mapState(['req', 'selected', 'showConfirm'])
|
...mapState(["req", "selected", "showConfirm"]),
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapMutations(['closeHovers']),
|
...mapMutations(["closeHovers"]),
|
||||||
submit: async function () {
|
submit: async function () {
|
||||||
buttons.loading('delete')
|
buttons.loading("delete");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!this.isListing) {
|
if (!this.isListing) {
|
||||||
await api.remove(this.$route.path)
|
await api.remove(this.$route.path);
|
||||||
buttons.success('delete')
|
buttons.success("delete");
|
||||||
|
|
||||||
this.showConfirm()
|
this.showConfirm();
|
||||||
this.closeHovers()
|
this.closeHovers();
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.closeHovers()
|
this.closeHovers();
|
||||||
|
|
||||||
if (this.selectedCount === 0) {
|
if (this.selectedCount === 0) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let promises = []
|
let promises = [];
|
||||||
for (let index of this.selected) {
|
for (let index of this.selected) {
|
||||||
promises.push(api.remove(this.req.items[index].url))
|
promises.push(api.remove(this.req.items[index].url));
|
||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all(promises)
|
await Promise.all(promises);
|
||||||
buttons.success('delete')
|
buttons.success("delete");
|
||||||
this.$store.commit('setReload', true)
|
this.$store.commit("setReload", true);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
buttons.done('delete')
|
buttons.done("delete");
|
||||||
this.$showError(e)
|
this.$showError(e);
|
||||||
if (this.isListing) this.$store.commit('setReload', true)
|
if (this.isListing) this.$store.commit("setReload", true);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,35 +1,43 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="card floating" id="download">
|
<div class="card floating" id="download">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
<h2>{{ $t('prompts.download') }}</h2>
|
<h2>{{ $t("prompts.download") }}</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<p>{{ $t('prompts.downloadMessage') }}</p>
|
<p>{{ $t("prompts.downloadMessage") }}</p>
|
||||||
|
|
||||||
<button v-for="(ext, format) in formats" :key="format" class="button button--block" @click="showConfirm(format)" v-focus>{{ ext }}</button>
|
<button
|
||||||
|
v-for="(ext, format) in formats"
|
||||||
|
:key="format"
|
||||||
|
class="button button--block"
|
||||||
|
@click="showConfirm(format)"
|
||||||
|
v-focus
|
||||||
|
>
|
||||||
|
{{ ext }}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from "vuex";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'download',
|
name: "download",
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
formats: {
|
formats: {
|
||||||
zip: 'zip',
|
zip: "zip",
|
||||||
tar: 'tar',
|
tar: "tar",
|
||||||
targz: 'tar.gz',
|
targz: "tar.gz",
|
||||||
tarbz2: 'tar.bz2',
|
tarbz2: "tar.bz2",
|
||||||
tarxz: 'tar.xz',
|
tarxz: "tar.xz",
|
||||||
tarlz4: 'tar.lz4',
|
tarlz4: "tar.lz4",
|
||||||
tarsz: 'tar.sz'
|
tarsz: "tar.sz",
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
computed: mapState(['showConfirm'])
|
computed: mapState(["showConfirm"]),
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,132 +1,138 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<ul class="file-list">
|
<ul class="file-list">
|
||||||
<li @click="itemClick"
|
<li
|
||||||
|
@click="itemClick"
|
||||||
@touchstart="touchstart"
|
@touchstart="touchstart"
|
||||||
@dblclick="next"
|
@dblclick="next"
|
||||||
role="button"
|
role="button"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
:aria-label="item.name"
|
:aria-label="item.name"
|
||||||
:aria-selected="selected == item.url"
|
:aria-selected="selected == item.url"
|
||||||
:key="item.name" v-for="item in items"
|
:key="item.name"
|
||||||
:data-url="item.url">{{ item.name }}</li>
|
v-for="item in items"
|
||||||
|
:data-url="item.url"
|
||||||
|
>
|
||||||
|
{{ item.name }}
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p>{{ $t('prompts.currentlyNavigating') }} <code>{{ nav }}</code>.</p>
|
<p>
|
||||||
|
{{ $t("prompts.currentlyNavigating") }} <code>{{ nav }}</code
|
||||||
|
>.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from "vuex";
|
||||||
import url from '@/utils/url'
|
import url from "@/utils/url";
|
||||||
import { files } from '@/api'
|
import { files } from "@/api";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'file-list',
|
name: "file-list",
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
items: [],
|
items: [],
|
||||||
touches: {
|
touches: {
|
||||||
id: '',
|
id: "",
|
||||||
count: 0
|
count: 0,
|
||||||
},
|
},
|
||||||
selected: null,
|
selected: null,
|
||||||
current: window.location.pathname
|
current: window.location.pathname,
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState([ 'req', 'user' ]),
|
...mapState(["req", "user"]),
|
||||||
nav () {
|
nav() {
|
||||||
return decodeURIComponent(this.current)
|
return decodeURIComponent(this.current);
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted() {
|
||||||
this.fillOptions(this.req)
|
this.fillOptions(this.req);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
fillOptions (req) {
|
fillOptions(req) {
|
||||||
// Sets the current path and resets
|
// Sets the current path and resets
|
||||||
// the current items.
|
// the current items.
|
||||||
this.current = req.url
|
this.current = req.url;
|
||||||
this.items = []
|
this.items = [];
|
||||||
|
|
||||||
this.$emit('update:selected', this.current)
|
this.$emit("update:selected", this.current);
|
||||||
|
|
||||||
// If the path isn't the root path,
|
// If the path isn't the root path,
|
||||||
// show a button to navigate to the previous
|
// show a button to navigate to the previous
|
||||||
// directory.
|
// directory.
|
||||||
if (req.url !== '/files/') {
|
if (req.url !== "/files/") {
|
||||||
this.items.push({
|
this.items.push({
|
||||||
name: '..',
|
name: "..",
|
||||||
url: url.removeLastDir(req.url) + '/'
|
url: url.removeLastDir(req.url) + "/",
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this folder is empty, finish here.
|
// If this folder is empty, finish here.
|
||||||
if (req.items === null) return
|
if (req.items === null) return;
|
||||||
|
|
||||||
// Otherwise we add every directory to the
|
// Otherwise we add every directory to the
|
||||||
// move options.
|
// move options.
|
||||||
for (let item of req.items) {
|
for (let item of req.items) {
|
||||||
if (!item.isDir) continue
|
if (!item.isDir) continue;
|
||||||
|
|
||||||
this.items.push({
|
this.items.push({
|
||||||
name: item.name,
|
name: item.name,
|
||||||
url: item.url
|
url: item.url,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
next: function (event) {
|
next: function (event) {
|
||||||
// Retrieves the URL of the directory the user
|
// Retrieves the URL of the directory the user
|
||||||
// just clicked in and fill the options with its
|
// just clicked in and fill the options with its
|
||||||
// content.
|
// content.
|
||||||
let uri = event.currentTarget.dataset.url
|
let uri = event.currentTarget.dataset.url;
|
||||||
|
|
||||||
files.fetch(uri)
|
files.fetch(uri).then(this.fillOptions).catch(this.$showError);
|
||||||
.then(this.fillOptions)
|
|
||||||
.catch(this.$showError)
|
|
||||||
},
|
},
|
||||||
touchstart (event) {
|
touchstart(event) {
|
||||||
let url = event.currentTarget.dataset.url
|
let url = event.currentTarget.dataset.url;
|
||||||
|
|
||||||
// In 300 milliseconds, we shall reset the count.
|
// In 300 milliseconds, we shall reset the count.
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.touches.count = 0
|
this.touches.count = 0;
|
||||||
}, 300)
|
}, 300);
|
||||||
|
|
||||||
// If the element the user is touching
|
// If the element the user is touching
|
||||||
// is different from the last one he touched,
|
// is different from the last one he touched,
|
||||||
// reset the count.
|
// reset the count.
|
||||||
if (this.touches.id !== url) {
|
if (this.touches.id !== url) {
|
||||||
this.touches.id = url
|
this.touches.id = url;
|
||||||
this.touches.count = 1
|
this.touches.count = 1;
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.touches.count++
|
this.touches.count++;
|
||||||
|
|
||||||
// If there is more than one touch already,
|
// If there is more than one touch already,
|
||||||
// open the next screen.
|
// open the next screen.
|
||||||
if (this.touches.count > 1) {
|
if (this.touches.count > 1) {
|
||||||
this.next(event)
|
this.next(event);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
itemClick: function (event) {
|
itemClick: function (event) {
|
||||||
if (this.user.singleClick) this.next(event)
|
if (this.user.singleClick) this.next(event);
|
||||||
else this.select(event)
|
else this.select(event);
|
||||||
},
|
},
|
||||||
select: function (event) {
|
select: function (event) {
|
||||||
// If the element is already selected, unselect it.
|
// If the element is already selected, unselect it.
|
||||||
if (this.selected === event.currentTarget.dataset.url) {
|
if (this.selected === event.currentTarget.dataset.url) {
|
||||||
this.selected = null
|
this.selected = null;
|
||||||
this.$emit('update:selected', this.current)
|
this.$emit("update:selected", this.current);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise select the element.
|
// Otherwise select the element.
|
||||||
this.selected = event.currentTarget.dataset.url
|
this.selected = event.currentTarget.dataset.url;
|
||||||
this.$emit('update:selected', this.selected)
|
this.$emit("update:selected", this.selected);
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,34 +1,37 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="card floating help">
|
<div class="card floating help">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
<h2>{{ $t('help.help') }}</h2>
|
<h2>{{ $t("help.help") }}</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<ul>
|
<ul>
|
||||||
<li><strong>F1</strong> - {{ $t('help.f1') }}</li>
|
<li><strong>F1</strong> - {{ $t("help.f1") }}</li>
|
||||||
<li><strong>F2</strong> - {{ $t('help.f2') }}</li>
|
<li><strong>F2</strong> - {{ $t("help.f2") }}</li>
|
||||||
<li><strong>DEL</strong> - {{ $t('help.del') }}</li>
|
<li><strong>DEL</strong> - {{ $t("help.del") }}</li>
|
||||||
<li><strong>ESC</strong> - {{ $t('help.esc') }}</li>
|
<li><strong>ESC</strong> - {{ $t("help.esc") }}</li>
|
||||||
<li><strong>CTRL + S</strong> - {{ $t('help.ctrl.s') }}</li>
|
<li><strong>CTRL + S</strong> - {{ $t("help.ctrl.s") }}</li>
|
||||||
<li><strong>CTRL + F</strong> - {{ $t('help.ctrl.f') }}</li>
|
<li><strong>CTRL + F</strong> - {{ $t("help.ctrl.f") }}</li>
|
||||||
<li><strong>CTRL + Click</strong> - {{ $t('help.ctrl.click') }}</li>
|
<li><strong>CTRL + Click</strong> - {{ $t("help.ctrl.click") }}</li>
|
||||||
<li><strong>Click</strong> - {{ $t('help.click') }}</li>
|
<li><strong>Click</strong> - {{ $t("help.click") }}</li>
|
||||||
<li><strong>Double click</strong> - {{ $t('help.doubleClick') }}</li>
|
<li><strong>Double click</strong> - {{ $t("help.doubleClick") }}</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-action">
|
<div class="card-action">
|
||||||
<button type="submit"
|
<button
|
||||||
|
type="submit"
|
||||||
@click="$store.commit('closeHovers')"
|
@click="$store.commit('closeHovers')"
|
||||||
class="button button--flat"
|
class="button button--flat"
|
||||||
:aria-label="$t('buttons.ok')"
|
:aria-label="$t('buttons.ok')"
|
||||||
:title="$t('buttons.ok')">{{ $t('buttons.ok') }}</button>
|
:title="$t('buttons.ok')"
|
||||||
|
>
|
||||||
|
{{ $t("buttons.ok") }}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default { name: 'help' }
|
export default { name: "help" };
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1,99 +1,149 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="card floating">
|
<div class="card floating">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
<h2>{{ $t('prompts.fileInfo') }}</h2>
|
<h2>{{ $t("prompts.fileInfo") }}</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<p v-if="selected.length > 1">{{ $t('prompts.filesSelected', { count: selected.length }) }}</p>
|
<p v-if="selected.length > 1">
|
||||||
|
{{ $t("prompts.filesSelected", { count: selected.length }) }}
|
||||||
|
</p>
|
||||||
|
|
||||||
<p class="break-word" v-if="selected.length < 2"><strong>{{ $t('prompts.displayName') }}</strong> {{ name }}</p>
|
<p class="break-word" v-if="selected.length < 2">
|
||||||
<p v-if="!dir || selected.length > 1"><strong>{{ $t('prompts.size') }}:</strong> <span id="content_length"></span> {{ humanSize }}</p>
|
<strong>{{ $t("prompts.displayName") }}</strong> {{ name }}
|
||||||
<p v-if="selected.length < 2"><strong>{{ $t('prompts.lastModified') }}:</strong> {{ humanTime }}</p>
|
</p>
|
||||||
|
<p v-if="!dir || selected.length > 1">
|
||||||
|
<strong>{{ $t("prompts.size") }}:</strong>
|
||||||
|
<span id="content_length"></span> {{ humanSize }}
|
||||||
|
</p>
|
||||||
|
<p v-if="selected.length < 2">
|
||||||
|
<strong>{{ $t("prompts.lastModified") }}:</strong> {{ humanTime }}
|
||||||
|
</p>
|
||||||
|
|
||||||
<template v-if="dir && selected.length === 0">
|
<template v-if="dir && selected.length === 0">
|
||||||
<p><strong>{{ $t('prompts.numberFiles') }}:</strong> {{ req.numFiles }}</p>
|
<p>
|
||||||
<p><strong>{{ $t('prompts.numberDirs') }}:</strong> {{ req.numDirs }}</p>
|
<strong>{{ $t("prompts.numberFiles") }}:</strong> {{ req.numFiles }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong>{{ $t("prompts.numberDirs") }}:</strong> {{ req.numDirs }}
|
||||||
|
</p>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-if="!dir">
|
<template v-if="!dir">
|
||||||
<p><strong>MD5: </strong><code><a @click="checksum($event, 'md5')">{{ $t('prompts.show') }}</a></code></p>
|
<p>
|
||||||
<p><strong>SHA1: </strong><code><a @click="checksum($event, 'sha1')">{{ $t('prompts.show') }}</a></code></p>
|
<strong>MD5: </strong
|
||||||
<p><strong>SHA256: </strong><code><a @click="checksum($event, 'sha256')">{{ $t('prompts.show') }}</a></code></p>
|
><code
|
||||||
<p><strong>SHA512: </strong><code><a @click="checksum($event, 'sha512')">{{ $t('prompts.show') }}</a></code></p>
|
><a @click="checksum($event, 'md5')">{{
|
||||||
|
$t("prompts.show")
|
||||||
|
}}</a></code
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong>SHA1: </strong
|
||||||
|
><code
|
||||||
|
><a @click="checksum($event, 'sha1')">{{
|
||||||
|
$t("prompts.show")
|
||||||
|
}}</a></code
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong>SHA256: </strong
|
||||||
|
><code
|
||||||
|
><a @click="checksum($event, 'sha256')">{{
|
||||||
|
$t("prompts.show")
|
||||||
|
}}</a></code
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong>SHA512: </strong
|
||||||
|
><code
|
||||||
|
><a @click="checksum($event, 'sha512')">{{
|
||||||
|
$t("prompts.show")
|
||||||
|
}}</a></code
|
||||||
|
>
|
||||||
|
</p>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-action">
|
<div class="card-action">
|
||||||
<button type="submit"
|
<button
|
||||||
|
type="submit"
|
||||||
@click="$store.commit('closeHovers')"
|
@click="$store.commit('closeHovers')"
|
||||||
class="button button--flat"
|
class="button button--flat"
|
||||||
:aria-label="$t('buttons.ok')"
|
:aria-label="$t('buttons.ok')"
|
||||||
:title="$t('buttons.ok')">{{ $t('buttons.ok') }}</button>
|
:title="$t('buttons.ok')"
|
||||||
|
>
|
||||||
|
{{ $t("buttons.ok") }}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {mapState, mapGetters} from 'vuex'
|
import { mapState, mapGetters } 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";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'info',
|
name: "info",
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['req', 'selected']),
|
...mapState(["req", "selected"]),
|
||||||
...mapGetters(['selectedCount', 'isListing']),
|
...mapGetters(["selectedCount", "isListing"]),
|
||||||
humanSize: function () {
|
humanSize: function () {
|
||||||
if (this.selectedCount === 0 || !this.isListing) {
|
if (this.selectedCount === 0 || !this.isListing) {
|
||||||
return filesize(this.req.size)
|
return filesize(this.req.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
let sum = 0
|
let sum = 0;
|
||||||
|
|
||||||
for (let selected of this.selected) {
|
for (let selected of this.selected) {
|
||||||
sum += this.req.items[selected].size
|
sum += this.req.items[selected].size;
|
||||||
}
|
}
|
||||||
|
|
||||||
return filesize(sum)
|
return filesize(sum);
|
||||||
},
|
},
|
||||||
humanTime: function () {
|
humanTime: function () {
|
||||||
if (this.selectedCount === 0) {
|
if (this.selectedCount === 0) {
|
||||||
return moment(this.req.modified).fromNow()
|
return moment(this.req.modified).fromNow();
|
||||||
}
|
}
|
||||||
|
|
||||||
return moment(this.req.items[this.selected[0]].modified).fromNow()
|
return moment(this.req.items[this.selected[0]].modified).fromNow();
|
||||||
},
|
},
|
||||||
name: function () {
|
name: function () {
|
||||||
return this.selectedCount === 0 ? this.req.name : this.req.items[this.selected[0]].name
|
return this.selectedCount === 0
|
||||||
|
? this.req.name
|
||||||
|
: this.req.items[this.selected[0]].name;
|
||||||
},
|
},
|
||||||
dir: function () {
|
dir: function () {
|
||||||
return this.selectedCount > 1 || (this.selectedCount === 0
|
return (
|
||||||
? this.req.isDir
|
this.selectedCount > 1 ||
|
||||||
: this.req.items[this.selected[0]].isDir)
|
(this.selectedCount === 0
|
||||||
}
|
? this.req.isDir
|
||||||
|
: this.req.items[this.selected[0]].isDir)
|
||||||
|
);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
checksum: async function (event, algo) {
|
checksum: async function (event, algo) {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
|
|
||||||
let link
|
let link;
|
||||||
|
|
||||||
if (this.selectedCount) {
|
if (this.selectedCount) {
|
||||||
link = this.req.items[this.selected[0]].url
|
link = this.req.items[this.selected[0]].url;
|
||||||
} else {
|
} else {
|
||||||
link = this.$route.path
|
link = this.$route.path;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const hash = await api.checksum(link, algo)
|
const hash = await api.checksum(link, algo);
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
event.target.innerHTML = hash
|
event.target.innerHTML = hash
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$showError(e)
|
this.$showError(e);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,93 +1,104 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="card floating">
|
<div class="card floating">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
<h2>{{ $t('prompts.move') }}</h2>
|
<h2>{{ $t("prompts.move") }}</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<file-list @update:selected="val => dest = val"></file-list>
|
<file-list @update:selected="(val) => (dest = val)"></file-list>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-action">
|
<div class="card-action">
|
||||||
<button class="button button--flat button--grey"
|
<button
|
||||||
|
class="button button--flat button--grey"
|
||||||
@click="$store.commit('closeHovers')"
|
@click="$store.commit('closeHovers')"
|
||||||
:aria-label="$t('buttons.cancel')"
|
:aria-label="$t('buttons.cancel')"
|
||||||
:title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
|
:title="$t('buttons.cancel')"
|
||||||
<button class="button button--flat"
|
>
|
||||||
|
{{ $t("buttons.cancel") }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="button button--flat"
|
||||||
@click="move"
|
@click="move"
|
||||||
:disabled="$route.path === dest"
|
:disabled="$route.path === dest"
|
||||||
:aria-label="$t('buttons.move')"
|
:aria-label="$t('buttons.move')"
|
||||||
:title="$t('buttons.move')">{{ $t('buttons.move') }}</button>
|
:title="$t('buttons.move')"
|
||||||
|
>
|
||||||
|
{{ $t("buttons.move") }}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState } from 'vuex'
|
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'
|
import * as upload from "@/utils/upload";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'move',
|
name: "move",
|
||||||
components: { FileList },
|
components: { FileList },
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
current: window.location.pathname,
|
current: window.location.pathname,
|
||||||
dest: null
|
dest: null,
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
computed: mapState(['req', 'selected']),
|
computed: mapState(["req", "selected"]),
|
||||||
methods: {
|
methods: {
|
||||||
move: async function (event) {
|
move: async function (event) {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
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
|
name: this.req.items[item].name,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let action = async (overwrite, rename) => {
|
let action = async (overwrite, rename) => {
|
||||||
buttons.loading('move')
|
buttons.loading("move");
|
||||||
|
|
||||||
await api.move(items, overwrite, rename).then(() => {
|
await api
|
||||||
buttons.success('move')
|
.move(items, overwrite, rename)
|
||||||
this.$router.push({ path: this.dest })
|
.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);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
let dstItems = (await api.fetch(this.dest)).items
|
let dstItems = (await api.fetch(this.dest)).items;
|
||||||
let conflict = upload.checkConflict(items, dstItems)
|
let conflict = upload.checkConflict(items, dstItems);
|
||||||
|
|
||||||
let overwrite = false
|
let overwrite = false;
|
||||||
let rename = false
|
let rename = false;
|
||||||
|
|
||||||
if (conflict) {
|
if (conflict) {
|
||||||
this.$store.commit('showHover', {
|
this.$store.commit("showHover", {
|
||||||
prompt: 'replace-rename',
|
prompt: "replace-rename",
|
||||||
confirm: (event, option) => {
|
confirm: (event, option) => {
|
||||||
overwrite = option == 'overwrite'
|
overwrite = option == "overwrite";
|
||||||
rename = option == 'rename'
|
rename = option == "rename";
|
||||||
|
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
this.$store.commit('closeHovers')
|
this.$store.commit("closeHovers");
|
||||||
action(overwrite, rename)
|
action(overwrite, rename);
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
action(overwrite, rename)
|
action(overwrite, rename);
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,12 +1,18 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="card floating">
|
<div class="card floating">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
<h2>{{ $t('prompts.newDir') }}</h2>
|
<h2>{{ $t("prompts.newDir") }}</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<p>{{ $t('prompts.newDirMessage') }}</p>
|
<p>{{ $t("prompts.newDirMessage") }}</p>
|
||||||
<input class="input input--block" type="text" @keyup.enter="submit" v-model.trim="name" v-focus>
|
<input
|
||||||
|
class="input input--block"
|
||||||
|
type="text"
|
||||||
|
@keyup.enter="submit"
|
||||||
|
v-model.trim="name"
|
||||||
|
v-focus
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-action">
|
<div class="card-action">
|
||||||
|
@ -15,57 +21,60 @@
|
||||||
@click="$store.commit('closeHovers')"
|
@click="$store.commit('closeHovers')"
|
||||||
:aria-label="$t('buttons.cancel')"
|
:aria-label="$t('buttons.cancel')"
|
||||||
:title="$t('buttons.cancel')"
|
:title="$t('buttons.cancel')"
|
||||||
>{{ $t('buttons.cancel') }}</button>
|
>
|
||||||
|
{{ $t("buttons.cancel") }}
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
class="button button--flat"
|
class="button button--flat"
|
||||||
:aria-label="$t('buttons.create')"
|
:aria-label="$t('buttons.create')"
|
||||||
:title="$t('buttons.create')"
|
:title="$t('buttons.create')"
|
||||||
@click="submit"
|
@click="submit"
|
||||||
>{{ $t('buttons.create') }}</button>
|
>
|
||||||
|
{{ $t("buttons.create") }}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapGetters } from 'vuex'
|
import { mapGetters } from "vuex";
|
||||||
import { files as api } from '@/api'
|
import { files as api } from "@/api";
|
||||||
import url from '@/utils/url'
|
import url from "@/utils/url";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'new-dir',
|
name: "new-dir",
|
||||||
data: function() {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
name: ''
|
name: "",
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters([ 'isFiles', 'isListing' ])
|
...mapGetters(["isFiles", "isListing"]),
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
submit: async function(event) {
|
submit: async function (event) {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
if (this.new === '') return
|
if (this.new === "") return;
|
||||||
|
|
||||||
// Build the path of the new directory.
|
// Build the path of the new directory.
|
||||||
let uri = this.isFiles ? this.$route.path + '/' : '/'
|
let uri = this.isFiles ? this.$route.path + "/" : "/";
|
||||||
|
|
||||||
if (!this.isListing) {
|
if (!this.isListing) {
|
||||||
uri = url.removeLastDir(uri) + '/'
|
uri = url.removeLastDir(uri) + "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
uri += encodeURIComponent(this.name) + '/'
|
uri += encodeURIComponent(this.name) + "/";
|
||||||
uri = uri.replace('//', '/')
|
uri = uri.replace("//", "/");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await api.post(uri)
|
await api.post(uri);
|
||||||
this.$router.push({ path: uri })
|
this.$router.push({ path: uri });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$showError(e)
|
this.$showError(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$store.commit('closeHovers')
|
this.$store.commit("closeHovers");
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,18 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="card floating">
|
<div class="card floating">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
<h2>{{ $t('prompts.newFile') }}</h2>
|
<h2>{{ $t("prompts.newFile") }}</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<p>{{ $t('prompts.newFileMessage') }}</p>
|
<p>{{ $t("prompts.newFileMessage") }}</p>
|
||||||
<input class="input input--block" v-focus type="text" @keyup.enter="submit" v-model.trim="name">
|
<input
|
||||||
|
class="input input--block"
|
||||||
|
v-focus
|
||||||
|
type="text"
|
||||||
|
@keyup.enter="submit"
|
||||||
|
v-model.trim="name"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-action">
|
<div class="card-action">
|
||||||
|
@ -15,57 +21,60 @@
|
||||||
@click="$store.commit('closeHovers')"
|
@click="$store.commit('closeHovers')"
|
||||||
:aria-label="$t('buttons.cancel')"
|
:aria-label="$t('buttons.cancel')"
|
||||||
:title="$t('buttons.cancel')"
|
:title="$t('buttons.cancel')"
|
||||||
>{{ $t('buttons.cancel') }}</button>
|
>
|
||||||
|
{{ $t("buttons.cancel") }}
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
class="button button--flat"
|
class="button button--flat"
|
||||||
@click="submit"
|
@click="submit"
|
||||||
:aria-label="$t('buttons.create')"
|
:aria-label="$t('buttons.create')"
|
||||||
:title="$t('buttons.create')"
|
:title="$t('buttons.create')"
|
||||||
>{{ $t('buttons.create') }}</button>
|
>
|
||||||
|
{{ $t("buttons.create") }}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapGetters } from 'vuex'
|
import { mapGetters } from "vuex";
|
||||||
import { files as api } from '@/api'
|
import { files as api } from "@/api";
|
||||||
import url from '@/utils/url'
|
import url from "@/utils/url";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'new-file',
|
name: "new-file",
|
||||||
data: function() {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
name: ''
|
name: "",
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters([ 'isFiles', 'isListing' ])
|
...mapGetters(["isFiles", "isListing"]),
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
submit: async function(event) {
|
submit: async function (event) {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
if (this.new === '') return
|
if (this.new === "") return;
|
||||||
|
|
||||||
// Build the path of the new directory.
|
// Build the path of the new directory.
|
||||||
let uri = this.isFiles ? this.$route.path + '/' : '/'
|
let uri = this.isFiles ? this.$route.path + "/" : "/";
|
||||||
|
|
||||||
if (!this.isListing) {
|
if (!this.isListing) {
|
||||||
uri = url.removeLastDir(uri) + '/'
|
uri = url.removeLastDir(uri) + "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
uri += encodeURIComponent(this.name)
|
uri += encodeURIComponent(this.name);
|
||||||
uri = uri.replace('//', '/')
|
uri = uri.replace("//", "/");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await api.post(uri)
|
await api.post(uri);
|
||||||
this.$router.push({ path: uri })
|
this.$router.push({ path: uri });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$showError(e)
|
this.$showError(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$store.commit('closeHovers')
|
this.$store.commit("closeHovers");
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -6,25 +6,25 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Help from './Help'
|
import Help from "./Help";
|
||||||
import Info from './Info'
|
import Info from "./Info";
|
||||||
import Delete from './Delete'
|
import Delete from "./Delete";
|
||||||
import Rename from './Rename'
|
import Rename from "./Rename";
|
||||||
import Download from './Download'
|
import Download from "./Download";
|
||||||
import Move from './Move'
|
import Move from "./Move";
|
||||||
import Copy from './Copy'
|
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 ReplaceRename from "./ReplaceRename";
|
||||||
import Share from './Share'
|
import Share from "./Share";
|
||||||
import Upload from './Upload'
|
import Upload from "./Upload";
|
||||||
import ShareDelete from './ShareDelete'
|
import ShareDelete from "./ShareDelete";
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from "vuex";
|
||||||
import buttons from '@/utils/buttons'
|
import buttons from "@/utils/buttons";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'prompts',
|
name: "prompts",
|
||||||
components: {
|
components: {
|
||||||
Info,
|
Info,
|
||||||
Delete,
|
Delete,
|
||||||
|
@ -39,74 +39,75 @@ export default {
|
||||||
Replace,
|
Replace,
|
||||||
ReplaceRename,
|
ReplaceRename,
|
||||||
Upload,
|
Upload,
|
||||||
ShareDelete
|
ShareDelete,
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
pluginData: {
|
pluginData: {
|
||||||
buttons,
|
buttons,
|
||||||
'store': this.$store,
|
store: this.$store,
|
||||||
'router': this.$router
|
router: this.$router,
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
created () {
|
created() {
|
||||||
window.addEventListener('keydown', (event) => {
|
window.addEventListener("keydown", (event) => {
|
||||||
if (this.show == null)
|
if (this.show == null) 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) {
|
||||||
case 'delete':
|
case "delete":
|
||||||
prompt.submit()
|
prompt.submit();
|
||||||
break;
|
break;
|
||||||
case 'copy':
|
case "copy":
|
||||||
prompt.copy(event)
|
prompt.copy(event);
|
||||||
break;
|
break;
|
||||||
case 'move':
|
case "move":
|
||||||
prompt.move(event)
|
prompt.move(event);
|
||||||
break;
|
break;
|
||||||
case 'replace':
|
case "replace":
|
||||||
prompt.showConfirm(event)
|
prompt.showConfirm(event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['show', 'plugins']),
|
...mapState(["show", "plugins"]),
|
||||||
currentComponent: function () {
|
currentComponent: function () {
|
||||||
const matched = [
|
const matched =
|
||||||
'info',
|
[
|
||||||
'help',
|
"info",
|
||||||
'delete',
|
"help",
|
||||||
'rename',
|
"delete",
|
||||||
'move',
|
"rename",
|
||||||
'copy',
|
"move",
|
||||||
'newFile',
|
"copy",
|
||||||
'newDir',
|
"newFile",
|
||||||
'download',
|
"newDir",
|
||||||
'replace',
|
"download",
|
||||||
'replace-rename',
|
"replace",
|
||||||
'share',
|
"replace-rename",
|
||||||
'upload',
|
"share",
|
||||||
'share-delete'
|
"upload",
|
||||||
].indexOf(this.show) >= 0;
|
"share-delete",
|
||||||
|
].indexOf(this.show) >= 0;
|
||||||
|
|
||||||
return matched && this.show || null;
|
return (matched && this.show) || null;
|
||||||
},
|
},
|
||||||
showOverlay: function () {
|
showOverlay: function () {
|
||||||
return (this.show !== null && this.show !== 'search' && this.show !== 'more')
|
return (
|
||||||
}
|
this.show !== null && this.show !== "search" && this.show !== "more"
|
||||||
|
);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
resetPrompts () {
|
resetPrompts() {
|
||||||
this.$store.commit('closeHovers')
|
this.$store.commit("closeHovers");
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,89 +1,107 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="card floating">
|
<div class="card floating">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
<h2>{{ $t('prompts.rename') }}</h2>
|
<h2>{{ $t("prompts.rename") }}</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<p>{{ $t('prompts.renameMessage') }} <code>{{ oldName() }}</code>:</p>
|
<p>
|
||||||
<input class="input input--block" v-focus type="text" @keyup.enter="submit" v-model.trim="name">
|
{{ $t("prompts.renameMessage") }} <code>{{ oldName() }}</code
|
||||||
|
>:
|
||||||
|
</p>
|
||||||
|
<input
|
||||||
|
class="input input--block"
|
||||||
|
v-focus
|
||||||
|
type="text"
|
||||||
|
@keyup.enter="submit"
|
||||||
|
v-model.trim="name"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-action">
|
<div class="card-action">
|
||||||
<button class="button button--flat button--grey"
|
<button
|
||||||
|
class="button button--flat button--grey"
|
||||||
@click="$store.commit('closeHovers')"
|
@click="$store.commit('closeHovers')"
|
||||||
:aria-label="$t('buttons.cancel')"
|
:aria-label="$t('buttons.cancel')"
|
||||||
:title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
|
:title="$t('buttons.cancel')"
|
||||||
<button @click="submit"
|
>
|
||||||
|
{{ $t("buttons.cancel") }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
@click="submit"
|
||||||
class="button button--flat"
|
class="button button--flat"
|
||||||
type="submit"
|
type="submit"
|
||||||
:aria-label="$t('buttons.rename')"
|
:aria-label="$t('buttons.rename')"
|
||||||
:title="$t('buttons.rename')">{{ $t('buttons.rename') }}</button>
|
:title="$t('buttons.rename')"
|
||||||
|
>
|
||||||
|
{{ $t("buttons.rename") }}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState, mapGetters } from 'vuex'
|
import { mapState, mapGetters } from "vuex";
|
||||||
import url from '@/utils/url'
|
import url from "@/utils/url";
|
||||||
import { files as api } from '@/api'
|
import { files as api } from "@/api";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'rename',
|
name: "rename",
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
name: ''
|
name: "",
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
created () {
|
created() {
|
||||||
this.name = this.oldName()
|
this.name = this.oldName();
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['req', 'selected', 'selectedCount']),
|
...mapState(["req", "selected", "selectedCount"]),
|
||||||
...mapGetters(['isListing'])
|
...mapGetters(["isListing"]),
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
cancel: function () {
|
cancel: function () {
|
||||||
this.$store.commit('closeHovers')
|
this.$store.commit("closeHovers");
|
||||||
},
|
},
|
||||||
oldName: function () {
|
oldName: function () {
|
||||||
if (!this.isListing) {
|
if (!this.isListing) {
|
||||||
return this.req.name
|
return this.req.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.selectedCount === 0 || this.selectedCount > 1) {
|
if (this.selectedCount === 0 || this.selectedCount > 1) {
|
||||||
// This shouldn't happen.
|
// This shouldn't happen.
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.req.items[this.selected[0]].name
|
return this.req.items[this.selected[0]].name;
|
||||||
},
|
},
|
||||||
submit: async function () {
|
submit: async function () {
|
||||||
let oldLink = ''
|
let oldLink = "";
|
||||||
let newLink = ''
|
let newLink = "";
|
||||||
|
|
||||||
if (!this.isListing) {
|
if (!this.isListing) {
|
||||||
oldLink = this.req.url
|
oldLink = this.req.url;
|
||||||
} else {
|
} else {
|
||||||
oldLink = this.req.items[this.selected[0]].url
|
oldLink = this.req.items[this.selected[0]].url;
|
||||||
}
|
}
|
||||||
|
|
||||||
newLink = url.removeLastDir(oldLink) + '/' + encodeURIComponent(this.name)
|
newLink =
|
||||||
|
url.removeLastDir(oldLink) + "/" + encodeURIComponent(this.name);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await api.move([{ from: oldLink, to: newLink }])
|
await api.move([{ from: oldLink, to: newLink }]);
|
||||||
if (!this.isListing) {
|
if (!this.isListing) {
|
||||||
this.$router.push({ path: newLink })
|
this.$router.push({ path: newLink });
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$store.commit('setReload', true)
|
this.$store.commit("setReload", true);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$showError(e)
|
this.$showError(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$store.commit('closeHovers')
|
this.$store.commit("closeHovers");
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,31 +1,39 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="card floating">
|
<div class="card floating">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
<h2>{{ $t('prompts.replace') }}</h2>
|
<h2>{{ $t("prompts.replace") }}</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<p>{{ $t('prompts.replaceMessage') }}</p>
|
<p>{{ $t("prompts.replaceMessage") }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-action">
|
<div class="card-action">
|
||||||
<button class="button button--flat button--grey"
|
<button
|
||||||
|
class="button button--flat button--grey"
|
||||||
@click="$store.commit('closeHovers')"
|
@click="$store.commit('closeHovers')"
|
||||||
:aria-label="$t('buttons.cancel')"
|
:aria-label="$t('buttons.cancel')"
|
||||||
:title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
|
:title="$t('buttons.cancel')"
|
||||||
<button class="button button--flat button--red"
|
>
|
||||||
|
{{ $t("buttons.cancel") }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="button button--flat button--red"
|
||||||
@click="showConfirm"
|
@click="showConfirm"
|
||||||
:aria-label="$t('buttons.replace')"
|
:aria-label="$t('buttons.replace')"
|
||||||
:title="$t('buttons.replace')">{{ $t('buttons.replace') }}</button>
|
:title="$t('buttons.replace')"
|
||||||
|
>
|
||||||
|
{{ $t("buttons.replace") }}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from "vuex";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'replace',
|
name: "replace",
|
||||||
computed: mapState(['showConfirm'])
|
computed: mapState(["showConfirm"]),
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,35 +1,47 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="card floating">
|
<div class="card floating">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
<h2>{{ $t('prompts.replace') }}</h2>
|
<h2>{{ $t("prompts.replace") }}</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<p>{{ $t('prompts.replaceMessage') }}</p>
|
<p>{{ $t("prompts.replaceMessage") }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-action">
|
<div class="card-action">
|
||||||
<button class="button button--flat button--grey"
|
<button
|
||||||
|
class="button button--flat button--grey"
|
||||||
@click="$store.commit('closeHovers')"
|
@click="$store.commit('closeHovers')"
|
||||||
:aria-label="$t('buttons.cancel')"
|
:aria-label="$t('buttons.cancel')"
|
||||||
:title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
|
:title="$t('buttons.cancel')"
|
||||||
<button class="button button--flat button--blue"
|
>
|
||||||
|
{{ $t("buttons.cancel") }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="button button--flat button--blue"
|
||||||
@click="(event) => showConfirm(event, 'rename')"
|
@click="(event) => showConfirm(event, 'rename')"
|
||||||
:aria-label="$t('buttons.rename')"
|
:aria-label="$t('buttons.rename')"
|
||||||
:title="$t('buttons.rename')">{{ $t('buttons.rename') }}</button>
|
:title="$t('buttons.rename')"
|
||||||
<button class="button button--flat button--red"
|
>
|
||||||
|
{{ $t("buttons.rename") }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="button button--flat button--red"
|
||||||
@click="(event) => showConfirm(event, 'overwrite')"
|
@click="(event) => showConfirm(event, 'overwrite')"
|
||||||
:aria-label="$t('buttons.replace')"
|
:aria-label="$t('buttons.replace')"
|
||||||
:title="$t('buttons.replace')">{{ $t('buttons.replace') }}</button>
|
:title="$t('buttons.replace')"
|
||||||
|
>
|
||||||
|
{{ $t("buttons.replace") }}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from "vuex";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'replace-rename',
|
name: "replace-rename",
|
||||||
computed: mapState(['showConfirm'])
|
computed: mapState(["showConfirm"]),
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="card floating share__promt__card" id="share">
|
<div class="card floating share__promt__card" id="share">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
<h2>{{ $t('buttons.share') }}</h2>
|
<h2>{{ $t("buttons.share") }}</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template v-if="listing">
|
<template v-if="listing">
|
||||||
|
@ -9,7 +9,7 @@
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<th>#</th>
|
<th>#</th>
|
||||||
<th>{{ $t('settings.shareDuration') }}</th>
|
<th>{{ $t("settings.shareDuration") }}</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -17,188 +17,219 @@
|
||||||
<tr v-for="link in links" :key="link.hash">
|
<tr v-for="link in links" :key="link.hash">
|
||||||
<td>{{ link.hash }}</td>
|
<td>{{ link.hash }}</td>
|
||||||
<td>
|
<td>
|
||||||
<template v-if="link.expire !== 0">{{ humanTime(link.expire) }}</template>
|
<template v-if="link.expire !== 0">{{
|
||||||
<template v-else>{{ $t('permanent') }}</template>
|
humanTime(link.expire)
|
||||||
|
}}</template>
|
||||||
|
<template v-else>{{ $t("permanent") }}</template>
|
||||||
</td>
|
</td>
|
||||||
<td class="small">
|
<td class="small">
|
||||||
<button class="action copy-clipboard"
|
<button
|
||||||
|
class="action copy-clipboard"
|
||||||
:data-clipboard-text="buildLink(link.hash)"
|
:data-clipboard-text="buildLink(link.hash)"
|
||||||
:aria-label="$t('buttons.copyToClipboard')"
|
:aria-label="$t('buttons.copyToClipboard')"
|
||||||
:title="$t('buttons.copyToClipboard')"><i class="material-icons">content_paste</i></button>
|
:title="$t('buttons.copyToClipboard')"
|
||||||
|
>
|
||||||
|
<i class="material-icons">content_paste</i>
|
||||||
|
</button>
|
||||||
</td>
|
</td>
|
||||||
<td class="small">
|
<td class="small">
|
||||||
<button class="action"
|
<button
|
||||||
|
class="action"
|
||||||
@click="deleteLink($event, link)"
|
@click="deleteLink($event, link)"
|
||||||
:aria-label="$t('buttons.delete')"
|
:aria-label="$t('buttons.delete')"
|
||||||
:title="$t('buttons.delete')"><i class="material-icons">delete</i></button>
|
:title="$t('buttons.delete')"
|
||||||
|
>
|
||||||
|
<i class="material-icons">delete</i>
|
||||||
|
</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-action">
|
<div class="card-action">
|
||||||
<button class="button button--flat button--grey"
|
<button
|
||||||
|
class="button button--flat button--grey"
|
||||||
@click="$store.commit('closeHovers')"
|
@click="$store.commit('closeHovers')"
|
||||||
:aria-label="$t('buttons.close')"
|
:aria-label="$t('buttons.close')"
|
||||||
:title="$t('buttons.close')">{{ $t('buttons.close') }}</button>
|
:title="$t('buttons.close')"
|
||||||
<button class="button button--flat button--blue"
|
>
|
||||||
|
{{ $t("buttons.close") }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="button button--flat button--blue"
|
||||||
@click="() => switchListing()"
|
@click="() => switchListing()"
|
||||||
:aria-label="$t('buttons.new')"
|
:aria-label="$t('buttons.new')"
|
||||||
:title="$t('buttons.new')">{{ $t('buttons.new') }}</button>
|
:title="$t('buttons.new')"
|
||||||
|
>
|
||||||
|
{{ $t("buttons.new") }}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<p>{{ $t('settings.shareDuration') }}</p>
|
<p>{{ $t("settings.shareDuration") }}</p>
|
||||||
<div class="input-group input">
|
<div class="input-group input">
|
||||||
<input v-focus
|
<input
|
||||||
type="number"
|
v-focus
|
||||||
max="2147483647"
|
type="number"
|
||||||
min="1"
|
max="2147483647"
|
||||||
@keyup.enter="submit"
|
min="1"
|
||||||
v-model.trim="time">
|
@keyup.enter="submit"
|
||||||
<select class="right" v-model="unit" :aria-label="$t('time.unit')">
|
v-model.trim="time"
|
||||||
<option value="seconds">{{ $t('time.seconds') }}</option>
|
/>
|
||||||
<option value="minutes">{{ $t('time.minutes') }}</option>
|
<select class="right" v-model="unit" :aria-label="$t('time.unit')">
|
||||||
<option value="hours">{{ $t('time.hours') }}</option>
|
<option value="seconds">{{ $t("time.seconds") }}</option>
|
||||||
<option value="days">{{ $t('time.days') }}</option>
|
<option value="minutes">{{ $t("time.minutes") }}</option>
|
||||||
</select>
|
<option value="hours">{{ $t("time.hours") }}</option>
|
||||||
|
<option value="days">{{ $t("time.days") }}</option>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<p>{{ $t('prompts.optionalPassword') }}</p>
|
<p>{{ $t("prompts.optionalPassword") }}</p>
|
||||||
<input class="input input--block" type="password" v-model.trim="password">
|
<input
|
||||||
|
class="input input--block"
|
||||||
|
type="password"
|
||||||
|
v-model.trim="password"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-action">
|
<div class="card-action">
|
||||||
<button class="button button--flat button--grey"
|
<button
|
||||||
|
class="button button--flat button--grey"
|
||||||
@click="() => switchListing()"
|
@click="() => switchListing()"
|
||||||
:aria-label="$t('buttons.cancel')"
|
:aria-label="$t('buttons.cancel')"
|
||||||
:title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
|
:title="$t('buttons.cancel')"
|
||||||
<button class="button button--flat button--blue"
|
>
|
||||||
|
{{ $t("buttons.cancel") }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="button button--flat button--blue"
|
||||||
@click="submit"
|
@click="submit"
|
||||||
:aria-label="$t('buttons.share')"
|
:aria-label="$t('buttons.share')"
|
||||||
:title="$t('buttons.share')">{{ $t('buttons.share') }}</button>
|
:title="$t('buttons.share')"
|
||||||
|
>
|
||||||
|
{{ $t("buttons.share") }}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState, mapGetters } from 'vuex'
|
import { mapState, mapGetters } from "vuex";
|
||||||
import { share as api } from '@/api'
|
import { share as api } from "@/api";
|
||||||
import { baseURL } from '@/utils/constants'
|
import { baseURL } from "@/utils/constants";
|
||||||
import moment from 'moment'
|
import moment from "moment";
|
||||||
import Clipboard from 'clipboard'
|
import Clipboard from "clipboard";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'share',
|
name: "share",
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
time: '',
|
time: "",
|
||||||
unit: 'hours',
|
unit: "hours",
|
||||||
links: [],
|
links: [],
|
||||||
clip: null,
|
clip: null,
|
||||||
password: '',
|
password: "",
|
||||||
listing: true
|
listing: true,
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState([ 'req', 'selected', 'selectedCount' ]),
|
...mapState(["req", "selected", "selectedCount"]),
|
||||||
...mapGetters([ 'isListing' ]),
|
...mapGetters(["isListing"]),
|
||||||
url () {
|
url() {
|
||||||
if (!this.isListing) {
|
if (!this.isListing) {
|
||||||
return this.$route.path
|
return this.$route.path;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.selectedCount === 0 || this.selectedCount > 1) {
|
if (this.selectedCount === 0 || this.selectedCount > 1) {
|
||||||
// This shouldn't happen.
|
// This shouldn't happen.
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.req.items[this.selected[0]].url
|
return this.req.items[this.selected[0]].url;
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
async beforeMount () {
|
async beforeMount() {
|
||||||
try {
|
try {
|
||||||
const links = await api.get(this.url)
|
const links = await api.get(this.url);
|
||||||
this.links = links
|
this.links = links;
|
||||||
this.sort()
|
this.sort();
|
||||||
|
|
||||||
if (this.links.length == 0) {
|
if (this.links.length == 0) {
|
||||||
this.listing = false
|
this.listing = false;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$showError(e)
|
this.$showError(e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted() {
|
||||||
this.clip = new Clipboard('.copy-clipboard')
|
this.clip = new Clipboard(".copy-clipboard");
|
||||||
this.clip.on('success', () => {
|
this.clip.on("success", () => {
|
||||||
this.$showSuccess(this.$t('success.linkCopied'))
|
this.$showSuccess(this.$t("success.linkCopied"));
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
beforeDestroy () {
|
beforeDestroy() {
|
||||||
this.clip.destroy()
|
this.clip.destroy();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
submit: async function () {
|
submit: async function () {
|
||||||
let isPermanent = !this.time || this.time == 0
|
let isPermanent = !this.time || this.time == 0;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let res = null
|
let res = null;
|
||||||
|
|
||||||
if (isPermanent) {
|
if (isPermanent) {
|
||||||
res = await api.create(this.url, this.password)
|
res = await api.create(this.url, this.password);
|
||||||
} else {
|
} else {
|
||||||
res = await api.create(this.url, this.password, this.time, this.unit)
|
res = await api.create(this.url, this.password, this.time, this.unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.links.push(res)
|
this.links.push(res);
|
||||||
this.sort()
|
this.sort();
|
||||||
|
|
||||||
this.time = ''
|
this.time = "";
|
||||||
this.unit = 'hours'
|
this.unit = "hours";
|
||||||
this.password = ''
|
this.password = "";
|
||||||
|
|
||||||
this.listing = true
|
this.listing = true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$showError(e)
|
this.$showError(e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
deleteLink: async function (event, link) {
|
deleteLink: async function (event, link) {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
try {
|
try {
|
||||||
await api.remove(link.hash)
|
await api.remove(link.hash);
|
||||||
this.links = this.links.filter(item => item.hash !== link.hash)
|
this.links = this.links.filter((item) => item.hash !== link.hash);
|
||||||
|
|
||||||
if (this.links.length == 0) {
|
if (this.links.length == 0) {
|
||||||
this.listing = false
|
this.listing = false;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$showError(e)
|
this.$showError(e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
humanTime (time) {
|
humanTime(time) {
|
||||||
return moment(time * 1000).fromNow()
|
return moment(time * 1000).fromNow();
|
||||||
},
|
},
|
||||||
buildLink (hash) {
|
buildLink(hash) {
|
||||||
return `${window.location.origin}${baseURL}/share/${hash}`
|
return `${window.location.origin}${baseURL}/share/${hash}`;
|
||||||
},
|
},
|
||||||
sort () {
|
sort() {
|
||||||
this.links = this.links.sort((a, b) => {
|
this.links = this.links.sort((a, b) => {
|
||||||
if (a.expire === 0) return -1
|
if (a.expire === 0) return -1;
|
||||||
if (b.expire === 0) return 1
|
if (b.expire === 0) return 1;
|
||||||
return new Date(a.expire) - new Date(b.expire)
|
return new Date(a.expire) - new Date(b.expire);
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
switchListing () {
|
switchListing() {
|
||||||
if (this.links.length == 0 && !this.listing) {
|
if (this.links.length == 0 && !this.listing) {
|
||||||
this.$store.commit('closeHovers')
|
this.$store.commit("closeHovers");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.listing = !this.listing
|
this.listing = !this.listing;
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1,33 +1,41 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="card floating">
|
<div class="card floating">
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<p>{{ $t('prompts.deleteMessageShare', {path: ''}) }}</p>
|
<p>{{ $t("prompts.deleteMessageShare", { path: "" }) }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-action">
|
<div class="card-action">
|
||||||
<button @click="$store.commit('closeHovers')"
|
<button
|
||||||
|
@click="$store.commit('closeHovers')"
|
||||||
class="button button--flat button--grey"
|
class="button button--flat button--grey"
|
||||||
:aria-label="$t('buttons.cancel')"
|
:aria-label="$t('buttons.cancel')"
|
||||||
:title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
|
:title="$t('buttons.cancel')"
|
||||||
<button @click="submit"
|
>
|
||||||
|
{{ $t("buttons.cancel") }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
@click="submit"
|
||||||
class="button button--flat button--red"
|
class="button button--flat button--red"
|
||||||
:aria-label="$t('buttons.delete')"
|
:aria-label="$t('buttons.delete')"
|
||||||
:title="$t('buttons.delete')">{{ $t('buttons.delete') }}</button>
|
:title="$t('buttons.delete')"
|
||||||
|
>
|
||||||
|
{{ $t("buttons.delete") }}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {mapState} from 'vuex'
|
import { mapState } from "vuex";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'share-delete',
|
name: "share-delete",
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['showConfirm'])
|
...mapState(["showConfirm"]),
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
submit: function () {
|
submit: function () {
|
||||||
this.showConfirm()
|
this.showConfirm();
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="card floating">
|
<div class="card floating">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
<h2>{{ $t('prompts.upload') }}</h2>
|
<h2>{{ $t("prompts.upload") }}</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<p>{{ $t('prompts.uploadMessage') }}</p>
|
<p>{{ $t("prompts.uploadMessage") }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-action full">
|
<div class="card-action full">
|
||||||
|
@ -22,18 +22,17 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'upload',
|
name: "upload",
|
||||||
methods: {
|
methods: {
|
||||||
uploadFile: function () {
|
uploadFile: function () {
|
||||||
document.getElementById('upload-input').value = ''
|
document.getElementById("upload-input").value = "";
|
||||||
document.getElementById('upload-input').click()
|
document.getElementById("upload-input").click();
|
||||||
},
|
},
|
||||||
uploadFolder: function () {
|
uploadFolder: function () {
|
||||||
document.getElementById('upload-folder-input').value = ''
|
document.getElementById("upload-folder-input").value = "";
|
||||||
document.getElementById('upload-folder-input').click()
|
document.getElementById("upload-folder-input").click();
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,28 +1,30 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<h3>{{ $t('settings.userCommands') }}</h3>
|
<h3>{{ $t("settings.userCommands") }}</h3>
|
||||||
<p class="small">{{ $t('settings.userCommandsHelp') }} <i>git svn hg</i>.</p>
|
<p class="small">
|
||||||
<input class="input input--block" type="text" v-model.trim="raw">
|
{{ $t("settings.userCommandsHelp") }} <i>git svn hg</i>.
|
||||||
|
</p>
|
||||||
|
<input class="input input--block" type="text" v-model.trim="raw" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'permissions',
|
name: "permissions",
|
||||||
props: ['commands'],
|
props: ["commands"],
|
||||||
computed: {
|
computed: {
|
||||||
raw: {
|
raw: {
|
||||||
get () {
|
get() {
|
||||||
return this.commands.join(' ')
|
return this.commands.join(" ");
|
||||||
},
|
},
|
||||||
set (value) {
|
set(value) {
|
||||||
if (value !== '') {
|
if (value !== "") {
|
||||||
this.$emit('update:commands', value.split(' '))
|
this.$emit("update:commands", value.split(" "));
|
||||||
} else {
|
} else {
|
||||||
this.$emit('update:commands', [])
|
this.$emit("update:commands", []);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,46 +1,50 @@
|
||||||
<template>
|
<template>
|
||||||
<select v-on:change="change" :value="locale">
|
<select v-on:change="change" :value="locale">
|
||||||
<option v-for="(language, value) in locales" :key="value" :value="value">{{ $t('languages.' + language) }}</option>
|
<option v-for="(language, value) in locales" :key="value" :value="value">
|
||||||
|
{{ $t("languages." + language) }}
|
||||||
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'languages',
|
name: "languages",
|
||||||
props: [ 'locale' ],
|
props: ["locale"],
|
||||||
data() {
|
data() {
|
||||||
let dataObj = {
|
let dataObj = {
|
||||||
locales: {
|
locales: {
|
||||||
ar: 'ar',
|
ar: "ar",
|
||||||
de: 'de',
|
de: "de",
|
||||||
en: 'en',
|
en: "en",
|
||||||
es: 'es',
|
es: "es",
|
||||||
fr: 'fr',
|
fr: "fr",
|
||||||
is: 'is',
|
is: "is",
|
||||||
it: 'it',
|
it: "it",
|
||||||
ja: 'ja',
|
ja: "ja",
|
||||||
ko: 'ko',
|
ko: "ko",
|
||||||
'nl-be': 'nlBE',
|
"nl-be": "nlBE",
|
||||||
pl: 'pl',
|
pl: "pl",
|
||||||
'pt-br': 'ptBR',
|
"pt-br": "ptBR",
|
||||||
pt: 'pt',
|
pt: "pt",
|
||||||
ro: 'ro',
|
ro: "ro",
|
||||||
ru: 'ru',
|
ru: "ru",
|
||||||
'sv-se': 'svSE',
|
"sv-se": "svSE",
|
||||||
'zh-cn': 'zhCN',
|
"zh-cn": "zhCN",
|
||||||
'zh-tw': 'zhTW'
|
"zh-tw": "zhTW",
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
Object.defineProperty(dataObj, "locales", { configurable: false, writable: false });
|
Object.defineProperty(dataObj, "locales", {
|
||||||
|
configurable: false,
|
||||||
|
writable: false,
|
||||||
|
});
|
||||||
|
|
||||||
return dataObj;
|
return dataObj;
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
change (event) {
|
change(event) {
|
||||||
this.$emit('update:locale', event.target.value)
|
this.$emit("update:locale", event.target.value);
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,41 +1,65 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<h3>{{ $t('settings.permissions') }}</h3>
|
<h3>{{ $t("settings.permissions") }}</h3>
|
||||||
<p class="small">{{ $t('settings.permissionsHelp') }}</p>
|
<p class="small">{{ $t("settings.permissionsHelp") }}</p>
|
||||||
|
|
||||||
<p><input type="checkbox" v-model="admin"> {{ $t('settings.administrator') }}</p>
|
<p>
|
||||||
|
<input type="checkbox" v-model="admin" />
|
||||||
|
{{ $t("settings.administrator") }}
|
||||||
|
</p>
|
||||||
|
|
||||||
<p><input type="checkbox" :disabled="admin" v-model="perm.create"> {{ $t('settings.perm.create') }}</p>
|
<p>
|
||||||
<p><input type="checkbox" :disabled="admin" v-model="perm.delete"> {{ $t('settings.perm.delete') }}</p>
|
<input type="checkbox" :disabled="admin" v-model="perm.create" />
|
||||||
<p><input type="checkbox" :disabled="admin" v-model="perm.download"> {{ $t('settings.perm.download') }}</p>
|
{{ $t("settings.perm.create") }}
|
||||||
<p><input type="checkbox" :disabled="admin" v-model="perm.modify"> {{ $t('settings.perm.modify') }}</p>
|
</p>
|
||||||
<p v-if="isExecEnabled"><input type="checkbox" :disabled="admin" v-model="perm.execute"> {{ $t('settings.perm.execute') }}</p>
|
<p>
|
||||||
<p><input type="checkbox" :disabled="admin" v-model="perm.rename"> {{ $t('settings.perm.rename') }}</p>
|
<input type="checkbox" :disabled="admin" v-model="perm.delete" />
|
||||||
<p><input type="checkbox" :disabled="admin" v-model="perm.share"> {{ $t('settings.perm.share') }}</p>
|
{{ $t("settings.perm.delete") }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<input type="checkbox" :disabled="admin" v-model="perm.download" />
|
||||||
|
{{ $t("settings.perm.download") }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<input type="checkbox" :disabled="admin" v-model="perm.modify" />
|
||||||
|
{{ $t("settings.perm.modify") }}
|
||||||
|
</p>
|
||||||
|
<p v-if="isExecEnabled">
|
||||||
|
<input type="checkbox" :disabled="admin" v-model="perm.execute" />
|
||||||
|
{{ $t("settings.perm.execute") }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<input type="checkbox" :disabled="admin" v-model="perm.rename" />
|
||||||
|
{{ $t("settings.perm.rename") }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<input type="checkbox" :disabled="admin" v-model="perm.share" />
|
||||||
|
{{ $t("settings.perm.share") }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { enableExec } from '@/utils/constants'
|
import { enableExec } from "@/utils/constants";
|
||||||
export default {
|
export default {
|
||||||
name: 'permissions',
|
name: "permissions",
|
||||||
props: ['perm'],
|
props: ["perm"],
|
||||||
computed: {
|
computed: {
|
||||||
admin: {
|
admin: {
|
||||||
get () {
|
get() {
|
||||||
return this.perm.admin
|
return this.perm.admin;
|
||||||
},
|
},
|
||||||
set (value) {
|
set(value) {
|
||||||
if (value) {
|
if (value) {
|
||||||
for (const key in this.perm) {
|
for (const key in this.perm) {
|
||||||
this.perm[key] = true
|
this.perm[key] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.perm.admin = value
|
this.perm.admin = value;
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
isExecEnabled: () => enableExec
|
isExecEnabled: () => enableExec,
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,57 +1,63 @@
|
||||||
<template>
|
<template>
|
||||||
<form class="rules small">
|
<form class="rules small">
|
||||||
<div v-for="(rule, index) in rules" :key="index">
|
<div v-for="(rule, index) in rules" :key="index">
|
||||||
<input type="checkbox" v-model="rule.regex"><label>Regex</label>
|
<input type="checkbox" v-model="rule.regex" /><label>Regex</label>
|
||||||
<input type="checkbox" v-model="rule.allow"><label>Allow</label>
|
<input type="checkbox" v-model="rule.allow" /><label>Allow</label>
|
||||||
|
|
||||||
<input
|
<input
|
||||||
@keypress.enter.prevent
|
@keypress.enter.prevent
|
||||||
type="text"
|
type="text"
|
||||||
v-if="rule.regex"
|
v-if="rule.regex"
|
||||||
v-model="rule.regexp.raw"
|
v-model="rule.regexp.raw"
|
||||||
:placeholder="$t('settings.insertRegex')" />
|
:placeholder="$t('settings.insertRegex')"
|
||||||
|
/>
|
||||||
<input
|
<input
|
||||||
@keypress.enter.prevent
|
@keypress.enter.prevent
|
||||||
type="text"
|
type="text"
|
||||||
v-else
|
v-else
|
||||||
v-model="rule.path"
|
v-model="rule.path"
|
||||||
:placeholder="$t('settings.insertPath')" />
|
:placeholder="$t('settings.insertPath')"
|
||||||
|
/>
|
||||||
|
|
||||||
<button class="button button--red" @click="remove($event, index)">-</button>
|
<button class="button button--red" @click="remove($event, index)">
|
||||||
|
-
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<button class="button" @click="create" default="false">{{ $t('buttons.new') }}</button>
|
<button class="button" @click="create" default="false">
|
||||||
|
{{ $t("buttons.new") }}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'rules-textarea',
|
name: "rules-textarea",
|
||||||
props: ['rules'],
|
props: ["rules"],
|
||||||
methods: {
|
methods: {
|
||||||
remove (event, index) {
|
remove(event, index) {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
let rules = [ ...this.rules ]
|
let rules = [...this.rules];
|
||||||
rules.splice(index, 1)
|
rules.splice(index, 1);
|
||||||
this.$emit('update:rules', [ ...rules ])
|
this.$emit("update:rules", [...rules]);
|
||||||
},
|
},
|
||||||
create (event) {
|
create(event) {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
|
|
||||||
this.$emit('update:rules', [
|
this.$emit("update:rules", [
|
||||||
...this.rules,
|
...this.rules,
|
||||||
{
|
{
|
||||||
allow: true,
|
allow: true,
|
||||||
path: '',
|
path: "",
|
||||||
regex: false,
|
regex: false,
|
||||||
regexp: {
|
regexp: {
|
||||||
raw: ''
|
raw: "",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
])
|
]);
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
<template>
|
<template>
|
||||||
<select v-on:change="change" :value="theme">
|
<select v-on:change="change" :value="theme">
|
||||||
<option value="">{{ $t('settings.themes.light') }}</option>
|
<option value="">{{ $t("settings.themes.light") }}</option>
|
||||||
<option value="dark">{{ $t('settings.themes.dark') }}</option>
|
<option value="dark">{{ $t("settings.themes.dark") }}</option>
|
||||||
</select>
|
</select>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'themes',
|
name: "themes",
|
||||||
props: [ 'theme' ],
|
props: ["theme"],
|
||||||
methods: {
|
methods: {
|
||||||
change (event) {
|
change(event) {
|
||||||
this.$emit('update:theme', event.target.value)
|
this.$emit("update:theme", event.target.value);
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
|
@ -1,67 +1,92 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<p v-if="!isDefault">
|
<p v-if="!isDefault">
|
||||||
<label for="username">{{ $t('settings.username') }}</label>
|
<label for="username">{{ $t("settings.username") }}</label>
|
||||||
<input class="input input--block" type="text" v-model="user.username" id="username">
|
<input
|
||||||
|
class="input input--block"
|
||||||
|
type="text"
|
||||||
|
v-model="user.username"
|
||||||
|
id="username"
|
||||||
|
/>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p v-if="!isDefault">
|
<p v-if="!isDefault">
|
||||||
<label for="password">{{ $t('settings.password') }}</label>
|
<label for="password">{{ $t("settings.password") }}</label>
|
||||||
<input class="input input--block" type="password" :placeholder="passwordPlaceholder" v-model="user.password" id="password">
|
<input
|
||||||
|
class="input input--block"
|
||||||
|
type="password"
|
||||||
|
:placeholder="passwordPlaceholder"
|
||||||
|
v-model="user.password"
|
||||||
|
id="password"
|
||||||
|
/>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<label for="scope">{{ $t('settings.scope') }}</label>
|
<label for="scope">{{ $t("settings.scope") }}</label>
|
||||||
<input class="input input--block" type="text" v-model="user.scope" id="scope">
|
<input
|
||||||
|
class="input input--block"
|
||||||
|
type="text"
|
||||||
|
v-model="user.scope"
|
||||||
|
id="scope"
|
||||||
|
/>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<label for="locale">{{ $t('settings.language') }}</label>
|
<label for="locale">{{ $t("settings.language") }}</label>
|
||||||
<languages class="input input--block" id="locale" :locale.sync="user.locale"></languages>
|
<languages
|
||||||
|
class="input input--block"
|
||||||
|
id="locale"
|
||||||
|
:locale.sync="user.locale"
|
||||||
|
></languages>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p v-if="!isDefault">
|
<p v-if="!isDefault">
|
||||||
<input type="checkbox" :disabled="user.perm.admin" v-model="user.lockPassword"> {{ $t('settings.lockPassword') }}
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
:disabled="user.perm.admin"
|
||||||
|
v-model="user.lockPassword"
|
||||||
|
/>
|
||||||
|
{{ $t("settings.lockPassword") }}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<permissions :perm.sync="user.perm" />
|
<permissions :perm.sync="user.perm" />
|
||||||
<commands v-if="isExecEnabled" :commands.sync="user.commands" />
|
<commands v-if="isExecEnabled" :commands.sync="user.commands" />
|
||||||
|
|
||||||
<div v-if="!isDefault">
|
<div v-if="!isDefault">
|
||||||
<h3>{{ $t('settings.rules') }}</h3>
|
<h3>{{ $t("settings.rules") }}</h3>
|
||||||
<p class="small">{{ $t('settings.rulesHelp') }}</p>
|
<p class="small">{{ $t("settings.rulesHelp") }}</p>
|
||||||
<rules :rules.sync="user.rules" />
|
<rules :rules.sync="user.rules" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Languages from './Languages'
|
import Languages from "./Languages";
|
||||||
import Rules from './Rules'
|
import Rules from "./Rules";
|
||||||
import Permissions from './Permissions'
|
import Permissions from "./Permissions";
|
||||||
import Commands from './Commands'
|
import Commands from "./Commands";
|
||||||
import { enableExec } from '@/utils/constants'
|
import { enableExec } from "@/utils/constants";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'user',
|
name: "user",
|
||||||
components: {
|
components: {
|
||||||
Permissions,
|
Permissions,
|
||||||
Languages,
|
Languages,
|
||||||
Rules,
|
Rules,
|
||||||
Commands
|
Commands,
|
||||||
},
|
},
|
||||||
props: [ 'user', 'isNew', 'isDefault' ],
|
props: ["user", "isNew", "isDefault"],
|
||||||
computed: {
|
computed: {
|
||||||
passwordPlaceholder () {
|
passwordPlaceholder() {
|
||||||
return this.isNew ? '' : this.$t('settings.avoidChanges')
|
return this.isNew ? "" : this.$t("settings.avoidChanges");
|
||||||
},
|
},
|
||||||
isExecEnabled: () => enableExec
|
isExecEnabled: () => enableExec,
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
'user.perm.admin': function () {
|
"user.perm.admin": function () {
|
||||||
if (!this.user.perm.admin) return
|
if (!this.user.perm.admin) return;
|
||||||
this.user.lockPassword = false
|
this.user.lockPassword = false;
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,116 +1,116 @@
|
||||||
import Vue from 'vue'
|
import Vue from "vue";
|
||||||
import VueI18n from 'vue-i18n'
|
import VueI18n from "vue-i18n";
|
||||||
|
|
||||||
import ar from './ar.json'
|
import ar from "./ar.json";
|
||||||
import de from './de.json'
|
import de from "./de.json";
|
||||||
import en from './en.json'
|
import en from "./en.json";
|
||||||
import es from './es.json'
|
import es from "./es.json";
|
||||||
import fr from './fr.json'
|
import fr from "./fr.json";
|
||||||
import is from './is.json'
|
import is from "./is.json";
|
||||||
import it from './it.json'
|
import it from "./it.json";
|
||||||
import ja from './ja.json'
|
import ja from "./ja.json";
|
||||||
import ko from './ko.json'
|
import ko from "./ko.json";
|
||||||
import nlBE from './nl-be.json'
|
import nlBE from "./nl-be.json";
|
||||||
import pl from './pl.json'
|
import pl from "./pl.json";
|
||||||
import pt from './pt.json'
|
import pt from "./pt.json";
|
||||||
import ptBR from './pt-br.json'
|
import ptBR from "./pt-br.json";
|
||||||
import ro from './ro.json'
|
import ro from "./ro.json";
|
||||||
import ru from './ru.json'
|
import ru from "./ru.json";
|
||||||
import svSE from './sv-se.json'
|
import svSE from "./sv-se.json";
|
||||||
import zhCN from './zh-cn.json'
|
import zhCN from "./zh-cn.json";
|
||||||
import zhTW from './zh-tw.json'
|
import zhTW from "./zh-tw.json";
|
||||||
|
|
||||||
Vue.use(VueI18n)
|
Vue.use(VueI18n);
|
||||||
|
|
||||||
export function detectLocale () {
|
export function detectLocale() {
|
||||||
let locale = (navigator.language || navigator.browserLangugae).toLowerCase()
|
let locale = (navigator.language || navigator.browserLangugae).toLowerCase();
|
||||||
switch (true) {
|
switch (true) {
|
||||||
case /^ar.*/i.test(locale):
|
case /^ar.*/i.test(locale):
|
||||||
locale = 'ar'
|
locale = "ar";
|
||||||
break
|
break;
|
||||||
case /^es.*/i.test(locale):
|
case /^es.*/i.test(locale):
|
||||||
locale = 'es'
|
locale = "es";
|
||||||
break
|
break;
|
||||||
case /^en.*/i.test(locale):
|
case /^en.*/i.test(locale):
|
||||||
locale = 'en'
|
locale = "en";
|
||||||
break
|
break;
|
||||||
case /^it.*/i.test(locale):
|
case /^it.*/i.test(locale):
|
||||||
locale = 'it'
|
locale = "it";
|
||||||
break
|
break;
|
||||||
case /^fr.*/i.test(locale):
|
case /^fr.*/i.test(locale):
|
||||||
locale = 'fr'
|
locale = "fr";
|
||||||
break
|
break;
|
||||||
case /^pt.*/i.test(locale):
|
case /^pt.*/i.test(locale):
|
||||||
locale = 'pt'
|
locale = "pt";
|
||||||
break
|
break;
|
||||||
case /^pt-BR.*/i.test(locale):
|
case /^pt-BR.*/i.test(locale):
|
||||||
locale = 'pt-br'
|
locale = "pt-br";
|
||||||
break
|
break;
|
||||||
case /^ja.*/i.test(locale):
|
case /^ja.*/i.test(locale):
|
||||||
locale = 'ja'
|
locale = "ja";
|
||||||
break
|
break;
|
||||||
case /^zh-CN/i.test(locale):
|
case /^zh-CN/i.test(locale):
|
||||||
locale = 'zh-cn'
|
locale = "zh-cn";
|
||||||
break
|
break;
|
||||||
case /^zh-TW/i.test(locale):
|
case /^zh-TW/i.test(locale):
|
||||||
locale = 'zh-tw'
|
locale = "zh-tw";
|
||||||
break
|
break;
|
||||||
case /^zh.*/i.test(locale):
|
case /^zh.*/i.test(locale):
|
||||||
locale = 'zh-cn'
|
locale = "zh-cn";
|
||||||
break
|
break;
|
||||||
case /^de.*/i.test(locale):
|
case /^de.*/i.test(locale):
|
||||||
locale = 'de'
|
locale = "de";
|
||||||
break
|
break;
|
||||||
case /^ru.*/i.test(locale):
|
case /^ru.*/i.test(locale):
|
||||||
locale = 'ru'
|
locale = "ru";
|
||||||
break
|
break;
|
||||||
case /^pl.*/i.test(locale):
|
case /^pl.*/i.test(locale):
|
||||||
locale = 'pl'
|
locale = "pl";
|
||||||
break
|
break;
|
||||||
case /^ko.*/i.test(locale):
|
case /^ko.*/i.test(locale):
|
||||||
locale = 'ko'
|
locale = "ko";
|
||||||
break
|
break;
|
||||||
default:
|
default:
|
||||||
locale = 'en'
|
locale = "en";
|
||||||
}
|
}
|
||||||
|
|
||||||
return locale
|
return locale;
|
||||||
}
|
}
|
||||||
|
|
||||||
const removeEmpty = (obj) =>
|
const removeEmpty = (obj) =>
|
||||||
Object.keys(obj)
|
Object.keys(obj)
|
||||||
.filter((k) => obj[k] !== null && obj[k] !== undefined && obj[k] !== '') // Remove undef. and null and empty.string.
|
.filter((k) => obj[k] !== null && obj[k] !== undefined && obj[k] !== "") // Remove undef. and null and empty.string.
|
||||||
.reduce(
|
.reduce(
|
||||||
(newObj, k) =>
|
(newObj, k) =>
|
||||||
typeof obj[k] === 'object'
|
typeof obj[k] === "object"
|
||||||
? Object.assign(newObj, { [k]: removeEmpty(obj[k]) }) // Recurse.
|
? Object.assign(newObj, { [k]: removeEmpty(obj[k]) }) // Recurse.
|
||||||
: Object.assign(newObj, { [k]: obj[k] }), // Copy value.
|
: Object.assign(newObj, { [k]: obj[k] }), // Copy value.
|
||||||
{},
|
{}
|
||||||
);
|
);
|
||||||
|
|
||||||
const i18n = new VueI18n({
|
const i18n = new VueI18n({
|
||||||
locale: detectLocale(),
|
locale: detectLocale(),
|
||||||
fallbackLocale: 'en',
|
fallbackLocale: "en",
|
||||||
messages: {
|
messages: {
|
||||||
'ar': removeEmpty(ar),
|
ar: removeEmpty(ar),
|
||||||
'de': removeEmpty(de),
|
de: removeEmpty(de),
|
||||||
'en': en,
|
en: en,
|
||||||
'es': removeEmpty(es),
|
es: removeEmpty(es),
|
||||||
'fr': removeEmpty(fr),
|
fr: removeEmpty(fr),
|
||||||
'is': removeEmpty(is),
|
is: removeEmpty(is),
|
||||||
'it': removeEmpty(it),
|
it: removeEmpty(it),
|
||||||
'ja': removeEmpty(ja),
|
ja: removeEmpty(ja),
|
||||||
'ko': removeEmpty(ko),
|
ko: removeEmpty(ko),
|
||||||
'nl-be': removeEmpty(nlBE),
|
"nl-be": removeEmpty(nlBE),
|
||||||
'pl': removeEmpty(pl),
|
pl: removeEmpty(pl),
|
||||||
'pt-br': removeEmpty(ptBR),
|
"pt-br": removeEmpty(ptBR),
|
||||||
'pt': removeEmpty(pt),
|
pt: removeEmpty(pt),
|
||||||
'ru': removeEmpty(ru),
|
ru: removeEmpty(ru),
|
||||||
'ro': removeEmpty(ro),
|
ro: removeEmpty(ro),
|
||||||
'sv-se': removeEmpty(svSE),
|
"sv-se": removeEmpty(svSE),
|
||||||
'zh-cn': removeEmpty(zhCN),
|
"zh-cn": removeEmpty(zhCN),
|
||||||
'zh-tw': removeEmpty(zhTW)
|
"zh-tw": removeEmpty(zhTW),
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
export default i18n
|
export default i18n;
|
||||||
|
|
|
@ -1,43 +1,43 @@
|
||||||
import { sync } from 'vuex-router-sync'
|
import { sync } from "vuex-router-sync";
|
||||||
import store from '@/store'
|
import store from "@/store";
|
||||||
import router from '@/router'
|
import router from "@/router";
|
||||||
import i18n from '@/i18n'
|
import i18n from "@/i18n";
|
||||||
import Vue from '@/utils/vue'
|
import Vue from "@/utils/vue";
|
||||||
import { recaptcha, loginPage } from '@/utils/constants'
|
import { recaptcha, loginPage } from "@/utils/constants";
|
||||||
import { login, validateLogin } from '@/utils/auth'
|
import { login, validateLogin } from "@/utils/auth";
|
||||||
import App from '@/App'
|
import App from "@/App";
|
||||||
|
|
||||||
sync(store, router)
|
sync(store, router);
|
||||||
|
|
||||||
async function start () {
|
async function start() {
|
||||||
if (loginPage) {
|
if (loginPage) {
|
||||||
await validateLogin()
|
await validateLogin();
|
||||||
} else {
|
} else {
|
||||||
await login('', '', '')
|
await login("", "", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recaptcha) {
|
if (recaptcha) {
|
||||||
await new Promise (resolve => {
|
await new Promise((resolve) => {
|
||||||
const check = () => {
|
const check = () => {
|
||||||
if (typeof window.grecaptcha === 'undefined') {
|
if (typeof window.grecaptcha === "undefined") {
|
||||||
setTimeout(check, 100)
|
setTimeout(check, 100);
|
||||||
} else {
|
} else {
|
||||||
resolve()
|
resolve();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
check()
|
check();
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
new Vue({
|
new Vue({
|
||||||
el: '#app',
|
el: "#app",
|
||||||
store,
|
store,
|
||||||
router,
|
router,
|
||||||
i18n,
|
i18n,
|
||||||
template: '<App/>',
|
template: "<App/>",
|
||||||
components: { App }
|
components: { App },
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
start()
|
start();
|
||||||
|
|
|
@ -1,166 +1,166 @@
|
||||||
import Vue from 'vue'
|
import Vue from "vue";
|
||||||
import Router from 'vue-router'
|
import Router from "vue-router";
|
||||||
import Login from '@/views/Login'
|
import Login from "@/views/Login";
|
||||||
import Layout from '@/views/Layout'
|
import Layout from "@/views/Layout";
|
||||||
import Files from '@/views/Files'
|
import Files from "@/views/Files";
|
||||||
import Share from '@/views/Share'
|
import Share from "@/views/Share";
|
||||||
import Users from '@/views/settings/Users'
|
import Users from "@/views/settings/Users";
|
||||||
import User from '@/views/settings/User'
|
import User from "@/views/settings/User";
|
||||||
import Settings from '@/views/Settings'
|
import Settings from "@/views/Settings";
|
||||||
import GlobalSettings from '@/views/settings/Global'
|
import GlobalSettings from "@/views/settings/Global";
|
||||||
import ProfileSettings from '@/views/settings/Profile'
|
import ProfileSettings from "@/views/settings/Profile";
|
||||||
import Shares from '@/views/settings/Shares'
|
import Shares from "@/views/settings/Shares";
|
||||||
import Errors from '@/views/Errors'
|
import Errors from "@/views/Errors";
|
||||||
import store from '@/store'
|
import store from "@/store";
|
||||||
import { baseURL } from '@/utils/constants'
|
import { baseURL } from "@/utils/constants";
|
||||||
|
|
||||||
Vue.use(Router)
|
Vue.use(Router);
|
||||||
|
|
||||||
const router = new Router({
|
const router = new Router({
|
||||||
base: baseURL,
|
base: baseURL,
|
||||||
mode: 'history',
|
mode: "history",
|
||||||
routes: [
|
routes: [
|
||||||
{
|
{
|
||||||
path: '/login',
|
path: "/login",
|
||||||
name: 'Login',
|
name: "Login",
|
||||||
component: Login,
|
component: Login,
|
||||||
beforeEnter: (to, from, next) => {
|
beforeEnter: (to, from, next) => {
|
||||||
if (store.getters.isLogged) {
|
if (store.getters.isLogged) {
|
||||||
return next({ path: '/files' })
|
return next({ path: "/files" });
|
||||||
}
|
}
|
||||||
|
|
||||||
document.title = 'Login'
|
document.title = "Login";
|
||||||
next()
|
next();
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/*',
|
path: "/*",
|
||||||
component: Layout,
|
component: Layout,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/share/*',
|
path: "/share/*",
|
||||||
name: 'Share',
|
name: "Share",
|
||||||
component: Share
|
component: Share,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/files/*',
|
path: "/files/*",
|
||||||
name: 'Files',
|
name: "Files",
|
||||||
component: Files,
|
component: Files,
|
||||||
meta: {
|
meta: {
|
||||||
requiresAuth: true
|
requiresAuth: true,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/settings',
|
path: "/settings",
|
||||||
name: 'Settings',
|
name: "Settings",
|
||||||
component: Settings,
|
component: Settings,
|
||||||
redirect: {
|
redirect: {
|
||||||
path: '/settings/profile'
|
path: "/settings/profile",
|
||||||
},
|
},
|
||||||
meta: {
|
meta: {
|
||||||
requiresAuth: true
|
requiresAuth: true,
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/settings/profile',
|
path: "/settings/profile",
|
||||||
name: 'Profile Settings',
|
name: "Profile Settings",
|
||||||
component: ProfileSettings
|
component: ProfileSettings,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/settings/shares',
|
path: "/settings/shares",
|
||||||
name: 'Shares',
|
name: "Shares",
|
||||||
component: Shares
|
component: Shares,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/settings/global',
|
path: "/settings/global",
|
||||||
name: 'Global Settings',
|
name: "Global Settings",
|
||||||
component: GlobalSettings,
|
component: GlobalSettings,
|
||||||
meta: {
|
meta: {
|
||||||
requiresAdmin: true
|
requiresAdmin: true,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/settings/users',
|
path: "/settings/users",
|
||||||
name: 'Users',
|
name: "Users",
|
||||||
component: Users,
|
component: Users,
|
||||||
meta: {
|
meta: {
|
||||||
requiresAdmin: true
|
requiresAdmin: true,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/settings/users/*',
|
path: "/settings/users/*",
|
||||||
name: 'User',
|
name: "User",
|
||||||
component: User,
|
component: User,
|
||||||
meta: {
|
meta: {
|
||||||
requiresAdmin: true
|
requiresAdmin: true,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/403',
|
path: "/403",
|
||||||
name: 'Forbidden',
|
name: "Forbidden",
|
||||||
component: Errors,
|
component: Errors,
|
||||||
props: {
|
props: {
|
||||||
errorCode: 403,
|
errorCode: 403,
|
||||||
showHeader: true
|
showHeader: true,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/404',
|
path: "/404",
|
||||||
name: 'Not Found',
|
name: "Not Found",
|
||||||
component: Errors,
|
component: Errors,
|
||||||
props: {
|
props: {
|
||||||
errorCode: 404,
|
errorCode: 404,
|
||||||
showHeader: true
|
showHeader: true,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/500',
|
path: "/500",
|
||||||
name: 'Internal Server Error',
|
name: "Internal Server Error",
|
||||||
component: Errors,
|
component: Errors,
|
||||||
props: {
|
props: {
|
||||||
errorCode: 500,
|
errorCode: 500,
|
||||||
showHeader: true
|
showHeader: true,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/files',
|
path: "/files",
|
||||||
redirect: {
|
redirect: {
|
||||||
path: '/files/'
|
path: "/files/",
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/*',
|
path: "/*",
|
||||||
redirect: to => `/files${to.path}`
|
redirect: (to) => `/files${to.path}`,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
})
|
});
|
||||||
|
|
||||||
router.beforeEach((to, from, next) => {
|
router.beforeEach((to, from, next) => {
|
||||||
document.title = to.name
|
document.title = to.name;
|
||||||
|
|
||||||
if (to.matched.some(record => record.meta.requiresAuth)) {
|
if (to.matched.some((record) => record.meta.requiresAuth)) {
|
||||||
if (!store.getters.isLogged) {
|
if (!store.getters.isLogged) {
|
||||||
next({
|
next({
|
||||||
path: '/login',
|
path: "/login",
|
||||||
query: { redirect: to.fullPath }
|
query: { redirect: to.fullPath },
|
||||||
})
|
});
|
||||||
|
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (to.matched.some(record => record.meta.requiresAdmin)) {
|
if (to.matched.some((record) => record.meta.requiresAdmin)) {
|
||||||
if (!store.state.user.perm.admin) {
|
if (!store.state.user.perm.admin) {
|
||||||
next({ path: '/403' })
|
next({ path: "/403" });
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
next()
|
next();
|
||||||
})
|
});
|
||||||
|
|
||||||
export default router
|
export default router;
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
const getters = {
|
const getters = {
|
||||||
isLogged: state => state.user !== null,
|
isLogged: (state) => state.user !== null,
|
||||||
isFiles: state => !state.loading && state.route.name === 'Files',
|
isFiles: (state) => !state.loading && state.route.name === "Files",
|
||||||
isListing: (state, getters) => getters.isFiles && state.req.isDir,
|
isListing: (state, getters) => getters.isFiles && state.req.isDir,
|
||||||
selectedCount: state => state.selected.length,
|
selectedCount: (state) => state.selected.length,
|
||||||
progress : state => {
|
progress: (state) => {
|
||||||
if (state.upload.progress.length == 0) {
|
if (state.upload.progress.length == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let sum = state.upload.progress.reduce((acc, val) => acc + val)
|
let sum = state.upload.progress.reduce((acc, val) => acc + val);
|
||||||
return Math.ceil(sum / state.upload.size * 100);
|
return Math.ceil((sum / state.upload.size) * 100);
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
export default getters
|
export default getters;
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
import Vue from 'vue'
|
import Vue from "vue";
|
||||||
import Vuex from 'vuex'
|
import Vuex from "vuex";
|
||||||
import mutations from './mutations'
|
import mutations from "./mutations";
|
||||||
import getters from './getters'
|
import getters from "./getters";
|
||||||
import upload from './modules/upload'
|
import upload from "./modules/upload";
|
||||||
|
|
||||||
Vue.use(Vuex)
|
Vue.use(Vuex);
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
user: null,
|
user: null,
|
||||||
req: {},
|
req: {},
|
||||||
oldReq: {},
|
oldReq: {},
|
||||||
clipboard: {
|
clipboard: {
|
||||||
key: '',
|
key: "",
|
||||||
items: []
|
items: [],
|
||||||
},
|
},
|
||||||
jwt: '',
|
jwt: "",
|
||||||
progress: 0,
|
progress: 0,
|
||||||
loading: false,
|
loading: false,
|
||||||
reload: false,
|
reload: false,
|
||||||
|
@ -22,13 +22,13 @@ const state = {
|
||||||
multiple: false,
|
multiple: false,
|
||||||
show: null,
|
show: null,
|
||||||
showShell: false,
|
showShell: false,
|
||||||
showConfirm: null
|
showConfirm: null,
|
||||||
}
|
};
|
||||||
|
|
||||||
export default new Vuex.Store({
|
export default new Vuex.Store({
|
||||||
strict: true,
|
strict: true,
|
||||||
state,
|
state,
|
||||||
getters,
|
getters,
|
||||||
mutations,
|
mutations,
|
||||||
modules: { upload }
|
modules: { upload },
|
||||||
})
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import Vue from 'vue'
|
import Vue from "vue";
|
||||||
import { files as api } from '@/api'
|
import { files as api } from "@/api";
|
||||||
import throttle from 'lodash.throttle'
|
import throttle from "lodash.throttle";
|
||||||
import buttons from '@/utils/buttons'
|
import buttons from "@/utils/buttons";
|
||||||
|
|
||||||
const UPLOADS_LIMIT = 5;
|
const UPLOADS_LIMIT = 5;
|
||||||
|
|
||||||
|
@ -10,93 +10,100 @@ const state = {
|
||||||
size: 0,
|
size: 0,
|
||||||
progress: [],
|
progress: [],
|
||||||
queue: [],
|
queue: [],
|
||||||
uploads: {}
|
uploads: {},
|
||||||
}
|
};
|
||||||
|
|
||||||
const mutations = {
|
const mutations = {
|
||||||
setProgress(state, { id, loaded }) {
|
setProgress(state, { id, loaded }) {
|
||||||
Vue.set(state.progress, id, loaded)
|
Vue.set(state.progress, id, loaded);
|
||||||
},
|
},
|
||||||
reset: (state) => {
|
reset: (state) => {
|
||||||
state.id = 0
|
state.id = 0;
|
||||||
state.size = 0
|
state.size = 0;
|
||||||
state.progress = []
|
state.progress = [];
|
||||||
},
|
},
|
||||||
addJob: (state, item) => {
|
addJob: (state, item) => {
|
||||||
state.queue.push(item)
|
state.queue.push(item);
|
||||||
state.size += item.file.size
|
state.size += item.file.size;
|
||||||
state.id++
|
state.id++;
|
||||||
},
|
},
|
||||||
moveJob(state) {
|
moveJob(state) {
|
||||||
const item = state.queue[0]
|
const item = state.queue[0];
|
||||||
state.queue.shift()
|
state.queue.shift();
|
||||||
Vue.set(state.uploads, item.id, item)
|
Vue.set(state.uploads, item.id, item);
|
||||||
},
|
},
|
||||||
removeJob(state, id) {
|
removeJob(state, id) {
|
||||||
delete state.uploads[id]
|
delete state.uploads[id];
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
const beforeUnload = (event) => {
|
const beforeUnload = (event) => {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
event.returnValue = ''
|
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;
|
||||||
|
|
||||||
let isQueueEmpty = context.state.queue.length == 0
|
let isQueueEmpty = context.state.queue.length == 0;
|
||||||
let isUploadsEmpty = uploadsCount == 0
|
let isUploadsEmpty = uploadsCount == 0;
|
||||||
|
|
||||||
if (isQueueEmpty && isUploadsEmpty) {
|
if (isQueueEmpty && isUploadsEmpty) {
|
||||||
window.addEventListener('beforeunload', beforeUnload)
|
window.addEventListener("beforeunload", beforeUnload);
|
||||||
buttons.loading('upload')
|
buttons.loading("upload");
|
||||||
}
|
}
|
||||||
|
|
||||||
context.commit('addJob', item)
|
context.commit("addJob", item);
|
||||||
context.dispatch('processUploads')
|
context.dispatch("processUploads");
|
||||||
},
|
},
|
||||||
finishUpload: (context, item) => {
|
finishUpload: (context, item) => {
|
||||||
context.commit('setProgress', { id: item.id, loaded: item.file.size })
|
context.commit("setProgress", { id: item.id, loaded: item.file.size });
|
||||||
context.commit('removeJob', item.id)
|
context.commit("removeJob", item.id);
|
||||||
context.dispatch('processUploads')
|
context.dispatch("processUploads");
|
||||||
},
|
},
|
||||||
processUploads: async (context) => {
|
processUploads: async (context) => {
|
||||||
let uploadsCount = Object.keys(context.state.uploads).length;
|
let uploadsCount = Object.keys(context.state.uploads).length;
|
||||||
|
|
||||||
let isBellowLimit = uploadsCount < UPLOADS_LIMIT
|
let isBellowLimit = uploadsCount < UPLOADS_LIMIT;
|
||||||
let isQueueEmpty = context.state.queue.length == 0
|
let isQueueEmpty = context.state.queue.length == 0;
|
||||||
let isUploadsEmpty = uploadsCount == 0
|
let isUploadsEmpty = uploadsCount == 0;
|
||||||
|
|
||||||
let isFinished = isQueueEmpty && isUploadsEmpty
|
let isFinished = isQueueEmpty && isUploadsEmpty;
|
||||||
let canProcess = isBellowLimit && !isQueueEmpty
|
let canProcess = isBellowLimit && !isQueueEmpty;
|
||||||
|
|
||||||
if (isFinished) {
|
if (isFinished) {
|
||||||
window.removeEventListener('beforeunload', beforeUnload)
|
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 });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canProcess) {
|
if (canProcess) {
|
||||||
const item = context.state.queue[0];
|
const item = context.state.queue[0];
|
||||||
context.commit('moveJob')
|
context.commit("moveJob");
|
||||||
|
|
||||||
if (item.file.isDir) {
|
if (item.file.isDir) {
|
||||||
await api.post(item.path).catch(Vue.prototype.$showError)
|
await api.post(item.path).catch(Vue.prototype.$showError);
|
||||||
} else {
|
} else {
|
||||||
let onUpload = throttle(
|
let onUpload = throttle(
|
||||||
(event) => context.commit('setProgress', { id: item.id, loaded: event.loaded }),
|
(event) =>
|
||||||
100, { leading: true, trailing: false }
|
context.commit("setProgress", {
|
||||||
)
|
id: item.id,
|
||||||
|
loaded: event.loaded,
|
||||||
|
}),
|
||||||
|
100,
|
||||||
|
{ leading: true, trailing: false }
|
||||||
|
);
|
||||||
|
|
||||||
await api.post(item.path, item.file, item.overwrite, onUpload).catch(Vue.prototype.$showError)
|
await api
|
||||||
|
.post(item.path, item.file, item.overwrite, onUpload)
|
||||||
|
.catch(Vue.prototype.$showError);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.dispatch('finishUpload', item)
|
context.dispatch("finishUpload", item);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
export default { state, mutations, actions, namespaced: true }
|
export default { state, mutations, actions, namespaced: true };
|
||||||
|
|
|
@ -1,83 +1,87 @@
|
||||||
import * as i18n from '@/i18n'
|
import * as i18n from "@/i18n";
|
||||||
import moment from 'moment'
|
import moment from "moment";
|
||||||
|
|
||||||
const mutations = {
|
const mutations = {
|
||||||
closeHovers: state => {
|
closeHovers: (state) => {
|
||||||
state.show = null
|
state.show = null;
|
||||||
state.showConfirm = null
|
state.showConfirm = null;
|
||||||
},
|
},
|
||||||
toggleShell: (state) => {
|
toggleShell: (state) => {
|
||||||
state.showShell = !state.showShell
|
state.showShell = !state.showShell;
|
||||||
},
|
},
|
||||||
showHover: (state, value) => {
|
showHover: (state, value) => {
|
||||||
if (typeof value !== 'object') {
|
if (typeof value !== "object") {
|
||||||
state.show = value
|
state.show = value;
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.show = value.prompt
|
state.show = value.prompt;
|
||||||
state.showConfirm = value.confirm
|
state.showConfirm = value.confirm;
|
||||||
},
|
},
|
||||||
showError: (state) => {
|
showError: (state) => {
|
||||||
state.show = 'error'
|
state.show = "error";
|
||||||
},
|
},
|
||||||
showSuccess: (state) => {
|
showSuccess: (state) => {
|
||||||
state.show = 'success'
|
state.show = "success";
|
||||||
|
},
|
||||||
|
setLoading: (state, value) => {
|
||||||
|
state.loading = value;
|
||||||
|
},
|
||||||
|
setReload: (state, value) => {
|
||||||
|
state.reload = value;
|
||||||
},
|
},
|
||||||
setLoading: (state, value) => { state.loading = value },
|
|
||||||
setReload: (state, value) => { state.reload = value },
|
|
||||||
setUser: (state, value) => {
|
setUser: (state, value) => {
|
||||||
if (value === null) {
|
if (value === null) {
|
||||||
state.user = null
|
state.user = null;
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let locale = value.locale
|
let locale = value.locale;
|
||||||
|
|
||||||
if (locale === '') {
|
if (locale === "") {
|
||||||
locale = i18n.detectLocale()
|
locale = i18n.detectLocale();
|
||||||
}
|
}
|
||||||
|
|
||||||
moment.locale(locale)
|
moment.locale(locale);
|
||||||
i18n.default.locale = locale
|
i18n.default.locale = locale;
|
||||||
state.user = value
|
state.user = value;
|
||||||
},
|
},
|
||||||
setJWT: (state, value) => (state.jwt = value),
|
setJWT: (state, value) => (state.jwt = value),
|
||||||
multiple: (state, value) => (state.multiple = value),
|
multiple: (state, value) => (state.multiple = value),
|
||||||
addSelected: (state, value) => (state.selected.push(value)),
|
addSelected: (state, value) => state.selected.push(value),
|
||||||
removeSelected: (state, value) => {
|
removeSelected: (state, value) => {
|
||||||
let i = state.selected.indexOf(value)
|
let i = state.selected.indexOf(value);
|
||||||
if (i === -1) return
|
if (i === -1) return;
|
||||||
state.selected.splice(i, 1)
|
state.selected.splice(i, 1);
|
||||||
},
|
},
|
||||||
resetSelected: (state) => {
|
resetSelected: (state) => {
|
||||||
state.selected = []
|
state.selected = [];
|
||||||
},
|
},
|
||||||
updateUser: (state, value) => {
|
updateUser: (state, value) => {
|
||||||
if (typeof value !== 'object') return
|
if (typeof value !== "object") return;
|
||||||
|
|
||||||
for (let field in value) {
|
for (let field in value) {
|
||||||
if (field === 'locale') {
|
if (field === "locale") {
|
||||||
moment.locale(value[field])
|
moment.locale(value[field]);
|
||||||
i18n.default.locale = value[field]
|
i18n.default.locale = value[field];
|
||||||
}
|
}
|
||||||
|
|
||||||
state.user[field] = value[field]
|
state.user[field] = value[field];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
updateRequest: (state, value) => {
|
updateRequest: (state, value) => {
|
||||||
state.oldReq = state.req
|
state.oldReq = state.req;
|
||||||
state.req = value
|
state.req = value;
|
||||||
},
|
},
|
||||||
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
|
state.clipboard.path = value.path;
|
||||||
},
|
},
|
||||||
resetClipboard: (state) => {
|
resetClipboard: (state) => {
|
||||||
state.clipboard.key = ''
|
state.clipboard.key = "";
|
||||||
state.clipboard.items = []
|
state.clipboard.items = [];
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
export default mutations
|
export default mutations;
|
||||||
|
|
|
@ -1,88 +1,88 @@
|
||||||
import store from '@/store'
|
import store from "@/store";
|
||||||
import router from '@/router'
|
import router from "@/router";
|
||||||
import { Base64 } from 'js-base64'
|
import { Base64 } from "js-base64";
|
||||||
import { baseURL } from '@/utils/constants'
|
import { baseURL } from "@/utils/constants";
|
||||||
|
|
||||||
export function parseToken (token) {
|
export function parseToken(token) {
|
||||||
const parts = token.split('.')
|
const parts = token.split(".");
|
||||||
|
|
||||||
if (parts.length !== 3) {
|
if (parts.length !== 3) {
|
||||||
throw new Error('token malformed')
|
throw new Error("token malformed");
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = JSON.parse(Base64.decode(parts[1]))
|
const data = JSON.parse(Base64.decode(parts[1]));
|
||||||
|
|
||||||
localStorage.setItem('jwt', token)
|
localStorage.setItem("jwt", token);
|
||||||
store.commit('setJWT', token)
|
store.commit("setJWT", token);
|
||||||
store.commit('setUser', data.user)
|
store.commit("setUser", data.user);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function validateLogin () {
|
export async function validateLogin() {
|
||||||
try {
|
try {
|
||||||
if (localStorage.getItem('jwt')) {
|
if (localStorage.getItem("jwt")) {
|
||||||
await renew(localStorage.getItem('jwt'))
|
await renew(localStorage.getItem("jwt"));
|
||||||
}
|
}
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
console.warn('Invalid JWT token in storage') // eslint-disable-line
|
console.warn('Invalid JWT token in storage') // eslint-disable-line
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function login (username, password, recaptcha) {
|
export async function login(username, password, recaptcha) {
|
||||||
const data = { username, password, recaptcha }
|
const data = { username, password, recaptcha };
|
||||||
|
|
||||||
const res = await fetch(`${baseURL}/api/login`, {
|
const res = await fetch(`${baseURL}/api/login`, {
|
||||||
method: 'POST',
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify(data)
|
body: JSON.stringify(data),
|
||||||
})
|
});
|
||||||
|
|
||||||
const body = await res.text()
|
const body = await res.text();
|
||||||
|
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
parseToken(body)
|
parseToken(body);
|
||||||
} else {
|
} else {
|
||||||
throw new Error(body)
|
throw new Error(body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function renew (jwt) {
|
export async function renew(jwt) {
|
||||||
const res = await fetch(`${baseURL}/api/renew`, {
|
const res = await fetch(`${baseURL}/api/renew`, {
|
||||||
method: 'POST',
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
'X-Auth': jwt,
|
"X-Auth": jwt,
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
const body = await res.text()
|
const body = await res.text();
|
||||||
|
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
parseToken(body)
|
parseToken(body);
|
||||||
} else {
|
} else {
|
||||||
throw new Error(body)
|
throw new Error(body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function signup (username, password) {
|
export async function signup(username, password) {
|
||||||
const data = { username, password }
|
const data = { username, password };
|
||||||
|
|
||||||
const res = await fetch(`${baseURL}/api/signup`, {
|
const res = await fetch(`${baseURL}/api/signup`, {
|
||||||
method: 'POST',
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify(data)
|
body: JSON.stringify(data),
|
||||||
})
|
});
|
||||||
|
|
||||||
if (res.status !== 200) {
|
if (res.status !== 200) {
|
||||||
throw new Error(res.status)
|
throw new Error(res.status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function logout () {
|
export function logout() {
|
||||||
store.commit('setJWT', '')
|
store.commit("setJWT", "");
|
||||||
store.commit('setUser', null)
|
store.commit("setUser", null);
|
||||||
localStorage.setItem('jwt', null)
|
localStorage.setItem("jwt", null);
|
||||||
router.push({path: '/login'})
|
router.push({ path: "/login" });
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,70 +1,70 @@
|
||||||
function loading (button) {
|
function loading(button) {
|
||||||
let el = document.querySelector(`#${button}-button > i`)
|
let el = document.querySelector(`#${button}-button > i`);
|
||||||
|
|
||||||
if (el === undefined || el === null) {
|
if (el === undefined || el === null) {
|
||||||
console.log('Error getting button ' + button) // eslint-disable-line
|
console.log('Error getting button ' + button) // eslint-disable-line
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (el.innerHTML == 'autorenew' || el.innerHTML == 'done') {
|
if (el.innerHTML == "autorenew" || el.innerHTML == "done") {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
el.dataset.icon = el.innerHTML
|
el.dataset.icon = el.innerHTML;
|
||||||
el.style.opacity = 0
|
el.style.opacity = 0;
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
el.classList.add('spin')
|
el.classList.add("spin");
|
||||||
el.innerHTML = 'autorenew'
|
el.innerHTML = "autorenew";
|
||||||
el.style.opacity = 1
|
el.style.opacity = 1;
|
||||||
}, 100)
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
function done (button) {
|
function done(button) {
|
||||||
let el = document.querySelector(`#${button}-button > i`)
|
let el = document.querySelector(`#${button}-button > i`);
|
||||||
|
|
||||||
if (el === undefined || el === null) {
|
if (el === undefined || el === null) {
|
||||||
console.log('Error getting button ' + button) // eslint-disable-line
|
console.log('Error getting button ' + button) // eslint-disable-line
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
el.style.opacity = 0
|
el.style.opacity = 0;
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
el.classList.remove('spin')
|
el.classList.remove("spin");
|
||||||
el.innerHTML = el.dataset.icon
|
el.innerHTML = el.dataset.icon;
|
||||||
el.style.opacity = 1
|
el.style.opacity = 1;
|
||||||
}, 100)
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
function success (button) {
|
function success(button) {
|
||||||
let el = document.querySelector(`#${button}-button > i`)
|
let el = document.querySelector(`#${button}-button > i`);
|
||||||
|
|
||||||
if (el === undefined || el === null) {
|
if (el === undefined || el === null) {
|
||||||
console.log('Error getting button ' + button) // eslint-disable-line
|
console.log('Error getting button ' + button) // eslint-disable-line
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
el.style.opacity = 0
|
el.style.opacity = 0;
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
el.classList.remove('spin')
|
el.classList.remove("spin");
|
||||||
el.innerHTML = 'done'
|
el.innerHTML = "done";
|
||||||
el.style.opacity = 1
|
el.style.opacity = 1;
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
el.style.opacity = 0
|
el.style.opacity = 0;
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
el.innerHTML = el.dataset.icon
|
el.innerHTML = el.dataset.icon;
|
||||||
el.style.opacity = 1
|
el.style.opacity = 1;
|
||||||
}, 100)
|
}, 100);
|
||||||
}, 500)
|
}, 500);
|
||||||
}, 100)
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
loading,
|
loading,
|
||||||
done,
|
done,
|
||||||
success
|
success,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
const name = window.FileBrowser.Name || 'File Browser'
|
const name = window.FileBrowser.Name || "File Browser";
|
||||||
const disableExternal = window.FileBrowser.DisableExternal
|
const disableExternal = window.FileBrowser.DisableExternal;
|
||||||
const baseURL = window.FileBrowser.BaseURL
|
const baseURL = window.FileBrowser.BaseURL;
|
||||||
const staticURL = window.FileBrowser.StaticURL
|
const staticURL = window.FileBrowser.StaticURL;
|
||||||
const recaptcha = window.FileBrowser.ReCaptcha
|
const recaptcha = window.FileBrowser.ReCaptcha;
|
||||||
const recaptchaKey = window.FileBrowser.ReCaptchaKey
|
const recaptchaKey = window.FileBrowser.ReCaptchaKey;
|
||||||
const signup = window.FileBrowser.Signup
|
const signup = window.FileBrowser.Signup;
|
||||||
const version = window.FileBrowser.Version
|
const version = window.FileBrowser.Version;
|
||||||
const logoURL = `${staticURL}/img/logo.svg`
|
const logoURL = `${staticURL}/img/logo.svg`;
|
||||||
const noAuth = window.FileBrowser.NoAuth
|
const noAuth = window.FileBrowser.NoAuth;
|
||||||
const authMethod = window.FileBrowser.AuthMethod
|
const authMethod = window.FileBrowser.AuthMethod;
|
||||||
const loginPage = window.FileBrowser.LoginPage
|
const loginPage = window.FileBrowser.LoginPage;
|
||||||
const theme = window.FileBrowser.Theme
|
const theme = window.FileBrowser.Theme;
|
||||||
const enableThumbs = window.FileBrowser.EnableThumbs
|
const enableThumbs = window.FileBrowser.EnableThumbs;
|
||||||
const resizePreview = window.FileBrowser.ResizePreview
|
const resizePreview = window.FileBrowser.ResizePreview;
|
||||||
const enableExec = window.FileBrowser.EnableExec
|
const enableExec = window.FileBrowser.EnableExec;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
name,
|
name,
|
||||||
|
@ -30,5 +30,5 @@ export {
|
||||||
theme,
|
theme,
|
||||||
enableThumbs,
|
enableThumbs,
|
||||||
resizePreview,
|
resizePreview,
|
||||||
enableExec
|
enableExec,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
export default function (name) {
|
export default function (name) {
|
||||||
let re = new RegExp('(?:(?:^|.*;\\s*)' + name + '\\s*\\=\\s*([^;]*).*$)|^.*$')
|
let re = new RegExp(
|
||||||
return document.cookie.replace(re, '$1')
|
"(?:(?:^|.*;\\s*)" + name + "\\s*\\=\\s*([^;]*).*$)|^.*$"
|
||||||
|
);
|
||||||
|
return document.cookie.replace(re, "$1");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +1,28 @@
|
||||||
export default function getRule (rules) {
|
export default function getRule(rules) {
|
||||||
for (let i = 0; i < rules.length; i++) {
|
for (let i = 0; i < rules.length; i++) {
|
||||||
rules[i] = rules[i].toLowerCase()
|
rules[i] = rules[i].toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = null
|
let result = null;
|
||||||
let find = Array.prototype.find
|
let find = Array.prototype.find;
|
||||||
|
|
||||||
find.call(document.styleSheets, styleSheet => {
|
find.call(document.styleSheets, (styleSheet) => {
|
||||||
result = find.call(styleSheet.cssRules, cssRule => {
|
result = find.call(styleSheet.cssRules, (cssRule) => {
|
||||||
let found = false
|
let found = false;
|
||||||
|
|
||||||
if (cssRule instanceof window.CSSStyleRule) {
|
if (cssRule instanceof window.CSSStyleRule) {
|
||||||
for (let i = 0; i < rules.length; i++) {
|
for (let i = 0; i < rules.length; i++) {
|
||||||
if (cssRule.selectorText.toLowerCase() === rules[i]) {
|
if (cssRule.selectorText.toLowerCase() === rules[i]) {
|
||||||
found = true
|
found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return found
|
return found;
|
||||||
})
|
});
|
||||||
|
|
||||||
return result != null
|
return result != null;
|
||||||
})
|
});
|
||||||
|
|
||||||
return result
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,124 +1,127 @@
|
||||||
import store from '@/store'
|
import store from "@/store";
|
||||||
import url from '@/utils/url'
|
import url from "@/utils/url";
|
||||||
|
|
||||||
export function checkConflict(files, items) {
|
export function checkConflict(files, items) {
|
||||||
if (typeof items === 'undefined' || items === null) {
|
if (typeof items === "undefined" || items === null) {
|
||||||
items = []
|
items = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
let folder_upload = files[0].fullPath !== undefined
|
let folder_upload = files[0].fullPath !== undefined;
|
||||||
|
|
||||||
let conflict = false
|
let conflict = false;
|
||||||
for (let i = 0; i < files.length; i++) {
|
for (let i = 0; i < files.length; i++) {
|
||||||
let file = files[i]
|
let file = files[i];
|
||||||
let name = file.name
|
let name = file.name;
|
||||||
|
|
||||||
if (folder_upload) {
|
if (folder_upload) {
|
||||||
let dirs = file.fullPath.split("/")
|
let dirs = file.fullPath.split("/");
|
||||||
if (dirs.length > 1) {
|
if (dirs.length > 1) {
|
||||||
name = dirs[0]
|
name = dirs[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = items.findIndex(function hasConflict(element) {
|
let res = items.findIndex(function hasConflict(element) {
|
||||||
return (element.name === this)
|
return element.name === this;
|
||||||
}, name)
|
}, name);
|
||||||
|
|
||||||
if (res >= 0) {
|
if (res >= 0) {
|
||||||
conflict = true
|
conflict = true;
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return conflict
|
return conflict;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function scanFiles(dt) {
|
export function scanFiles(dt) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
let reading = 0
|
let reading = 0;
|
||||||
const contents = []
|
const contents = [];
|
||||||
|
|
||||||
if (dt.items !== undefined) {
|
if (dt.items !== undefined) {
|
||||||
for (let item of dt.items) {
|
for (let item of dt.items) {
|
||||||
if (item.kind === "file" && typeof item.webkitGetAsEntry === "function") {
|
if (
|
||||||
const entry = item.webkitGetAsEntry()
|
item.kind === "file" &&
|
||||||
readEntry(entry)
|
typeof item.webkitGetAsEntry === "function"
|
||||||
|
) {
|
||||||
|
const entry = item.webkitGetAsEntry();
|
||||||
|
readEntry(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
resolve(dt.files)
|
resolve(dt.files);
|
||||||
}
|
}
|
||||||
|
|
||||||
function readEntry(entry, directory = "") {
|
function readEntry(entry, directory = "") {
|
||||||
if (entry.isFile) {
|
if (entry.isFile) {
|
||||||
reading++
|
reading++;
|
||||||
entry.file(file => {
|
entry.file((file) => {
|
||||||
reading--
|
reading--;
|
||||||
|
|
||||||
file.fullPath = `${directory}${file.name}`
|
file.fullPath = `${directory}${file.name}`;
|
||||||
contents.push(file)
|
contents.push(file);
|
||||||
|
|
||||||
if (reading === 0) {
|
if (reading === 0) {
|
||||||
resolve(contents)
|
resolve(contents);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
} else if (entry.isDirectory) {
|
} else if (entry.isDirectory) {
|
||||||
const dir = {
|
const dir = {
|
||||||
isDir: true,
|
isDir: true,
|
||||||
size: 0,
|
size: 0,
|
||||||
fullPath: `${directory}${entry.name}`
|
fullPath: `${directory}${entry.name}`,
|
||||||
}
|
};
|
||||||
|
|
||||||
contents.push(dir)
|
contents.push(dir);
|
||||||
|
|
||||||
readReaderContent(entry.createReader(), `${directory}${entry.name}`)
|
readReaderContent(entry.createReader(), `${directory}${entry.name}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function readReaderContent(reader, directory) {
|
function readReaderContent(reader, directory) {
|
||||||
reading++
|
reading++;
|
||||||
|
|
||||||
reader.readEntries(function (entries) {
|
reader.readEntries(function (entries) {
|
||||||
reading--
|
reading--;
|
||||||
if (entries.length > 0) {
|
if (entries.length > 0) {
|
||||||
for (const entry of entries) {
|
for (const entry of entries) {
|
||||||
readEntry(entry, `${directory}/`)
|
readEntry(entry, `${directory}/`);
|
||||||
}
|
}
|
||||||
|
|
||||||
readReaderContent(reader, `${directory}/`)
|
readReaderContent(reader, `${directory}/`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reading === 0) {
|
if (reading === 0) {
|
||||||
resolve(contents)
|
resolve(contents);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function handleFiles(files, base, overwrite = false) {
|
export function handleFiles(files, base, overwrite = false) {
|
||||||
for (let i = 0; i < files.length; i++) {
|
for (let i = 0; i < files.length; i++) {
|
||||||
let id = store.state.upload.id
|
let id = store.state.upload.id;
|
||||||
let path = base
|
let path = base;
|
||||||
let file = files[i]
|
let file = files[i];
|
||||||
|
|
||||||
if (file.fullPath !== undefined) {
|
if (file.fullPath !== undefined) {
|
||||||
path += url.encodePath(file.fullPath)
|
path += url.encodePath(file.fullPath);
|
||||||
} else {
|
} else {
|
||||||
path += url.encodeRFC5987ValueChars(file.name)
|
path += url.encodeRFC5987ValueChars(file.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file.isDir) {
|
if (file.isDir) {
|
||||||
path += '/'
|
path += "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
const item = {
|
const item = {
|
||||||
id,
|
id,
|
||||||
path,
|
path,
|
||||||
file,
|
file,
|
||||||
overwrite
|
overwrite,
|
||||||
}
|
};
|
||||||
|
|
||||||
store.dispatch('upload/upload', item);
|
store.dispatch("upload/upload", item);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,31 +1,36 @@
|
||||||
function removeLastDir (url) {
|
function removeLastDir(url) {
|
||||||
var arr = url.split('/')
|
var arr = url.split("/");
|
||||||
if (arr.pop() === '') {
|
if (arr.pop() === "") {
|
||||||
arr.pop()
|
arr.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
return arr.join('/')
|
return arr.join("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
// this code borrow from mozilla
|
// this code borrow from mozilla
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent#Examples
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent#Examples
|
||||||
function encodeRFC5987ValueChars(str) {
|
function encodeRFC5987ValueChars(str) {
|
||||||
return encodeURIComponent(str).
|
return (
|
||||||
|
encodeURIComponent(str)
|
||||||
// Note that although RFC3986 reserves "!", RFC5987 does not,
|
// Note that although RFC3986 reserves "!", RFC5987 does not,
|
||||||
// so we do not need to escape it
|
// so we do not need to escape it
|
||||||
replace(/['()]/g, escape). // i.e., %27 %28 %29
|
.replace(/['()]/g, escape) // i.e., %27 %28 %29
|
||||||
replace(/\*/g, '%2A').
|
.replace(/\*/g, "%2A")
|
||||||
// The following are not required for percent-encoding per RFC5987,
|
// The following are not required for percent-encoding per RFC5987,
|
||||||
// so we can allow for a little better readability over the wire: |`^
|
// so we can allow for a little better readability over the wire: |`^
|
||||||
replace(/%(?:7C|60|5E)/g, unescape);
|
.replace(/%(?:7C|60|5E)/g, unescape)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function encodePath(str) {
|
function encodePath(str) {
|
||||||
return str.split('/').map(v => encodeURIComponent(v)).join('/')
|
return str
|
||||||
|
.split("/")
|
||||||
|
.map((v) => encodeURIComponent(v))
|
||||||
|
.join("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
encodeRFC5987ValueChars: encodeRFC5987ValueChars,
|
encodeRFC5987ValueChars: encodeRFC5987ValueChars,
|
||||||
removeLastDir: removeLastDir,
|
removeLastDir: removeLastDir,
|
||||||
encodePath: encodePath
|
encodePath: encodePath,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,58 +1,66 @@
|
||||||
import Vue from 'vue'
|
import Vue from "vue";
|
||||||
import Noty from 'noty'
|
import Noty from "noty";
|
||||||
import VueLazyload from 'vue-lazyload'
|
import VueLazyload from "vue-lazyload";
|
||||||
import i18n from '@/i18n'
|
import i18n from "@/i18n";
|
||||||
import { disableExternal } from '@/utils/constants'
|
import { disableExternal } from "@/utils/constants";
|
||||||
|
|
||||||
Vue.use(VueLazyload)
|
Vue.use(VueLazyload);
|
||||||
|
|
||||||
Vue.config.productionTip = true
|
Vue.config.productionTip = true;
|
||||||
|
|
||||||
const notyDefault = {
|
const notyDefault = {
|
||||||
type: 'info',
|
type: "info",
|
||||||
layout: 'bottomRight',
|
layout: "bottomRight",
|
||||||
timeout: 1000,
|
timeout: 1000,
|
||||||
progressBar: true
|
progressBar: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
Vue.prototype.$noty = (opts) => {
|
Vue.prototype.$noty = (opts) => {
|
||||||
new Noty(Object.assign({}, notyDefault, opts)).show()
|
new Noty(Object.assign({}, notyDefault, opts)).show();
|
||||||
}
|
};
|
||||||
|
|
||||||
Vue.prototype.$showSuccess = (message) => {
|
Vue.prototype.$showSuccess = (message) => {
|
||||||
new Noty(Object.assign({}, notyDefault, {
|
new Noty(
|
||||||
text: message,
|
Object.assign({}, notyDefault, {
|
||||||
type: 'success'
|
text: message,
|
||||||
})).show()
|
type: "success",
|
||||||
}
|
})
|
||||||
|
).show();
|
||||||
|
};
|
||||||
|
|
||||||
Vue.prototype.$showError = (error, displayReport = true) => {
|
Vue.prototype.$showError = (error, displayReport = true) => {
|
||||||
let btns = [
|
let btns = [
|
||||||
Noty.button(i18n.t('buttons.close'), '', function () {
|
Noty.button(i18n.t("buttons.close"), "", function () {
|
||||||
n.close()
|
n.close();
|
||||||
})
|
}),
|
||||||
]
|
];
|
||||||
|
|
||||||
if (!disableExternal && displayReport) {
|
if (!disableExternal && displayReport) {
|
||||||
btns.unshift(Noty.button(i18n.t('buttons.reportIssue'), '', function () {
|
btns.unshift(
|
||||||
window.open('https://github.com/filebrowser/filebrowser/issues/new/choose')
|
Noty.button(i18n.t("buttons.reportIssue"), "", function () {
|
||||||
}))
|
window.open(
|
||||||
|
"https://github.com/filebrowser/filebrowser/issues/new/choose"
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let n = new Noty(Object.assign({}, notyDefault, {
|
let n = new Noty(
|
||||||
text: error.message || error,
|
Object.assign({}, notyDefault, {
|
||||||
type: 'error',
|
text: error.message || error,
|
||||||
timeout: null,
|
type: "error",
|
||||||
buttons: btns
|
timeout: null,
|
||||||
}))
|
buttons: btns,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
n.show()
|
n.show();
|
||||||
}
|
};
|
||||||
|
|
||||||
Vue.directive('focus', {
|
Vue.directive("focus", {
|
||||||
inserted: function (el) {
|
inserted: function (el) {
|
||||||
el.focus()
|
el.focus();
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
export default Vue
|
export default Vue;
|
||||||
|
|
|
@ -10,37 +10,34 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import HeaderBar from "@/components/header/HeaderBar";
|
||||||
import HeaderBar from '@/components/header/HeaderBar'
|
|
||||||
|
|
||||||
const errors = {
|
const errors = {
|
||||||
403: {
|
403: {
|
||||||
icon: 'error',
|
icon: "error",
|
||||||
message: 'errors.forbidden'
|
message: "errors.forbidden",
|
||||||
},
|
},
|
||||||
404: {
|
404: {
|
||||||
icon: 'gps_off',
|
icon: "gps_off",
|
||||||
message: 'errors.notFound'
|
message: "errors.notFound",
|
||||||
},
|
},
|
||||||
500: {
|
500: {
|
||||||
icon: 'error_outline',
|
icon: "error_outline",
|
||||||
message: 'errors.internal'
|
message: "errors.internal",
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'errors',
|
name: "errors",
|
||||||
components: {
|
components: {
|
||||||
HeaderBar
|
HeaderBar,
|
||||||
},
|
},
|
||||||
props: [
|
props: ["errorCode", "showHeader"],
|
||||||
'errorCode', 'showHeader'
|
|
||||||
],
|
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
icon: errors[this.errorCode].icon,
|
icon: errors[this.errorCode].icon,
|
||||||
message: this.$t(errors[this.errorCode].message)
|
message: this.$t(errors[this.errorCode].message),
|
||||||
}
|
};
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
|
@ -8,137 +8,137 @@
|
||||||
<component v-else-if="currentView" :is="currentView"></component>
|
<component v-else-if="currentView" :is="currentView"></component>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<h2 class="message">
|
<h2 class="message">
|
||||||
<span>{{ $t('files.loading') }}</span>
|
<span>{{ $t("files.loading") }}</span>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { files as api } from '@/api'
|
import { files as api } from "@/api";
|
||||||
import { mapState, mapMutations } from 'vuex'
|
import { mapState, mapMutations } from "vuex";
|
||||||
|
|
||||||
import HeaderBar from '@/components/header/HeaderBar'
|
import HeaderBar from "@/components/header/HeaderBar";
|
||||||
import Breadcrumbs from '@/components/Breadcrumbs'
|
import Breadcrumbs from "@/components/Breadcrumbs";
|
||||||
import Errors from '@/views/Errors'
|
import Errors from "@/views/Errors";
|
||||||
import Preview from '@/views/files/Preview'
|
import Preview from "@/views/files/Preview";
|
||||||
import Listing from '@/views/files/Listing'
|
import Listing from "@/views/files/Listing";
|
||||||
|
|
||||||
function clean (path) {
|
function clean(path) {
|
||||||
return path.endsWith('/') ? path.slice(0, -1) : path
|
return path.endsWith("/") ? path.slice(0, -1) : path;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'files',
|
name: "files",
|
||||||
components: {
|
components: {
|
||||||
HeaderBar,
|
HeaderBar,
|
||||||
Breadcrumbs,
|
Breadcrumbs,
|
||||||
Errors,
|
Errors,
|
||||||
Preview,
|
Preview,
|
||||||
Listing,
|
Listing,
|
||||||
Editor: () => import('@/views/files/Editor'),
|
Editor: () => import("@/views/files/Editor"),
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
error: null,
|
error: null,
|
||||||
width: window.innerWidth
|
width: window.innerWidth,
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState([
|
...mapState(["req", "reload", "loading", "show"]),
|
||||||
'req',
|
currentView() {
|
||||||
'reload',
|
|
||||||
'loading',
|
|
||||||
'show'
|
|
||||||
]),
|
|
||||||
currentView () {
|
|
||||||
if (this.req.type == undefined) {
|
if (this.req.type == undefined) {
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.req.isDir) {
|
if (this.req.isDir) {
|
||||||
return 'listing'
|
return "listing";
|
||||||
} else if(this.req.type === 'text' || this.req.type === 'textImmutable') {
|
} else if (
|
||||||
return 'editor'
|
this.req.type === "text" ||
|
||||||
|
this.req.type === "textImmutable"
|
||||||
|
) {
|
||||||
|
return "editor";
|
||||||
} else {
|
} else {
|
||||||
return 'preview'
|
return "preview";
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
errorCode() {
|
errorCode() {
|
||||||
return (this.error.message === '404' || this.error.message === '403') ? parseInt(this.error.message) : 500
|
return this.error.message === "404" || this.error.message === "403"
|
||||||
}
|
? parseInt(this.error.message)
|
||||||
|
: 500;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
created () {
|
created() {
|
||||||
this.fetchData()
|
this.fetchData();
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
'$route': 'fetchData',
|
$route: "fetchData",
|
||||||
'reload': function (value) {
|
reload: function (value) {
|
||||||
if (value === true) {
|
if (value === true) {
|
||||||
this.fetchData()
|
this.fetchData();
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted () {
|
|
||||||
window.addEventListener('keydown', this.keyEvent)
|
|
||||||
},
|
|
||||||
beforeDestroy () {
|
|
||||||
window.removeEventListener('keydown', this.keyEvent)
|
|
||||||
},
|
|
||||||
destroyed () {
|
|
||||||
if (this.$store.state.showShell) {
|
|
||||||
this.$store.commit('toggleShell')
|
|
||||||
}
|
|
||||||
this.$store.commit('updateRequest', {})
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
...mapMutations([ 'setLoading' ]),
|
|
||||||
async fetchData () {
|
|
||||||
// Reset view information.
|
|
||||||
this.$store.commit('setReload', false)
|
|
||||||
this.$store.commit('resetSelected')
|
|
||||||
this.$store.commit('multiple', false)
|
|
||||||
this.$store.commit('closeHovers')
|
|
||||||
|
|
||||||
// Set loading to true and reset the error.
|
|
||||||
this.setLoading(true)
|
|
||||||
this.error = null
|
|
||||||
|
|
||||||
let url = this.$route.path
|
|
||||||
if (url === '') url = '/'
|
|
||||||
if (url[0] !== '/') url = '/' + url
|
|
||||||
|
|
||||||
try {
|
|
||||||
const res = await api.fetch(url)
|
|
||||||
|
|
||||||
if (clean(res.path) !== clean(`/${this.$route.params.pathMatch}`)) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$store.commit('updateRequest', res)
|
|
||||||
document.title = res.name
|
|
||||||
} catch (e) {
|
|
||||||
this.error = e
|
|
||||||
} finally {
|
|
||||||
this.setLoading(false)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
keyEvent (event) {
|
},
|
||||||
|
mounted() {
|
||||||
|
window.addEventListener("keydown", this.keyEvent);
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
window.removeEventListener("keydown", this.keyEvent);
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
if (this.$store.state.showShell) {
|
||||||
|
this.$store.commit("toggleShell");
|
||||||
|
}
|
||||||
|
this.$store.commit("updateRequest", {});
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapMutations(["setLoading"]),
|
||||||
|
async fetchData() {
|
||||||
|
// Reset view information.
|
||||||
|
this.$store.commit("setReload", false);
|
||||||
|
this.$store.commit("resetSelected");
|
||||||
|
this.$store.commit("multiple", false);
|
||||||
|
this.$store.commit("closeHovers");
|
||||||
|
|
||||||
|
// Set loading to true and reset the error.
|
||||||
|
this.setLoading(true);
|
||||||
|
this.error = null;
|
||||||
|
|
||||||
|
let url = this.$route.path;
|
||||||
|
if (url === "") url = "/";
|
||||||
|
if (url[0] !== "/") url = "/" + url;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await api.fetch(url);
|
||||||
|
|
||||||
|
if (clean(res.path) !== clean(`/${this.$route.params.pathMatch}`)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$store.commit("updateRequest", res);
|
||||||
|
document.title = res.name;
|
||||||
|
} catch (e) {
|
||||||
|
this.error = e;
|
||||||
|
} finally {
|
||||||
|
this.setLoading(false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
keyEvent(event) {
|
||||||
if (this.show !== null) {
|
if (this.show !== null) {
|
||||||
// Esc!
|
// Esc!
|
||||||
if (event.keyCode === 27) {
|
if (event.keyCode === 27) {
|
||||||
this.$store.commit('closeHovers')
|
this.$store.commit("closeHovers");
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// F1!
|
// F1!
|
||||||
if (event.keyCode === 112) {
|
if (event.keyCode === 112) {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
this.$store.commit('showHover', 'help')
|
this.$store.commit("showHover", "help");
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -13,30 +13,31 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState, mapGetters } from 'vuex'
|
import { mapState, mapGetters } from "vuex";
|
||||||
import Sidebar from '@/components/Sidebar'
|
import Sidebar from "@/components/Sidebar";
|
||||||
import Prompts from '@/components/prompts/Prompts'
|
import Prompts from "@/components/prompts/Prompts";
|
||||||
import Shell from '@/components/Shell'
|
import Shell from "@/components/Shell";
|
||||||
import { enableExec } from '@/utils/constants'
|
import { enableExec } from "@/utils/constants";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'layout',
|
name: "layout",
|
||||||
components: {
|
components: {
|
||||||
Sidebar,
|
Sidebar,
|
||||||
Prompts,
|
Prompts,
|
||||||
Shell
|
Shell,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters([ 'isLogged', 'progress' ]),
|
...mapGetters(["isLogged", "progress"]),
|
||||||
...mapState([ 'user' ]),
|
...mapState(["user"]),
|
||||||
isExecEnabled: () => enableExec
|
isExecEnabled: () => enableExec,
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
'$route': function () {
|
$route: function () {
|
||||||
this.$store.commit('resetSelected')
|
this.$store.commit("resetSelected");
|
||||||
this.$store.commit('multiple', false)
|
this.$store.commit("multiple", false);
|
||||||
if (this.$store.state.show !== 'success') this.$store.commit('closeHovers')
|
if (this.$store.state.show !== "success")
|
||||||
}
|
this.$store.commit("closeHovers");
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,97 +1,127 @@
|
||||||
<template>
|
<template>
|
||||||
<div id="login" :class="{ recaptcha: recaptcha }">
|
<div id="login" :class="{ recaptcha: recaptcha }">
|
||||||
<form @submit="submit">
|
<form @submit="submit">
|
||||||
<img :src="logoURL" alt="File Browser">
|
<img :src="logoURL" alt="File Browser" />
|
||||||
<h1>{{ name }}</h1>
|
<h1>{{ name }}</h1>
|
||||||
<div v-if="error !== ''" class="wrong">{{ error }}</div>
|
<div v-if="error !== ''" class="wrong">{{ error }}</div>
|
||||||
|
|
||||||
<input class="input input--block" type="text" v-model="username" :placeholder="$t('login.username')">
|
<input
|
||||||
<input class="input input--block" type="password" v-model="password" :placeholder="$t('login.password')">
|
class="input input--block"
|
||||||
<input class="input input--block" v-if="createMode" type="password" v-model="passwordConfirm" :placeholder="$t('login.passwordConfirm')" />
|
type="text"
|
||||||
|
v-model="username"
|
||||||
|
:placeholder="$t('login.username')"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
class="input input--block"
|
||||||
|
type="password"
|
||||||
|
v-model="password"
|
||||||
|
:placeholder="$t('login.password')"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
class="input input--block"
|
||||||
|
v-if="createMode"
|
||||||
|
type="password"
|
||||||
|
v-model="passwordConfirm"
|
||||||
|
:placeholder="$t('login.passwordConfirm')"
|
||||||
|
/>
|
||||||
|
|
||||||
<div v-if="recaptcha" id="recaptcha"></div>
|
<div v-if="recaptcha" id="recaptcha"></div>
|
||||||
<input class="button button--block" type="submit" :value="createMode ? $t('login.signup') : $t('login.submit')">
|
<input
|
||||||
|
class="button button--block"
|
||||||
|
type="submit"
|
||||||
|
:value="createMode ? $t('login.signup') : $t('login.submit')"
|
||||||
|
/>
|
||||||
|
|
||||||
<p @click="toggleMode" v-if="signup">{{ createMode ? $t('login.loginInstead') : $t('login.createAnAccount') }}</p>
|
<p @click="toggleMode" v-if="signup">
|
||||||
|
{{
|
||||||
|
createMode ? $t("login.loginInstead") : $t("login.createAnAccount")
|
||||||
|
}}
|
||||||
|
</p>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import * as auth from '@/utils/auth'
|
import * as auth from "@/utils/auth";
|
||||||
import { name, logoURL, recaptcha, recaptchaKey, signup } from '@/utils/constants'
|
import {
|
||||||
|
name,
|
||||||
|
logoURL,
|
||||||
|
recaptcha,
|
||||||
|
recaptchaKey,
|
||||||
|
signup,
|
||||||
|
} from "@/utils/constants";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'login',
|
name: "login",
|
||||||
computed: {
|
computed: {
|
||||||
signup: () => signup,
|
signup: () => signup,
|
||||||
name: () => name,
|
name: () => name,
|
||||||
logoURL: () => logoURL
|
logoURL: () => logoURL,
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
createMode: false,
|
createMode: false,
|
||||||
error: '',
|
error: "",
|
||||||
username: '',
|
username: "",
|
||||||
password: '',
|
password: "",
|
||||||
recaptcha: recaptcha,
|
recaptcha: recaptcha,
|
||||||
passwordConfirm: ''
|
passwordConfirm: "",
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted() {
|
||||||
if (!recaptcha) return
|
if (!recaptcha) return;
|
||||||
|
|
||||||
window.grecaptcha.ready(function () {
|
window.grecaptcha.ready(function () {
|
||||||
window.grecaptcha.render('recaptcha', {
|
window.grecaptcha.render("recaptcha", {
|
||||||
sitekey: recaptchaKey
|
sitekey: recaptchaKey,
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
toggleMode () {
|
toggleMode() {
|
||||||
this.createMode = !this.createMode
|
this.createMode = !this.createMode;
|
||||||
},
|
},
|
||||||
async submit (event) {
|
async submit(event) {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
event.stopPropagation()
|
event.stopPropagation();
|
||||||
|
|
||||||
let redirect = this.$route.query.redirect
|
let redirect = this.$route.query.redirect;
|
||||||
if (redirect === '' || redirect === undefined || redirect === null) {
|
if (redirect === "" || redirect === undefined || redirect === null) {
|
||||||
redirect = '/files/'
|
redirect = "/files/";
|
||||||
}
|
}
|
||||||
|
|
||||||
let captcha = ''
|
let captcha = "";
|
||||||
if (recaptcha) {
|
if (recaptcha) {
|
||||||
captcha = window.grecaptcha.getResponse()
|
captcha = window.grecaptcha.getResponse();
|
||||||
|
|
||||||
if (captcha === '') {
|
if (captcha === "") {
|
||||||
this.error = this.$t('login.wrongCredentials')
|
this.error = this.$t("login.wrongCredentials");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.createMode) {
|
if (this.createMode) {
|
||||||
if (this.password !== this.passwordConfirm) {
|
if (this.password !== this.passwordConfirm) {
|
||||||
this.error = this.$t('login.passwordsDontMatch')
|
this.error = this.$t("login.passwordsDontMatch");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (this.createMode) {
|
if (this.createMode) {
|
||||||
await auth.signup(this.username, this.password)
|
await auth.signup(this.username, this.password);
|
||||||
}
|
}
|
||||||
|
|
||||||
await auth.login(this.username, this.password, captcha)
|
await auth.login(this.username, this.password, captcha);
|
||||||
this.$router.push({ path: redirect })
|
this.$router.push({ path: redirect });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.message == 409) {
|
if (e.message == 409) {
|
||||||
this.error = this.$t('login.usernameTaken')
|
this.error = this.$t("login.usernameTaken");
|
||||||
} else {
|
} else {
|
||||||
this.error = this.$t('login.wrongCredentials')
|
this.error = this.$t("login.wrongCredentials");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -5,10 +5,35 @@
|
||||||
<div id="nav">
|
<div id="nav">
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<ul>
|
<ul>
|
||||||
<router-link to="/settings/profile"><li :class="{ active: $route.path === '/settings/profile' }">{{ $t('settings.profileSettings') }}</li></router-link>
|
<router-link to="/settings/profile"
|
||||||
<router-link to="/settings/shares"><li :class="{ active: $route.path === '/settings/shares' }">{{ $t('settings.shareManagement') }}</li></router-link>
|
><li :class="{ active: $route.path === '/settings/profile' }">
|
||||||
<router-link to="/settings/global"><li :class="{ active: $route.path === '/settings/global' }" v-if="user.perm.admin">{{ $t('settings.globalSettings') }}</li></router-link>
|
{{ $t("settings.profileSettings") }}
|
||||||
<router-link to="/settings/users"><li :class="{ active: $route.path === '/settings/users' || $route.name === 'User' }" v-if="user.perm.admin">{{ $t('settings.userManagement') }}</li></router-link>
|
</li></router-link
|
||||||
|
>
|
||||||
|
<router-link to="/settings/shares"
|
||||||
|
><li :class="{ active: $route.path === '/settings/shares' }">
|
||||||
|
{{ $t("settings.shareManagement") }}
|
||||||
|
</li></router-link
|
||||||
|
>
|
||||||
|
<router-link to="/settings/global"
|
||||||
|
><li
|
||||||
|
:class="{ active: $route.path === '/settings/global' }"
|
||||||
|
v-if="user.perm.admin"
|
||||||
|
>
|
||||||
|
{{ $t("settings.globalSettings") }}
|
||||||
|
</li></router-link
|
||||||
|
>
|
||||||
|
<router-link to="/settings/users"
|
||||||
|
><li
|
||||||
|
:class="{
|
||||||
|
active:
|
||||||
|
$route.path === '/settings/users' || $route.name === 'User',
|
||||||
|
}"
|
||||||
|
v-if="user.perm.admin"
|
||||||
|
>
|
||||||
|
{{ $t("settings.userManagement") }}
|
||||||
|
</li></router-link
|
||||||
|
>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -18,17 +43,17 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from "vuex";
|
||||||
|
|
||||||
import HeaderBar from '@/components/header/HeaderBar'
|
import HeaderBar from "@/components/header/HeaderBar";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'settings',
|
name: "settings",
|
||||||
components: {
|
components: {
|
||||||
HeaderBar
|
HeaderBar,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState([ 'user' ])
|
...mapState(["user"]),
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -3,8 +3,18 @@
|
||||||
<header-bar showMenu showLogo>
|
<header-bar showMenu showLogo>
|
||||||
<title />
|
<title />
|
||||||
|
|
||||||
<action v-if="selectedCount" icon="file_download" :label="$t('buttons.download')" @action="download" :counter="selectedCount" />
|
<action
|
||||||
<action icon="check_circle" :label="$t('buttons.selectMultiple')" @action="toggleMultipleSelection" />
|
v-if="selectedCount"
|
||||||
|
icon="file_download"
|
||||||
|
:label="$t('buttons.download')"
|
||||||
|
@action="download"
|
||||||
|
:counter="selectedCount"
|
||||||
|
/>
|
||||||
|
<action
|
||||||
|
icon="check_circle"
|
||||||
|
:label="$t('buttons.selectMultiple')"
|
||||||
|
@action="toggleMultipleSelection"
|
||||||
|
/>
|
||||||
</header-bar>
|
</header-bar>
|
||||||
|
|
||||||
<breadcrumbs :base="'/share/' + hash" />
|
<breadcrumbs :base="'/share/' + hash" />
|
||||||
|
@ -12,34 +22,44 @@
|
||||||
<div v-if="!loading">
|
<div v-if="!loading">
|
||||||
<div class="share">
|
<div class="share">
|
||||||
<div class="share__box share__box__info">
|
<div class="share__box share__box__info">
|
||||||
<div class="share__box__header">
|
<div class="share__box__header">
|
||||||
{{ req.isDir ? $t('download.downloadFolder') : $t('download.downloadFile') }}
|
{{
|
||||||
</div>
|
req.isDir
|
||||||
<div class="share__box__element share__box__center share__box__icon">
|
? $t("download.downloadFolder")
|
||||||
<i class="material-icons">{{ icon }}</i>
|
: $t("download.downloadFile")
|
||||||
</div>
|
}}
|
||||||
<div class="share__box__element">
|
</div>
|
||||||
<strong>{{ $t('prompts.displayName') }}</strong> {{ req.name }}
|
<div class="share__box__element share__box__center share__box__icon">
|
||||||
</div>
|
<i class="material-icons">{{ icon }}</i>
|
||||||
<div class="share__box__element">
|
</div>
|
||||||
<strong>{{ $t('prompts.lastModified') }}:</strong> {{ humanTime }}
|
<div class="share__box__element">
|
||||||
</div>
|
<strong>{{ $t("prompts.displayName") }}</strong> {{ req.name }}
|
||||||
<div class="share__box__element">
|
</div>
|
||||||
<strong>{{ $t('prompts.size') }}:</strong> {{ humanSize }}
|
<div class="share__box__element">
|
||||||
</div>
|
<strong>{{ $t("prompts.lastModified") }}:</strong> {{ humanTime }}
|
||||||
<div class="share__box__element share__box__center">
|
</div>
|
||||||
<a target="_blank" :href="link" class="button button--flat">{{ $t('buttons.download') }}</a>
|
<div class="share__box__element">
|
||||||
</div>
|
<strong>{{ $t("prompts.size") }}:</strong> {{ humanSize }}
|
||||||
<div class="share__box__element share__box__center">
|
</div>
|
||||||
<qrcode-vue :value="fullLink" size="200" level="M"></qrcode-vue>
|
<div class="share__box__element share__box__center">
|
||||||
</div>
|
<a target="_blank" :href="link" class="button button--flat">{{
|
||||||
|
$t("buttons.download")
|
||||||
|
}}</a>
|
||||||
|
</div>
|
||||||
|
<div class="share__box__element share__box__center">
|
||||||
|
<qrcode-vue :value="fullLink" size="200" level="M"></qrcode-vue>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="req.isDir && req.items.length > 0" class="share__box share__box__items">
|
<div
|
||||||
|
v-if="req.isDir && req.items.length > 0"
|
||||||
|
class="share__box share__box__items"
|
||||||
|
>
|
||||||
<div class="share__box__header" v-if="req.isDir">
|
<div class="share__box__header" v-if="req.isDir">
|
||||||
{{ $t('files.files') }}
|
{{ $t("files.files") }}
|
||||||
</div>
|
</div>
|
||||||
<div id="listing" class="list">
|
<div id="listing" class="list">
|
||||||
<item v-for="(item) in req.items.slice(0, this.showLimit)"
|
<item
|
||||||
|
v-for="item in req.items.slice(0, this.showLimit)"
|
||||||
:key="base64(item.name)"
|
:key="base64(item.name)"
|
||||||
v-bind:index="item.index"
|
v-bind:index="item.index"
|
||||||
v-bind:name="item.name"
|
v-bind:name="item.name"
|
||||||
|
@ -48,26 +68,40 @@
|
||||||
v-bind:modified="item.modified"
|
v-bind:modified="item.modified"
|
||||||
v-bind:type="item.type"
|
v-bind:type="item.type"
|
||||||
v-bind:size="item.size"
|
v-bind:size="item.size"
|
||||||
readOnly>
|
readOnly
|
||||||
|
>
|
||||||
</item>
|
</item>
|
||||||
<div v-if="req.items.length > showLimit" class="item">
|
<div v-if="req.items.length > showLimit" class="item">
|
||||||
<div>
|
<div>
|
||||||
<p class="name"> + {{ req.items.length - showLimit }} </p>
|
<p class="name">+ {{ req.items.length - showLimit }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div :class="{ active: $store.state.multiple }" id="multiple-selection">
|
<div
|
||||||
<p>{{ $t('files.multipleSelectionEnabled') }}</p>
|
:class="{ active: $store.state.multiple }"
|
||||||
<div @click="$store.commit('multiple', false)" tabindex="0" role="button" :title="$t('files.clear')" :aria-label="$t('files.clear')" class="action">
|
id="multiple-selection"
|
||||||
|
>
|
||||||
|
<p>{{ $t("files.multipleSelectionEnabled") }}</p>
|
||||||
|
<div
|
||||||
|
@click="$store.commit('multiple', false)"
|
||||||
|
tabindex="0"
|
||||||
|
role="button"
|
||||||
|
:title="$t('files.clear')"
|
||||||
|
:aria-label="$t('files.clear')"
|
||||||
|
class="action"
|
||||||
|
>
|
||||||
<i class="material-icons">clear</i>
|
<i class="material-icons">clear</i>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="req.isDir && req.items.length === 0" class="share__box share__box__items">
|
<div
|
||||||
|
v-else-if="req.isDir && req.items.length === 0"
|
||||||
|
class="share__box share__box__items"
|
||||||
|
>
|
||||||
<h2 class="message">
|
<h2 class="message">
|
||||||
<i class="material-icons">sentiment_dissatisfied</i>
|
<i class="material-icons">sentiment_dissatisfied</i>
|
||||||
<span>{{ $t('files.lonely') }}</span>
|
<span>{{ $t("files.lonely") }}</span>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -75,19 +109,31 @@
|
||||||
<div v-if="error">
|
<div v-if="error">
|
||||||
<div v-if="error.message === '401'">
|
<div v-if="error.message === '401'">
|
||||||
<div class="card floating" id="password">
|
<div class="card floating" id="password">
|
||||||
<div v-if="attemptedPasswordLogin" class="share__wrong__password">{{ $t('login.wrongCredentials') }}</div>
|
<div v-if="attemptedPasswordLogin" class="share__wrong__password">
|
||||||
|
{{ $t("login.wrongCredentials") }}
|
||||||
|
</div>
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
<h2>{{ $t('login.password') }}</h2>
|
<h2>{{ $t("login.password") }}</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<input v-focus type="password" :placeholder="$t('login.password')" v-model="password" @keyup.enter="fetchData">
|
<input
|
||||||
|
v-focus
|
||||||
|
type="password"
|
||||||
|
:placeholder="$t('login.password')"
|
||||||
|
v-model="password"
|
||||||
|
@keyup.enter="fetchData"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-action">
|
<div class="card-action">
|
||||||
<button class="button button--flat"
|
<button
|
||||||
|
class="button button--flat"
|
||||||
@click="fetchData"
|
@click="fetchData"
|
||||||
:aria-label="$t('buttons.submit')"
|
:aria-label="$t('buttons.submit')"
|
||||||
:title="$t('buttons.submit')">{{ $t('buttons.submit') }}</button>
|
:title="$t('buttons.submit')"
|
||||||
|
>
|
||||||
|
{{ $t("buttons.submit") }}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -97,156 +143,163 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {mapState, mapMutations, mapGetters} from 'vuex';
|
import { mapState, mapMutations, mapGetters } from "vuex";
|
||||||
import { pub as api } from '@/api'
|
import { pub as api } from "@/api";
|
||||||
import { baseURL } from '@/utils/constants'
|
import { baseURL } from "@/utils/constants";
|
||||||
import filesize from 'filesize'
|
import filesize from "filesize";
|
||||||
import moment from 'moment'
|
import moment from "moment";
|
||||||
|
|
||||||
import HeaderBar from '@/components/header/HeaderBar'
|
import HeaderBar from "@/components/header/HeaderBar";
|
||||||
import Action from '@/components/header/Action'
|
import Action from "@/components/header/Action";
|
||||||
import Breadcrumbs from '@/components/Breadcrumbs'
|
import Breadcrumbs from "@/components/Breadcrumbs";
|
||||||
import Errors from '@/views/Errors'
|
import Errors from "@/views/Errors";
|
||||||
import QrcodeVue from 'qrcode.vue'
|
import QrcodeVue from "qrcode.vue";
|
||||||
import Item from "@/components/files/ListingItem"
|
import Item from "@/components/files/ListingItem";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'share',
|
name: "share",
|
||||||
components: {
|
components: {
|
||||||
HeaderBar,
|
HeaderBar,
|
||||||
Action,
|
Action,
|
||||||
Breadcrumbs,
|
Breadcrumbs,
|
||||||
Item,
|
Item,
|
||||||
QrcodeVue,
|
QrcodeVue,
|
||||||
Errors
|
Errors,
|
||||||
},
|
},
|
||||||
data: () => ({
|
data: () => ({
|
||||||
error: null,
|
error: null,
|
||||||
showLimit: 500,
|
showLimit: 500,
|
||||||
password: '',
|
password: "",
|
||||||
attemptedPasswordLogin: false,
|
attemptedPasswordLogin: false,
|
||||||
hash: null,
|
hash: null,
|
||||||
token: null
|
token: null,
|
||||||
}),
|
}),
|
||||||
watch: {
|
watch: {
|
||||||
'$route': 'fetchData'
|
$route: "fetchData",
|
||||||
},
|
},
|
||||||
created: async function () {
|
created: async function () {
|
||||||
const hash = this.$route.params.pathMatch.split('/')[0]
|
const hash = this.$route.params.pathMatch.split("/")[0];
|
||||||
this.hash = hash
|
this.hash = hash;
|
||||||
await this.fetchData()
|
await this.fetchData();
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted() {
|
||||||
window.addEventListener('keydown', this.keyEvent)
|
window.addEventListener("keydown", this.keyEvent);
|
||||||
},
|
},
|
||||||
beforeDestroy () {
|
beforeDestroy() {
|
||||||
window.removeEventListener('keydown', this.keyEvent)
|
window.removeEventListener("keydown", this.keyEvent);
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['req', 'loading', 'multiple', 'selected']),
|
...mapState(["req", "loading", "multiple", "selected"]),
|
||||||
...mapGetters(['selectedCount', 'selectedCount']),
|
...mapGetters(["selectedCount", "selectedCount"]),
|
||||||
icon: function () {
|
icon: function () {
|
||||||
if (this.req.isDir) return 'folder'
|
if (this.req.isDir) return "folder";
|
||||||
if (this.req.type === 'image') return 'insert_photo'
|
if (this.req.type === "image") return "insert_photo";
|
||||||
if (this.req.type === 'audio') return 'volume_up'
|
if (this.req.type === "audio") return "volume_up";
|
||||||
if (this.req.type === 'video') return 'movie'
|
if (this.req.type === "video") return "movie";
|
||||||
return 'insert_drive_file'
|
return "insert_drive_file";
|
||||||
},
|
},
|
||||||
link: function () {
|
link: function () {
|
||||||
let queryArg = '';
|
let queryArg = "";
|
||||||
if (this.token !== ''){
|
if (this.token !== "") {
|
||||||
queryArg = `?token=${this.token}`
|
queryArg = `?token=${this.token}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const path = this.$route.path.split('/').splice(2).join('/')
|
const path = this.$route.path.split("/").splice(2).join("/");
|
||||||
return `${baseURL}/api/public/dl/${path}${queryArg}`
|
return `${baseURL}/api/public/dl/${path}${queryArg}`;
|
||||||
},
|
},
|
||||||
fullLink: function () {
|
fullLink: function () {
|
||||||
return window.location.origin + this.link
|
return window.location.origin + this.link;
|
||||||
},
|
},
|
||||||
humanSize: function () {
|
humanSize: function () {
|
||||||
if (this.req.isDir) {
|
if (this.req.isDir) {
|
||||||
return this.req.items.length
|
return this.req.items.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
return filesize(this.req.size)
|
return filesize(this.req.size);
|
||||||
},
|
},
|
||||||
humanTime: function () {
|
humanTime: function () {
|
||||||
return moment(this.req.modified).fromNow()
|
return moment(this.req.modified).fromNow();
|
||||||
},
|
},
|
||||||
errorCode() {
|
errorCode() {
|
||||||
return (this.error.message === '404' || this.error.message === '403') ? parseInt(this.error.message) : 500
|
return this.error.message === "404" || this.error.message === "403"
|
||||||
}
|
? parseInt(this.error.message)
|
||||||
|
: 500;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapMutations([ 'resetSelected', 'updateRequest', 'setLoading' ]),
|
...mapMutations(["resetSelected", "updateRequest", "setLoading"]),
|
||||||
base64: function (name) {
|
base64: function (name) {
|
||||||
return window.btoa(unescape(encodeURIComponent(name)))
|
return window.btoa(unescape(encodeURIComponent(name)));
|
||||||
},
|
},
|
||||||
fetchData: async function () {
|
fetchData: async function () {
|
||||||
// Reset view information.
|
// Reset view information.
|
||||||
this.$store.commit('setReload', false)
|
this.$store.commit("setReload", false);
|
||||||
this.$store.commit('resetSelected')
|
this.$store.commit("resetSelected");
|
||||||
this.$store.commit('multiple', false)
|
this.$store.commit("multiple", false);
|
||||||
this.$store.commit('closeHovers')
|
this.$store.commit("closeHovers");
|
||||||
|
|
||||||
// Set loading to true and reset the error.
|
// Set loading to true and reset the error.
|
||||||
this.setLoading(true)
|
this.setLoading(true);
|
||||||
this.error = null
|
this.error = null;
|
||||||
|
|
||||||
if (this.password !== ''){
|
if (this.password !== "") {
|
||||||
this.attemptedPasswordLogin = true
|
this.attemptedPasswordLogin = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let url = this.$route.path
|
let url = this.$route.path;
|
||||||
if (url === '') url = '/'
|
if (url === "") url = "/";
|
||||||
if (url[0] !== '/') url = '/' + url
|
if (url[0] !== "/") url = "/" + url;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let file = await api.fetch(url, this.password)
|
let file = await api.fetch(url, this.password);
|
||||||
|
|
||||||
this.token = file.token || ''
|
this.token = file.token || "";
|
||||||
|
|
||||||
this.updateRequest(file)
|
this.updateRequest(file);
|
||||||
this.setLoading(false)
|
this.setLoading(false);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.error = e
|
this.error = e;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
keyEvent (event) {
|
keyEvent(event) {
|
||||||
// Esc!
|
// Esc!
|
||||||
if (event.keyCode === 27) {
|
if (event.keyCode === 27) {
|
||||||
// If we're on a listing, unselect all
|
// If we're on a listing, unselect all
|
||||||
// files and folders.
|
// files and folders.
|
||||||
if (this.selectedCount > 0) {
|
if (this.selectedCount > 0) {
|
||||||
this.resetSelected()
|
this.resetSelected();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
toggleMultipleSelection () {
|
toggleMultipleSelection() {
|
||||||
this.$store.commit('multiple', !this.multiple)
|
this.$store.commit("multiple", !this.multiple);
|
||||||
},
|
},
|
||||||
download () {
|
download() {
|
||||||
if (this.selectedCount === 1 && !this.req.items[this.selected[0]].isDir) {
|
if (this.selectedCount === 1 && !this.req.items[this.selected[0]].isDir) {
|
||||||
api.download(null, this.hash, this.token, this.req.items[this.selected[0]].path)
|
api.download(
|
||||||
return
|
null,
|
||||||
|
this.hash,
|
||||||
|
this.token,
|
||||||
|
this.req.items[this.selected[0]].path
|
||||||
|
);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$store.commit('showHover', {
|
this.$store.commit("showHover", {
|
||||||
prompt: 'download',
|
prompt: "download",
|
||||||
confirm: (format) => {
|
confirm: (format) => {
|
||||||
this.$store.commit('closeHovers')
|
this.$store.commit("closeHovers");
|
||||||
|
|
||||||
let files = []
|
let files = [];
|
||||||
|
|
||||||
for (let i of this.selected) {
|
for (let i of this.selected) {
|
||||||
files.push(this.req.items[i].path)
|
files.push(this.req.items[i].path);
|
||||||
}
|
}
|
||||||
|
|
||||||
api.download(format, this.hash, this.token, ...files)
|
api.download(format, this.hash, this.token, ...files);
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -5,7 +5,12 @@
|
||||||
<title>{{ req.name }}</title>
|
<title>{{ req.name }}</title>
|
||||||
|
|
||||||
<template #actions>
|
<template #actions>
|
||||||
<action id="save-button" icon="save" :label="$t('buttons.save')" @action="save()" />
|
<action
|
||||||
|
id="save-button"
|
||||||
|
icon="save"
|
||||||
|
:label="$t('buttons.save')"
|
||||||
|
@action="save()"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
</header-bar>
|
</header-bar>
|
||||||
|
|
||||||
|
@ -16,120 +21,120 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from "vuex";
|
||||||
import { files as api } from '@/api'
|
import { files as api } from "@/api";
|
||||||
import { theme } from '@/utils/constants'
|
import { theme } from "@/utils/constants";
|
||||||
import buttons from '@/utils/buttons'
|
import buttons from "@/utils/buttons";
|
||||||
import url from '@/utils/url'
|
import url from "@/utils/url";
|
||||||
|
|
||||||
import ace from 'ace-builds/src-min-noconflict/ace.js'
|
import ace from "ace-builds/src-min-noconflict/ace.js";
|
||||||
import modelist from 'ace-builds/src-min-noconflict/ext-modelist.js'
|
import modelist from "ace-builds/src-min-noconflict/ext-modelist.js";
|
||||||
import 'ace-builds/webpack-resolver'
|
import "ace-builds/webpack-resolver";
|
||||||
|
|
||||||
import HeaderBar from '@/components/header/HeaderBar'
|
import HeaderBar from "@/components/header/HeaderBar";
|
||||||
import Action from '@/components/header/Action'
|
import Action from "@/components/header/Action";
|
||||||
import Breadcrumbs from '@/components/Breadcrumbs'
|
import Breadcrumbs from "@/components/Breadcrumbs";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'editor',
|
name: "editor",
|
||||||
components: {
|
components: {
|
||||||
HeaderBar,
|
HeaderBar,
|
||||||
Action,
|
Action,
|
||||||
Breadcrumbs
|
Breadcrumbs,
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {}
|
return {};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['req', 'user']),
|
...mapState(["req", "user"]),
|
||||||
breadcrumbs () {
|
breadcrumbs() {
|
||||||
let parts = this.$route.path.split('/')
|
let parts = this.$route.path.split("/");
|
||||||
|
|
||||||
if (parts[0] === '') {
|
if (parts[0] === "") {
|
||||||
parts.shift()
|
parts.shift();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parts[parts.length - 1] === '') {
|
if (parts[parts.length - 1] === "") {
|
||||||
parts.pop()
|
parts.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
let breadcrumbs = []
|
let breadcrumbs = [];
|
||||||
|
|
||||||
for (let i = 0; i < parts.length; i++) {
|
for (let i = 0; i < parts.length; i++) {
|
||||||
breadcrumbs.push({ name: decodeURIComponent(parts[i]) })
|
breadcrumbs.push({ name: decodeURIComponent(parts[i]) });
|
||||||
}
|
}
|
||||||
|
|
||||||
breadcrumbs.shift()
|
breadcrumbs.shift();
|
||||||
|
|
||||||
if (breadcrumbs.length > 3) {
|
if (breadcrumbs.length > 3) {
|
||||||
while (breadcrumbs.length !== 4) {
|
while (breadcrumbs.length !== 4) {
|
||||||
breadcrumbs.shift()
|
breadcrumbs.shift();
|
||||||
}
|
}
|
||||||
|
|
||||||
breadcrumbs[0].name = '...'
|
breadcrumbs[0].name = "...";
|
||||||
}
|
}
|
||||||
|
|
||||||
return breadcrumbs
|
return breadcrumbs;
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
created () {
|
created() {
|
||||||
window.addEventListener('keydown', this.keyEvent)
|
window.addEventListener("keydown", this.keyEvent);
|
||||||
},
|
},
|
||||||
beforeDestroy () {
|
beforeDestroy() {
|
||||||
window.removeEventListener('keydown', this.keyEvent)
|
window.removeEventListener("keydown", this.keyEvent);
|
||||||
this.editor.destroy();
|
this.editor.destroy();
|
||||||
},
|
},
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
const fileContent = this.req.content || '';
|
const fileContent = this.req.content || "";
|
||||||
|
|
||||||
this.editor = ace.edit('editor', {
|
this.editor = ace.edit("editor", {
|
||||||
value: fileContent,
|
value: fileContent,
|
||||||
showPrintMargin: false,
|
showPrintMargin: false,
|
||||||
readOnly: this.req.type === 'textImmutable',
|
readOnly: this.req.type === "textImmutable",
|
||||||
theme: 'ace/theme/chrome',
|
theme: "ace/theme/chrome",
|
||||||
mode: modelist.getModeForPath(this.req.name).mode,
|
mode: modelist.getModeForPath(this.req.name).mode,
|
||||||
wrap: true
|
wrap: true,
|
||||||
})
|
});
|
||||||
|
|
||||||
if (theme == 'dark') {
|
if (theme == "dark") {
|
||||||
this.editor.setTheme("ace/theme/twilight");
|
this.editor.setTheme("ace/theme/twilight");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
back () {
|
back() {
|
||||||
let uri = url.removeLastDir(this.$route.path) + '/'
|
let uri = url.removeLastDir(this.$route.path) + "/";
|
||||||
this.$router.push({ path: uri })
|
this.$router.push({ path: uri });
|
||||||
},
|
},
|
||||||
keyEvent (event) {
|
keyEvent(event) {
|
||||||
if (!event.ctrlKey && !event.metaKey) {
|
if (!event.ctrlKey && !event.metaKey) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (String.fromCharCode(event.which).toLowerCase() !== 's') {
|
if (String.fromCharCode(event.which).toLowerCase() !== "s") {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
this.save()
|
this.save();
|
||||||
},
|
},
|
||||||
async save () {
|
async save() {
|
||||||
const button = 'save'
|
const button = "save";
|
||||||
buttons.loading('save')
|
buttons.loading("save");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await api.put(this.$route.path, this.editor.getValue())
|
await api.put(this.$route.path, this.editor.getValue());
|
||||||
buttons.success(button)
|
buttons.success(button);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
buttons.done(button)
|
buttons.done(button);
|
||||||
this.$showError(e)
|
this.$showError(e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
close () {
|
close() {
|
||||||
this.$store.commit('updateRequest', {})
|
this.$store.commit("updateRequest", {});
|
||||||
|
|
||||||
let uri = url.removeLastDir(this.$route.path) + '/'
|
let uri = url.removeLastDir(this.$route.path) + "/";
|
||||||
this.$router.push({ path: uri })
|
this.$router.push({ path: uri });
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,15 +1,45 @@
|
||||||
<template>
|
<template>
|
||||||
<div id="previewer" @mousemove="toggleNavigation" @touchstart="toggleNavigation">
|
<div
|
||||||
|
id="previewer"
|
||||||
|
@mousemove="toggleNavigation"
|
||||||
|
@touchstart="toggleNavigation"
|
||||||
|
>
|
||||||
<header-bar>
|
<header-bar>
|
||||||
<action icon="close" :label="$t('buttons.close')" @action="close()" />
|
<action icon="close" :label="$t('buttons.close')" @action="close()" />
|
||||||
<title>{{ name }}</title>
|
<title>{{ name }}</title>
|
||||||
<action :disabled="loading" v-if="isResizeEnabled && req.type === 'image'" :icon="fullSize ? 'photo_size_select_large' : 'hd'" @action="toggleSize" />
|
<action
|
||||||
|
:disabled="loading"
|
||||||
|
v-if="isResizeEnabled && req.type === 'image'"
|
||||||
|
:icon="fullSize ? 'photo_size_select_large' : 'hd'"
|
||||||
|
@action="toggleSize"
|
||||||
|
/>
|
||||||
|
|
||||||
<template #actions>
|
<template #actions>
|
||||||
<action :disabled="loading" icon="mode_edit" :label="$t('buttons.rename')" show="rename" />
|
<action
|
||||||
<action :disabled="loading" icon="delete" :label="$t('buttons.delete')" @action="deleteFile" id="delete-button" />
|
:disabled="loading"
|
||||||
<action :disabled="loading" icon="file_download" :label="$t('buttons.download')" @action="download" />
|
icon="mode_edit"
|
||||||
<action :disabled="loading" icon="info" :label="$t('buttons.info')" show="info" />
|
:label="$t('buttons.rename')"
|
||||||
|
show="rename"
|
||||||
|
/>
|
||||||
|
<action
|
||||||
|
:disabled="loading"
|
||||||
|
icon="delete"
|
||||||
|
:label="$t('buttons.delete')"
|
||||||
|
@action="deleteFile"
|
||||||
|
id="delete-button"
|
||||||
|
/>
|
||||||
|
<action
|
||||||
|
:disabled="loading"
|
||||||
|
icon="file_download"
|
||||||
|
:label="$t('buttons.download')"
|
||||||
|
@action="download"
|
||||||
|
/>
|
||||||
|
<action
|
||||||
|
:disabled="loading"
|
||||||
|
icon="info"
|
||||||
|
:label="$t('buttons.info')"
|
||||||
|
show="info"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
</header-bar>
|
</header-bar>
|
||||||
|
|
||||||
|
@ -31,221 +61,249 @@
|
||||||
v-for="(sub, index) in subtitles"
|
v-for="(sub, index) in subtitles"
|
||||||
:key="index"
|
:key="index"
|
||||||
:src="sub"
|
:src="sub"
|
||||||
:label="'Subtitle ' + index" :default="index === 0">
|
:label="'Subtitle ' + index"
|
||||||
Sorry, your browser doesn't support embedded videos,
|
:default="index === 0"
|
||||||
but don't worry, you can <a :href="downloadUrl">download it</a>
|
/>
|
||||||
|
Sorry, your browser doesn't support embedded videos, but don't worry,
|
||||||
|
you can <a :href="downloadUrl">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="req.extension.toLowerCase() == '.pdf'" class="pdf" :data="raw"></object>
|
<object
|
||||||
|
v-else-if="req.extension.toLowerCase() == '.pdf'"
|
||||||
|
class="pdf"
|
||||||
|
:data="raw"
|
||||||
|
></object>
|
||||||
<a v-else-if="req.type == 'blob'" :href="downloadUrl">
|
<a v-else-if="req.type == 'blob'" :href="downloadUrl">
|
||||||
<h2 class="message">{{ $t('buttons.download') }} <i class="material-icons">file_download</i></h2>
|
<h2 class="message">
|
||||||
|
{{ $t("buttons.download") }}
|
||||||
|
<i class="material-icons">file_download</i>
|
||||||
|
</h2>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<button @click="prev" @mouseover="hoverNav = true" @mouseleave="hoverNav = false" :class="{ hidden: !hasPrevious || !showNav }" :aria-label="$t('buttons.previous')" :title="$t('buttons.previous')">
|
<button
|
||||||
|
@click="prev"
|
||||||
|
@mouseover="hoverNav = true"
|
||||||
|
@mouseleave="hoverNav = false"
|
||||||
|
:class="{ hidden: !hasPrevious || !showNav }"
|
||||||
|
:aria-label="$t('buttons.previous')"
|
||||||
|
:title="$t('buttons.previous')"
|
||||||
|
>
|
||||||
<i class="material-icons">chevron_left</i>
|
<i class="material-icons">chevron_left</i>
|
||||||
</button>
|
</button>
|
||||||
<button @click="next" @mouseover="hoverNav = true" @mouseleave="hoverNav = false" :class="{ hidden: !hasNext || !showNav }" :aria-label="$t('buttons.next')" :title="$t('buttons.next')">
|
<button
|
||||||
|
@click="next"
|
||||||
|
@mouseover="hoverNav = true"
|
||||||
|
@mouseleave="hoverNav = false"
|
||||||
|
:class="{ hidden: !hasNext || !showNav }"
|
||||||
|
:aria-label="$t('buttons.next')"
|
||||||
|
:title="$t('buttons.next')"
|
||||||
|
>
|
||||||
<i class="material-icons">chevron_right</i>
|
<i class="material-icons">chevron_right</i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from "vuex";
|
||||||
import { files as api } from '@/api'
|
import { files as api } from "@/api";
|
||||||
import { baseURL, resizePreview } from '@/utils/constants'
|
import { baseURL, resizePreview } from "@/utils/constants";
|
||||||
import url from '@/utils/url'
|
import url from "@/utils/url";
|
||||||
import throttle from 'lodash.throttle'
|
import throttle from "lodash.throttle";
|
||||||
|
|
||||||
import HeaderBar from '@/components/header/HeaderBar'
|
import HeaderBar from "@/components/header/HeaderBar";
|
||||||
import Action from '@/components/header/Action'
|
import Action from "@/components/header/Action";
|
||||||
import ExtendedImage from '@/components/files/ExtendedImage'
|
import ExtendedImage from "@/components/files/ExtendedImage";
|
||||||
|
|
||||||
const mediaTypes = [
|
const mediaTypes = ["image", "video", "audio", "blob"];
|
||||||
"image",
|
|
||||||
"video",
|
|
||||||
"audio",
|
|
||||||
"blob"
|
|
||||||
]
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'preview',
|
name: "preview",
|
||||||
components: {
|
components: {
|
||||||
HeaderBar,
|
HeaderBar,
|
||||||
Action,
|
Action,
|
||||||
ExtendedImage
|
ExtendedImage,
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
previousLink: '',
|
previousLink: "",
|
||||||
nextLink: '',
|
nextLink: "",
|
||||||
listing: null,
|
listing: null,
|
||||||
name: '',
|
name: "",
|
||||||
subtitles: [],
|
subtitles: [],
|
||||||
fullSize: false,
|
fullSize: false,
|
||||||
showNav: true,
|
showNav: true,
|
||||||
navTimeout: null,
|
navTimeout: null,
|
||||||
hoverNav: false
|
hoverNav: false,
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['req', 'user', 'oldReq', 'jwt', 'loading', 'show']),
|
...mapState(["req", "user", "oldReq", "jwt", "loading", "show"]),
|
||||||
hasPrevious () {
|
hasPrevious() {
|
||||||
return (this.previousLink !== '')
|
return this.previousLink !== "";
|
||||||
},
|
},
|
||||||
hasNext () {
|
hasNext() {
|
||||||
return (this.nextLink !== '')
|
return this.nextLink !== "";
|
||||||
},
|
},
|
||||||
downloadUrl () {
|
downloadUrl() {
|
||||||
return `${baseURL}/api/raw${url.encodePath(this.req.path)}?auth=${this.jwt}`
|
return `${baseURL}/api/raw${url.encodePath(this.req.path)}?auth=${
|
||||||
|
this.jwt
|
||||||
|
}`;
|
||||||
},
|
},
|
||||||
previewUrl () {
|
previewUrl() {
|
||||||
// reload the image when the file is replaced
|
// reload the image when the file is replaced
|
||||||
const key = Date.parse(this.req.modified)
|
const key = Date.parse(this.req.modified);
|
||||||
|
|
||||||
if (this.req.type === 'image' && !this.fullSize) {
|
if (this.req.type === "image" && !this.fullSize) {
|
||||||
return `${baseURL}/api/preview/big${url.encodePath(this.req.path)}?auth=${this.jwt}&k=${key}`
|
return `${baseURL}/api/preview/big${url.encodePath(
|
||||||
|
this.req.path
|
||||||
|
)}?auth=${this.jwt}&k=${key}`;
|
||||||
}
|
}
|
||||||
return `${baseURL}/api/raw${url.encodePath(this.req.path)}?auth=${this.jwt}&k=${key}`
|
return `${baseURL}/api/raw${url.encodePath(this.req.path)}?auth=${
|
||||||
|
this.jwt
|
||||||
|
}&k=${key}`;
|
||||||
},
|
},
|
||||||
raw () {
|
raw() {
|
||||||
return `${this.previewUrl}&inline=true`
|
return `${this.previewUrl}&inline=true`;
|
||||||
},
|
},
|
||||||
showMore () {
|
showMore() {
|
||||||
return this.$store.state.show === 'more'
|
return this.$store.state.show === "more";
|
||||||
|
},
|
||||||
|
isResizeEnabled() {
|
||||||
|
return resizePreview;
|
||||||
},
|
},
|
||||||
isResizeEnabled () {
|
|
||||||
return resizePreview
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
$route: function () {
|
$route: function () {
|
||||||
this.updatePreview()
|
this.updatePreview();
|
||||||
this.toggleNavigation()
|
this.toggleNavigation();
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
async mounted () {
|
async mounted() {
|
||||||
window.addEventListener('keydown', this.key)
|
window.addEventListener("keydown", this.key);
|
||||||
this.listing = this.oldReq.items
|
this.listing = this.oldReq.items;
|
||||||
this.updatePreview()
|
this.updatePreview();
|
||||||
},
|
},
|
||||||
beforeDestroy () {
|
beforeDestroy() {
|
||||||
window.removeEventListener('keydown', this.key)
|
window.removeEventListener("keydown", this.key);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
deleteFile () {
|
deleteFile() {
|
||||||
this.$store.commit('showHover', {
|
this.$store.commit("showHover", {
|
||||||
prompt: 'delete',
|
prompt: "delete",
|
||||||
confirm: () => {
|
confirm: () => {
|
||||||
this.listing = this.listing.filter(item => item.name !== this.name)
|
this.listing = this.listing.filter((item) => item.name !== this.name);
|
||||||
|
|
||||||
if (this.hasNext) {
|
if (this.hasNext) {
|
||||||
this.next()
|
this.next();
|
||||||
} else if (!this.hasPrevious && !this.hasNext) {
|
} else if (!this.hasPrevious && !this.hasNext) {
|
||||||
this.close()
|
this.close();
|
||||||
} else {
|
} else {
|
||||||
this.prev()
|
this.prev();
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
prev () {
|
prev() {
|
||||||
this.hoverNav = false
|
this.hoverNav = false;
|
||||||
this.$router.push({ path: this.previousLink })
|
this.$router.push({ path: this.previousLink });
|
||||||
},
|
},
|
||||||
next () {
|
next() {
|
||||||
this.hoverNav = false
|
this.hoverNav = false;
|
||||||
this.$router.push({ path: this.nextLink })
|
this.$router.push({ path: this.nextLink });
|
||||||
},
|
},
|
||||||
key (event) {
|
key(event) {
|
||||||
|
|
||||||
if (this.show !== null) {
|
if (this.show !== null) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.which === 13 || event.which === 39) { // right arrow
|
if (event.which === 13 || event.which === 39) {
|
||||||
if (this.hasNext) this.next()
|
// right arrow
|
||||||
} else if (event.which === 37) { // left arrow
|
if (this.hasNext) this.next();
|
||||||
if (this.hasPrevious) this.prev()
|
} else if (event.which === 37) {
|
||||||
} else if (event.which === 27) { // esc
|
// left arrow
|
||||||
this.close()
|
if (this.hasPrevious) this.prev();
|
||||||
|
} else if (event.which === 27) {
|
||||||
|
// esc
|
||||||
|
this.close();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async updatePreview () {
|
async updatePreview() {
|
||||||
if (this.req.subtitles) {
|
if (this.req.subtitles) {
|
||||||
this.subtitles = this.req.subtitles.map(sub => `${baseURL}/api/raw${sub}?auth=${this.jwt}&inline=true`)
|
this.subtitles = this.req.subtitles.map(
|
||||||
|
(sub) => `${baseURL}/api/raw${sub}?auth=${this.jwt}&inline=true`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let dirs = this.$route.fullPath.split("/")
|
let dirs = this.$route.fullPath.split("/");
|
||||||
this.name = decodeURIComponent(dirs[dirs.length - 1])
|
this.name = decodeURIComponent(dirs[dirs.length - 1]);
|
||||||
|
|
||||||
if (!this.listing) {
|
if (!this.listing) {
|
||||||
try {
|
try {
|
||||||
const path = url.removeLastDir(this.$route.path)
|
const path = url.removeLastDir(this.$route.path);
|
||||||
const res = await api.fetch(path)
|
const res = await api.fetch(path);
|
||||||
this.listing = res.items
|
this.listing = res.items;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$showError(e)
|
this.$showError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.previousLink = ''
|
this.previousLink = "";
|
||||||
this.nextLink = ''
|
this.nextLink = "";
|
||||||
|
|
||||||
for (let i = 0; i < this.listing.length; i++) {
|
for (let i = 0; i < this.listing.length; i++) {
|
||||||
if (this.listing[i].name !== this.name) {
|
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(this.listing[j].type)) {
|
if (mediaTypes.includes(this.listing[j].type)) {
|
||||||
this.previousLink = this.listing[j].url
|
this.previousLink = this.listing[j].url;
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let j = i + 1; j < this.listing.length; j++) {
|
for (let j = i + 1; j < this.listing.length; j++) {
|
||||||
if (mediaTypes.includes(this.listing[j].type)) {
|
if (mediaTypes.includes(this.listing[j].type)) {
|
||||||
this.nextLink = this.listing[j].url
|
this.nextLink = this.listing[j].url;
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
openMore () {
|
openMore() {
|
||||||
this.$store.commit('showHover', 'more')
|
this.$store.commit("showHover", "more");
|
||||||
},
|
},
|
||||||
resetPrompts () {
|
resetPrompts() {
|
||||||
this.$store.commit('closeHovers')
|
this.$store.commit("closeHovers");
|
||||||
},
|
},
|
||||||
toggleSize () {
|
toggleSize() {
|
||||||
this.fullSize = !this.fullSize
|
this.fullSize = !this.fullSize;
|
||||||
},
|
},
|
||||||
toggleNavigation: throttle(function() {
|
toggleNavigation: throttle(function () {
|
||||||
this.showNav = true
|
this.showNav = true;
|
||||||
|
|
||||||
if (this.navTimeout) {
|
if (this.navTimeout) {
|
||||||
clearTimeout(this.navTimeout)
|
clearTimeout(this.navTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.navTimeout = setTimeout(() => {
|
this.navTimeout = setTimeout(() => {
|
||||||
this.showNav = false || this.hoverNav
|
this.showNav = false || this.hoverNav;
|
||||||
this.navTimeout = null
|
this.navTimeout = null;
|
||||||
}, 1500);
|
}, 1500);
|
||||||
}, 500),
|
}, 500),
|
||||||
close () {
|
close() {
|
||||||
this.$store.commit('updateRequest', {})
|
this.$store.commit("updateRequest", {});
|
||||||
|
|
||||||
let uri = url.removeLastDir(this.$route.path) + '/'
|
let uri = url.removeLastDir(this.$route.path) + "/";
|
||||||
this.$router.push({ path: uri })
|
this.$router.push({ path: uri });
|
||||||
},
|
},
|
||||||
download() {
|
download() {
|
||||||
api.download(null, this.$route.path)
|
api.download(null, this.$route.path);
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -3,54 +3,93 @@
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<form class="card" @submit.prevent="save">
|
<form class="card" @submit.prevent="save">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
<h2>{{ $t('settings.globalSettings') }}</h2>
|
<h2>{{ $t("settings.globalSettings") }}</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<p><input type="checkbox" v-model="settings.signup"> {{ $t('settings.allowSignup') }}</p>
|
<p>
|
||||||
|
<input type="checkbox" v-model="settings.signup" />
|
||||||
|
{{ $t("settings.allowSignup") }}
|
||||||
|
</p>
|
||||||
|
|
||||||
<p><input type="checkbox" v-model="settings.createUserDir"> {{ $t('settings.createUserDir') }}</p>
|
<p>
|
||||||
|
<input type="checkbox" v-model="settings.createUserDir" />
|
||||||
|
{{ $t("settings.createUserDir") }}
|
||||||
|
</p>
|
||||||
|
|
||||||
<h3>{{ $t('settings.rules') }}</h3>
|
<h3>{{ $t("settings.rules") }}</h3>
|
||||||
<p class="small">{{ $t('settings.globalRules') }}</p>
|
<p class="small">{{ $t("settings.globalRules") }}</p>
|
||||||
<rules :rules.sync="settings.rules" />
|
<rules :rules.sync="settings.rules" />
|
||||||
|
|
||||||
<div v-if="isExecEnabled">
|
<div v-if="isExecEnabled">
|
||||||
<h3>{{ $t('settings.executeOnShell') }}</h3>
|
<h3>{{ $t("settings.executeOnShell") }}</h3>
|
||||||
<p class="small">{{ $t('settings.executeOnShellDescription') }}</p>
|
<p class="small">{{ $t("settings.executeOnShellDescription") }}</p>
|
||||||
<input class="input input--block" type="text" placeholder="bash -c, cmd /c, ..." v-model="settings.shell" />
|
<input
|
||||||
|
class="input input--block"
|
||||||
|
type="text"
|
||||||
|
placeholder="bash -c, cmd /c, ..."
|
||||||
|
v-model="settings.shell"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3>{{ $t('settings.branding') }}</h3>
|
<h3>{{ $t("settings.branding") }}</h3>
|
||||||
|
|
||||||
<i18n path="settings.brandingHelp" tag="p" class="small">
|
<i18n path="settings.brandingHelp" tag="p" class="small">
|
||||||
<a class="link" target="_blank" href="https://filebrowser.org/configuration/custom-branding">{{ $t('settings.documentation') }}</a>
|
<a
|
||||||
|
class="link"
|
||||||
|
target="_blank"
|
||||||
|
href="https://filebrowser.org/configuration/custom-branding"
|
||||||
|
>{{ $t("settings.documentation") }}</a
|
||||||
|
>
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<input type="checkbox" v-model="settings.branding.disableExternal" id="branding-links" />
|
<input
|
||||||
{{ $t('settings.disableExternalLinks') }}
|
type="checkbox"
|
||||||
|
v-model="settings.branding.disableExternal"
|
||||||
|
id="branding-links"
|
||||||
|
/>
|
||||||
|
{{ $t("settings.disableExternalLinks") }}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<label for="theme">{{ $t('settings.themes.title') }}</label>
|
<label for="theme">{{ $t("settings.themes.title") }}</label>
|
||||||
<themes class="input input--block" :theme.sync="settings.branding.theme" id="theme"></themes>
|
<themes
|
||||||
|
class="input input--block"
|
||||||
|
:theme.sync="settings.branding.theme"
|
||||||
|
id="theme"
|
||||||
|
></themes>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<label for="branding-name">{{ $t('settings.instanceName') }}</label>
|
<label for="branding-name">{{ $t("settings.instanceName") }}</label>
|
||||||
<input class="input input--block" type="text" v-model="settings.branding.name" id="branding-name" />
|
<input
|
||||||
|
class="input input--block"
|
||||||
|
type="text"
|
||||||
|
v-model="settings.branding.name"
|
||||||
|
id="branding-name"
|
||||||
|
/>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<label for="branding-files">{{ $t('settings.brandingDirectoryPath') }}</label>
|
<label for="branding-files">{{
|
||||||
<input class="input input--block" type="text" v-model="settings.branding.files" id="branding-files" />
|
$t("settings.brandingDirectoryPath")
|
||||||
|
}}</label>
|
||||||
|
<input
|
||||||
|
class="input input--block"
|
||||||
|
type="text"
|
||||||
|
v-model="settings.branding.files"
|
||||||
|
id="branding-files"
|
||||||
|
/>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-action">
|
<div class="card-action">
|
||||||
<input class="button button--flat" type="submit" :value="$t('buttons.update')">
|
<input
|
||||||
|
class="button button--flat"
|
||||||
|
type="submit"
|
||||||
|
:value="$t('buttons.update')"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -58,17 +97,25 @@
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<form class="card" @submit.prevent="save">
|
<form class="card" @submit.prevent="save">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
<h2>{{ $t('settings.userDefaults') }}</h2>
|
<h2>{{ $t("settings.userDefaults") }}</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<p class="small">{{ $t('settings.defaultUserDescription') }}</p>
|
<p class="small">{{ $t("settings.defaultUserDescription") }}</p>
|
||||||
|
|
||||||
<user-form :isNew="false" :isDefault="true" :user.sync="settings.defaults" />
|
<user-form
|
||||||
|
:isNew="false"
|
||||||
|
:isDefault="true"
|
||||||
|
:user.sync="settings.defaults"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-action">
|
<div class="card-action">
|
||||||
<input class="button button--flat" type="submit" :value="$t('buttons.update')">
|
<input
|
||||||
|
class="button button--flat"
|
||||||
|
type="submit"
|
||||||
|
:value="$t('buttons.update')"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -76,30 +123,46 @@
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<form v-if="isExecEnabled" class="card" @submit.prevent="save">
|
<form v-if="isExecEnabled" class="card" @submit.prevent="save">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
<h2>{{ $t('settings.commandRunner') }}</h2>
|
<h2>{{ $t("settings.commandRunner") }}</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<i18n path="settings.commandRunnerHelp" tag="p" class="small">
|
<i18n path="settings.commandRunnerHelp" tag="p" class="small">
|
||||||
<code>FILE</code>
|
<code>FILE</code>
|
||||||
<code>SCOPE</code>
|
<code>SCOPE</code>
|
||||||
<a class="link" target="_blank" href="https://filebrowser.org/configuration/command-runner">{{ $t('settings.documentation') }}</a>
|
<a
|
||||||
|
class="link"
|
||||||
|
target="_blank"
|
||||||
|
href="https://filebrowser.org/configuration/command-runner"
|
||||||
|
>{{ $t("settings.documentation") }}</a
|
||||||
|
>
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|
||||||
<div v-for="command in settings.commands" :key="command.name" class="collapsible">
|
<div
|
||||||
<input :id="command.name" type="checkbox">
|
v-for="command in settings.commands"
|
||||||
|
:key="command.name"
|
||||||
|
class="collapsible"
|
||||||
|
>
|
||||||
|
<input :id="command.name" type="checkbox" />
|
||||||
<label :for="command.name">
|
<label :for="command.name">
|
||||||
<p>{{ capitalize(command.name) }}</p>
|
<p>{{ capitalize(command.name) }}</p>
|
||||||
<i class="material-icons">arrow_drop_down</i>
|
<i class="material-icons">arrow_drop_down</i>
|
||||||
</label>
|
</label>
|
||||||
<div class="collapse">
|
<div class="collapse">
|
||||||
<textarea class="input input--block input--textarea" v-model.trim="command.value"></textarea>
|
<textarea
|
||||||
|
class="input input--block input--textarea"
|
||||||
|
v-model.trim="command.value"
|
||||||
|
></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-action">
|
<div class="card-action">
|
||||||
<input class="button button--flat" type="submit" :value="$t('buttons.update')">
|
<input
|
||||||
|
class="button button--flat"
|
||||||
|
type="submit"
|
||||||
|
:value="$t('buttons.update')"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -107,80 +170,84 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from "vuex";
|
||||||
import { settings as api } from '@/api'
|
import { settings as api } from "@/api";
|
||||||
import UserForm from '@/components/settings/UserForm'
|
import UserForm from "@/components/settings/UserForm";
|
||||||
import Rules from '@/components/settings/Rules'
|
import Rules from "@/components/settings/Rules";
|
||||||
import Themes from '@/components/settings/Themes'
|
import Themes from "@/components/settings/Themes";
|
||||||
import { enableExec } from '@/utils/constants'
|
import { enableExec } from "@/utils/constants";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'settings',
|
name: "settings",
|
||||||
components: {
|
components: {
|
||||||
Themes,
|
Themes,
|
||||||
UserForm,
|
UserForm,
|
||||||
Rules
|
Rules,
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
originalSettings: null,
|
originalSettings: null,
|
||||||
settings: null
|
settings: null,
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState([ 'user' ]),
|
...mapState(["user"]),
|
||||||
isExecEnabled: () => enableExec
|
isExecEnabled: () => enableExec,
|
||||||
},
|
},
|
||||||
async created () {
|
async created() {
|
||||||
try {
|
try {
|
||||||
const original = await api.get()
|
const original = await api.get();
|
||||||
let settings = { ...original, commands: [] }
|
let settings = { ...original, commands: [] };
|
||||||
|
|
||||||
for (const key in original.commands) {
|
for (const key in original.commands) {
|
||||||
settings.commands.push({
|
settings.commands.push({
|
||||||
name: key,
|
name: key,
|
||||||
value: original.commands[key].join('\n')
|
value: original.commands[key].join("\n"),
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.shell = settings.shell.join(' ')
|
settings.shell = settings.shell.join(" ");
|
||||||
|
|
||||||
this.originalSettings = original
|
this.originalSettings = original;
|
||||||
this.settings = settings
|
this.settings = settings;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$showError(e)
|
this.$showError(e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
capitalize (name, where = '_') {
|
capitalize(name, where = "_") {
|
||||||
if (where === 'caps') where = /(?=[A-Z])/
|
if (where === "caps") where = /(?=[A-Z])/;
|
||||||
let splitted = name.split(where)
|
let splitted = name.split(where);
|
||||||
name = ''
|
name = "";
|
||||||
|
|
||||||
for (let i = 0; i < splitted.length; i++) {
|
for (let i = 0; i < splitted.length; i++) {
|
||||||
name += splitted[i].charAt(0).toUpperCase() + splitted[i].slice(1) + ' '
|
name +=
|
||||||
|
splitted[i].charAt(0).toUpperCase() + splitted[i].slice(1) + " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
return name.slice(0, -1)
|
return name.slice(0, -1);
|
||||||
},
|
},
|
||||||
async save () {
|
async save() {
|
||||||
let settings = {
|
let settings = {
|
||||||
...this.settings,
|
...this.settings,
|
||||||
shell: this.settings.shell.trim().split(' ').filter(s => s !== ''),
|
shell: this.settings.shell
|
||||||
commands: {}
|
.trim()
|
||||||
}
|
.split(" ")
|
||||||
|
.filter((s) => s !== ""),
|
||||||
|
commands: {},
|
||||||
|
};
|
||||||
|
|
||||||
for (const { name, value } of this.settings.commands) {
|
for (const { name, value } of this.settings.commands) {
|
||||||
settings.commands[name] = value.split('\n').filter(cmd => cmd !== '')
|
settings.commands[name] = value.split("\n").filter((cmd) => cmd !== "");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await api.update(settings)
|
await api.update(settings);
|
||||||
this.$showSuccess(this.$t('settings.settingsUpdated'))
|
this.$showSuccess(this.$t("settings.settingsUpdated"));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$showError(e)
|
this.$showError(e);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -3,18 +3,31 @@
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<form class="card" @submit="updateSettings">
|
<form class="card" @submit="updateSettings">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
<h2>{{ $t('settings.profileSettings') }}</h2>
|
<h2>{{ $t("settings.profileSettings") }}</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<p><input type="checkbox" v-model="hideDotfiles"> {{ $t('settings.hideDotfiles') }}</p>
|
<p>
|
||||||
<p><input type="checkbox" v-model="singleClick"> {{ $t('settings.singleClick') }}</p>
|
<input type="checkbox" v-model="hideDotfiles" />
|
||||||
<h3>{{ $t('settings.language') }}</h3>
|
{{ $t("settings.hideDotfiles") }}
|
||||||
<languages class="input input--block" :locale.sync="locale"></languages>
|
</p>
|
||||||
|
<p>
|
||||||
|
<input type="checkbox" v-model="singleClick" />
|
||||||
|
{{ $t("settings.singleClick") }}
|
||||||
|
</p>
|
||||||
|
<h3>{{ $t("settings.language") }}</h3>
|
||||||
|
<languages
|
||||||
|
class="input input--block"
|
||||||
|
:locale.sync="locale"
|
||||||
|
></languages>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-action">
|
<div class="card-action">
|
||||||
<input class="button button--flat" type="submit" :value="$t('buttons.update')">
|
<input
|
||||||
|
class="button button--flat"
|
||||||
|
type="submit"
|
||||||
|
:value="$t('buttons.update')"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -22,16 +35,32 @@
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<form class="card" v-if="!user.lockPassword" @submit="updatePassword">
|
<form class="card" v-if="!user.lockPassword" @submit="updatePassword">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
<h2>{{ $t('settings.changePassword') }}</h2>
|
<h2>{{ $t("settings.changePassword") }}</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<input :class="passwordClass" type="password" :placeholder="$t('settings.newPassword')" v-model="password" name="password">
|
<input
|
||||||
<input :class="passwordClass" type="password" :placeholder="$t('settings.newPasswordConfirm')" v-model="passwordConf" name="password">
|
:class="passwordClass"
|
||||||
|
type="password"
|
||||||
|
:placeholder="$t('settings.newPassword')"
|
||||||
|
v-model="password"
|
||||||
|
name="password"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
:class="passwordClass"
|
||||||
|
type="password"
|
||||||
|
:placeholder="$t('settings.newPasswordConfirm')"
|
||||||
|
v-model="passwordConf"
|
||||||
|
name="password"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-action">
|
<div class="card-action">
|
||||||
<input class="button button--flat" type="submit" :value="$t('buttons.update')">
|
<input
|
||||||
|
class="button button--flat"
|
||||||
|
type="submit"
|
||||||
|
:value="$t('buttons.update')"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -39,75 +68,80 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState, mapMutations } from 'vuex'
|
import { mapState, mapMutations } from "vuex";
|
||||||
import { users as api } from '@/api'
|
import { users as api } from "@/api";
|
||||||
import Languages from '@/components/settings/Languages'
|
import Languages from "@/components/settings/Languages";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'settings',
|
name: "settings",
|
||||||
components: {
|
components: {
|
||||||
Languages
|
Languages,
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
password: '',
|
password: "",
|
||||||
passwordConf: '',
|
passwordConf: "",
|
||||||
hideDotfiles: false,
|
hideDotfiles: false,
|
||||||
singleClick: false,
|
singleClick: false,
|
||||||
locale: ''
|
locale: "",
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState([ 'user' ]),
|
...mapState(["user"]),
|
||||||
passwordClass () {
|
passwordClass() {
|
||||||
const baseClass = 'input input--block'
|
const baseClass = "input input--block";
|
||||||
|
|
||||||
if (this.password === '' && this.passwordConf === '') {
|
if (this.password === "" && this.passwordConf === "") {
|
||||||
return baseClass
|
return baseClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.password === this.passwordConf) {
|
if (this.password === this.passwordConf) {
|
||||||
return `${baseClass} input--green`
|
return `${baseClass} input--green`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return `${baseClass} input--red`
|
return `${baseClass} input--red`;
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
created () {
|
created() {
|
||||||
this.locale = this.user.locale
|
this.locale = this.user.locale;
|
||||||
this.hideDotfiles = this.user.hideDotfiles
|
this.hideDotfiles = this.user.hideDotfiles;
|
||||||
this.singleClick = this.user.singleClick
|
this.singleClick = this.user.singleClick;
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapMutations([ 'updateUser' ]),
|
...mapMutations(["updateUser"]),
|
||||||
async updatePassword (event) {
|
async updatePassword(event) {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
|
|
||||||
if (this.password !== this.passwordConf || this.password === '') {
|
if (this.password !== this.passwordConf || this.password === "") {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = { id: this.user.id, password: this.password }
|
const data = { id: this.user.id, password: this.password };
|
||||||
await api.update(data, ['password'])
|
await api.update(data, ["password"]);
|
||||||
this.updateUser(data)
|
this.updateUser(data);
|
||||||
this.$showSuccess(this.$t('settings.passwordUpdated'))
|
this.$showSuccess(this.$t("settings.passwordUpdated"));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$showError(e)
|
this.$showError(e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async updateSettings (event) {
|
async updateSettings(event) {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = { id: this.user.id, locale: this.locale, hideDotfiles: this.hideDotfiles, singleClick: this.singleClick }
|
const data = {
|
||||||
await api.update(data, ['locale', 'hideDotfiles', 'singleClick'])
|
id: this.user.id,
|
||||||
this.updateUser(data)
|
locale: this.locale,
|
||||||
this.$showSuccess(this.$t('settings.settingsUpdated'))
|
hideDotfiles: this.hideDotfiles,
|
||||||
|
singleClick: this.singleClick,
|
||||||
|
};
|
||||||
|
await api.update(data, ["locale", "hideDotfiles", "singleClick"]);
|
||||||
|
this.updateUser(data);
|
||||||
|
this.$showSuccess(this.$t("settings.settingsUpdated"));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$showError(e)
|
this.$showError(e);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -3,37 +3,51 @@
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
<h2>{{ $t('settings.shareManagement') }}</h2>
|
<h2>{{ $t("settings.shareManagement") }}</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-content full">
|
<div class="card-content full">
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{{ $t('settings.path') }}</th>
|
<th>{{ $t("settings.path") }}</th>
|
||||||
<th>{{ $t('settings.shareDuration') }}</th>
|
<th>{{ $t("settings.shareDuration") }}</th>
|
||||||
<th v-if="user.perm.admin">{{ $t('settings.username') }}</th>
|
<th v-if="user.perm.admin">{{ $t("settings.username") }}</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr v-for="link in links" :key="link.hash">
|
<tr v-for="link in links" :key="link.hash">
|
||||||
<td><a :href="buildLink(link.hash)" target="_blank">{{ link.path }}</a></td>
|
|
||||||
<td>
|
<td>
|
||||||
<template v-if="link.expire !== 0">{{ humanTime(link.expire) }}</template>
|
<a :href="buildLink(link.hash)" target="_blank">{{
|
||||||
<template v-else>{{ $t('permanent') }}</template>
|
link.path
|
||||||
|
}}</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<template v-if="link.expire !== 0">{{
|
||||||
|
humanTime(link.expire)
|
||||||
|
}}</template>
|
||||||
|
<template v-else>{{ $t("permanent") }}</template>
|
||||||
</td>
|
</td>
|
||||||
<td v-if="user.perm.admin">{{ link.username }}</td>
|
<td v-if="user.perm.admin">{{ link.username }}</td>
|
||||||
<td class="small">
|
<td class="small">
|
||||||
<button class="action"
|
<button
|
||||||
@click="deleteLink($event, link)"
|
class="action"
|
||||||
:aria-label="$t('buttons.delete')"
|
@click="deleteLink($event, link)"
|
||||||
:title="$t('buttons.delete')"><i class="material-icons">delete</i></button>
|
:aria-label="$t('buttons.delete')"
|
||||||
|
:title="$t('buttons.delete')"
|
||||||
|
>
|
||||||
|
<i class="material-icons">delete</i>
|
||||||
|
</button>
|
||||||
</td>
|
</td>
|
||||||
<td class="small">
|
<td class="small">
|
||||||
<button class="action copy-clipboard"
|
<button
|
||||||
:data-clipboard-text="buildLink(link.hash)"
|
class="action copy-clipboard"
|
||||||
:aria-label="$t('buttons.copyToClipboard')"
|
:data-clipboard-text="buildLink(link.hash)"
|
||||||
:title="$t('buttons.copyToClipboard')"><i class="material-icons">content_paste</i></button>
|
:aria-label="$t('buttons.copyToClipboard')"
|
||||||
|
:title="$t('buttons.copyToClipboard')"
|
||||||
|
>
|
||||||
|
<i class="material-icons">content_paste</i>
|
||||||
|
</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
@ -44,63 +58,67 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { share as api, users } from '@/api'
|
import { share as api, users } from "@/api";
|
||||||
import moment from 'moment'
|
import moment from "moment";
|
||||||
import {baseURL} from "@/utils/constants"
|
import { baseURL } from "@/utils/constants";
|
||||||
import Clipboard from 'clipboard'
|
import Clipboard from "clipboard";
|
||||||
import {mapState} from "vuex";
|
import { mapState } from "vuex";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'shares',
|
name: "shares",
|
||||||
computed: mapState([ 'user' ]),
|
computed: mapState(["user"]),
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
links: [],
|
links: [],
|
||||||
clip: null
|
clip: null,
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
async created () {
|
async created() {
|
||||||
try {
|
try {
|
||||||
let links = await api.list()
|
let links = await api.list();
|
||||||
if (this.user.perm.admin) {
|
if (this.user.perm.admin) {
|
||||||
let userMap = new Map()
|
let userMap = new Map();
|
||||||
for (let user of await users.getAll()) userMap.set(user.id, user.username)
|
for (let user of await users.getAll())
|
||||||
for (let link of links) link.username = userMap.has(link.userID) ? userMap.get(link.userID) : ''
|
userMap.set(user.id, user.username);
|
||||||
|
for (let link of links)
|
||||||
|
link.username = userMap.has(link.userID)
|
||||||
|
? userMap.get(link.userID)
|
||||||
|
: "";
|
||||||
}
|
}
|
||||||
this.links = links
|
this.links = links;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$showError(e)
|
this.$showError(e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.clip = new Clipboard('.copy-clipboard')
|
this.clip = new Clipboard(".copy-clipboard");
|
||||||
this.clip.on('success', () => {
|
this.clip.on("success", () => {
|
||||||
this.$showSuccess(this.$t('success.linkCopied'))
|
this.$showSuccess(this.$t("success.linkCopied"));
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
beforeDestroy () {
|
beforeDestroy() {
|
||||||
this.clip.destroy()
|
this.clip.destroy();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
deleteLink: async function (event, link) {
|
deleteLink: async function (event, link) {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
|
|
||||||
this.$store.commit('showHover', {
|
this.$store.commit("showHover", {
|
||||||
prompt: 'share-delete',
|
prompt: "share-delete",
|
||||||
confirm: () => {
|
confirm: () => {
|
||||||
this.$store.commit('closeHovers')
|
this.$store.commit("closeHovers");
|
||||||
|
|
||||||
api.remove(link.hash)
|
api.remove(link.hash);
|
||||||
this.links = this.links.filter(item => item.hash !== link.hash)
|
this.links = this.links.filter((item) => item.hash !== link.hash);
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
humanTime (time) {
|
humanTime(time) {
|
||||||
return moment(time * 1000).fromNow()
|
return moment(time * 1000).fromNow();
|
||||||
},
|
},
|
||||||
buildLink (hash) {
|
buildLink(hash) {
|
||||||
return `${window.location.origin}${baseURL}/share/${hash}`
|
return `${window.location.origin}${baseURL}/share/${hash}`;
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<form v-if="loaded" @submit="save" class="card">
|
<form v-if="loaded" @submit="save" class="card">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
<h2 v-if="user.id === 0">{{ $t('settings.newUser') }}</h2>
|
<h2 v-if="user.id === 0">{{ $t("settings.newUser") }}</h2>
|
||||||
<h2 v-else>{{ $t('settings.user') }} {{ user.username }}</h2>
|
<h2 v-else>{{ $t("settings.user") }} {{ user.username }}</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
|
@ -18,11 +18,15 @@
|
||||||
type="button"
|
type="button"
|
||||||
class="button button--flat button--red"
|
class="button button--flat button--red"
|
||||||
:aria-label="$t('buttons.delete')"
|
:aria-label="$t('buttons.delete')"
|
||||||
:title="$t('buttons.delete')">{{ $t('buttons.delete') }}</button>
|
:title="$t('buttons.delete')"
|
||||||
|
>
|
||||||
|
{{ $t("buttons.delete") }}
|
||||||
|
</button>
|
||||||
<input
|
<input
|
||||||
class="button button--flat"
|
class="button button--flat"
|
||||||
type="submit"
|
type="submit"
|
||||||
:value="$t('buttons.save')">
|
:value="$t('buttons.save')"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -33,16 +37,17 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-action">
|
<div class="card-action">
|
||||||
<button class="button button--flat button--grey"
|
<button
|
||||||
|
class="button button--flat button--grey"
|
||||||
@click="closeHovers"
|
@click="closeHovers"
|
||||||
v-focus
|
v-focus
|
||||||
:aria-label="$t('buttons.cancel')"
|
:aria-label="$t('buttons.cancel')"
|
||||||
:title="$t('buttons.cancel')">
|
:title="$t('buttons.cancel')"
|
||||||
{{ $t('buttons.cancel') }}
|
>
|
||||||
|
{{ $t("buttons.cancel") }}
|
||||||
</button>
|
</button>
|
||||||
<button class="button button--flat"
|
<button class="button button--flat" @click="deleteUser">
|
||||||
@click="deleteUser">
|
{{ $t("buttons.delete") }}
|
||||||
{{ $t('buttons.delete') }}
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -50,101 +55,103 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapMutations } from 'vuex'
|
import { mapMutations } from "vuex";
|
||||||
import { users as api, settings } from '@/api'
|
import { users as api, settings } from "@/api";
|
||||||
import UserForm from '@/components/settings/UserForm'
|
import UserForm from "@/components/settings/UserForm";
|
||||||
import deepClone from 'lodash.clonedeep'
|
import deepClone from "lodash.clonedeep";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'user',
|
name: "user",
|
||||||
components: {
|
components: {
|
||||||
UserForm
|
UserForm,
|
||||||
},
|
},
|
||||||
data: () => {
|
data: () => {
|
||||||
return {
|
return {
|
||||||
originalUser: null,
|
originalUser: null,
|
||||||
user: {},
|
user: {},
|
||||||
loaded: false
|
loaded: false,
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
created () {
|
created() {
|
||||||
this.fetchData()
|
this.fetchData();
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
isNew () {
|
isNew() {
|
||||||
return this.$route.path === '/settings/users/new'
|
return this.$route.path === "/settings/users/new";
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
'$route': 'fetchData',
|
$route: "fetchData",
|
||||||
'user.perm.admin': function () {
|
"user.perm.admin": function () {
|
||||||
if (!this.user.perm.admin) return
|
if (!this.user.perm.admin) return;
|
||||||
this.user.lockPassword = false
|
this.user.lockPassword = false;
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapMutations([ 'closeHovers', 'showHover', 'setUser' ]),
|
...mapMutations(["closeHovers", "showHover", "setUser"]),
|
||||||
async fetchData () {
|
async fetchData() {
|
||||||
try {
|
try {
|
||||||
if (this.isNew) {
|
if (this.isNew) {
|
||||||
let { defaults } = await settings.get()
|
let { defaults } = await settings.get();
|
||||||
this.user = {
|
this.user = {
|
||||||
...defaults,
|
...defaults,
|
||||||
username: '',
|
username: "",
|
||||||
passsword: '',
|
passsword: "",
|
||||||
rules: [],
|
rules: [],
|
||||||
lockPassword: false,
|
lockPassword: false,
|
||||||
id: 0
|
id: 0,
|
||||||
}
|
};
|
||||||
} else {
|
} else {
|
||||||
const id = this.$route.params.pathMatch
|
const id = this.$route.params.pathMatch;
|
||||||
this.user = { ...await api.get(id) }
|
this.user = { ...(await api.get(id)) };
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loaded = true
|
this.loaded = true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$router.push({ path: '/settings/users/new' })
|
this.$router.push({ path: "/settings/users/new" });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
deletePrompt () {
|
deletePrompt() {
|
||||||
this.showHover('deleteUser')
|
this.showHover("deleteUser");
|
||||||
},
|
},
|
||||||
async deleteUser (event) {
|
async deleteUser(event) {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await api.remove(this.user.id)
|
await api.remove(this.user.id);
|
||||||
this.$router.push({ path: '/settings/users' })
|
this.$router.push({ path: "/settings/users" });
|
||||||
this.$showSuccess(this.$t('settings.userDeleted'))
|
this.$showSuccess(this.$t("settings.userDeleted"));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
(e.message === "403") ? this.$showError(this.$t("errors.forbidden"), false) : this.$showError(e)
|
e.message === "403"
|
||||||
|
? this.$showError(this.$t("errors.forbidden"), false)
|
||||||
|
: this.$showError(e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async save (event) {
|
async save(event) {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
let user = {
|
let user = {
|
||||||
...this.originalUser,
|
...this.originalUser,
|
||||||
...this.user
|
...this.user,
|
||||||
}
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (this.isNew) {
|
if (this.isNew) {
|
||||||
const loc = await api.create(user)
|
const loc = await api.create(user);
|
||||||
this.$router.push({ path: loc })
|
this.$router.push({ path: loc });
|
||||||
this.$showSuccess(this.$t('settings.userCreated'))
|
this.$showSuccess(this.$t("settings.userCreated"));
|
||||||
} else {
|
} else {
|
||||||
await api.update(user)
|
await api.update(user);
|
||||||
|
|
||||||
if (user.id === this.$store.state.user.id) {
|
if (user.id === this.$store.state.user.id) {
|
||||||
this.setUser({ ...deepClone(user) })
|
this.setUser({ ...deepClone(user) });
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$showSuccess(this.$t('settings.userUpdated'))
|
this.$showSuccess(this.$t("settings.userUpdated"));
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$showError(e)
|
this.$showError(e);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -3,25 +3,34 @@
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
<h2>{{ $t('settings.users') }}</h2>
|
<h2>{{ $t("settings.users") }}</h2>
|
||||||
<router-link to="/settings/users/new"><button class="button">{{ $t('buttons.new') }}</button></router-link>
|
<router-link to="/settings/users/new"
|
||||||
|
><button class="button">
|
||||||
|
{{ $t("buttons.new") }}
|
||||||
|
</button></router-link
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-content full">
|
<div class="card-content full">
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{{ $t('settings.username') }}</th>
|
<th>{{ $t("settings.username") }}</th>
|
||||||
<th>{{ $t('settings.admin') }}</th>
|
<th>{{ $t("settings.admin") }}</th>
|
||||||
<th>{{ $t('settings.scope') }}</th>
|
<th>{{ $t("settings.scope") }}</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr v-for="user in users" :key="user.id">
|
<tr v-for="user in users" :key="user.id">
|
||||||
<td>{{ user.username }}</td>
|
<td>{{ user.username }}</td>
|
||||||
<td><i v-if="user.perm.admin" class="material-icons">done</i><i v-else class="material-icons">close</i></td>
|
<td>
|
||||||
|
<i v-if="user.perm.admin" class="material-icons">done</i
|
||||||
|
><i v-else class="material-icons">close</i>
|
||||||
|
</td>
|
||||||
<td>{{ user.scope }}</td>
|
<td>{{ user.scope }}</td>
|
||||||
<td class="small">
|
<td class="small">
|
||||||
<router-link :to="'/settings/users/' + user.id"><i class="material-icons">mode_edit</i></router-link>
|
<router-link :to="'/settings/users/' + user.id"
|
||||||
|
><i class="material-icons">mode_edit</i></router-link
|
||||||
|
>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
@ -32,21 +41,21 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { users as api } from '@/api'
|
import { users as api } from "@/api";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'users',
|
name: "users",
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
users: []
|
users: [],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
async created() {
|
||||||
|
try {
|
||||||
|
this.users = await api.getAll();
|
||||||
|
} catch (e) {
|
||||||
|
this.$showError(e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async created () {
|
};
|
||||||
try {
|
|
||||||
this.users = await api.getAll()
|
|
||||||
} catch (e) {
|
|
||||||
this.$showError(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
runtimeCompiler: true,
|
runtimeCompiler: true,
|
||||||
publicPath: '[{[ .StaticURL ]}]',
|
publicPath: "[{[ .StaticURL ]}]",
|
||||||
parallel: 2,
|
parallel: 2,
|
||||||
}
|
};
|
||||||
|
|
Loading…
Reference in New Issue