chore: add prettier frontent linter
This commit is contained in:
		
							parent
							
								
									a721dc1f31
								
							
						
					
					
						commit
						c44b37c50c
					
				| 
						 | 
				
			
			@ -1,5 +1,3 @@
 | 
			
		|||
module.exports = {
 | 
			
		||||
  presets: [
 | 
			
		||||
    '@vue/app'
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
  presets: ["@vue/app"],
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
				
			
			@ -5,8 +5,9 @@
 | 
			
		|||
  "scripts": {
 | 
			
		||||
    "serve": "vue-cli-service serve",
 | 
			
		||||
    "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": "vue-cli-service lint --fix"
 | 
			
		||||
    "lint": "npx vue-cli-service lint --no-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": {
 | 
			
		||||
    "ace-builds": "^1.4.7",
 | 
			
		||||
| 
						 | 
				
			
			@ -29,11 +30,14 @@
 | 
			
		|||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@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",
 | 
			
		||||
    "babel-eslint": "^10.0.3",
 | 
			
		||||
    "@vue/eslint-config-prettier": "^6.0.0",
 | 
			
		||||
    "babel-eslint": "^10.1.0",
 | 
			
		||||
    "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"
 | 
			
		||||
  },
 | 
			
		||||
  "eslintConfig": {
 | 
			
		||||
| 
						 | 
				
			
			@ -43,7 +47,8 @@
 | 
			
		|||
    },
 | 
			
		||||
    "extends": [
 | 
			
		||||
      "plugin:vue/essential",
 | 
			
		||||
      "eslint:recommended"
 | 
			
		||||
      "eslint:recommended",
 | 
			
		||||
      "@vue/prettier"
 | 
			
		||||
    ],
 | 
			
		||||
    "rules": {},
 | 
			
		||||
    "parserOptions": {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,18 +6,18 @@
 | 
			
		|||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'app',
 | 
			
		||||
  mounted () {
 | 
			
		||||
    const loading = document.getElementById('loading')
 | 
			
		||||
    loading.classList.add('done')
 | 
			
		||||
  name: "app",
 | 
			
		||||
  mounted() {
 | 
			
		||||
    const loading = document.getElementById("loading");
 | 
			
		||||
    loading.classList.add("done");
 | 
			
		||||
 | 
			
		||||
    setTimeout(function () {
 | 
			
		||||
      loading.parentNode.removeChild(loading)
 | 
			
		||||
    }, 200)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
      loading.parentNode.removeChild(loading);
 | 
			
		||||
    }, 200);
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style>
 | 
			
		||||
@import './css/styles.css';
 | 
			
		||||
@import "./css/styles.css";
 | 
			
		||||
</style>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,16 +1,16 @@
 | 
			
		|||
import { removePrefix } from './utils'
 | 
			
		||||
import { baseURL } from '@/utils/constants'
 | 
			
		||||
import store from '@/store'
 | 
			
		||||
import { removePrefix } from "./utils";
 | 
			
		||||
import { baseURL } from "@/utils/constants";
 | 
			
		||||
import store from "@/store";
 | 
			
		||||
 | 
			
		||||
const ssl = (window.location.protocol === 'https:')
 | 
			
		||||
const protocol = (ssl ? 'wss:' : 'ws:')
 | 
			
		||||
const ssl = window.location.protocol === "https:";
 | 
			
		||||
const protocol = ssl ? "wss:" : "ws:";
 | 
			
		||||
 | 
			
		||||
export default function command(url, command, onmessage, onclose) {
 | 
			
		||||
  url = removePrefix(url)
 | 
			
		||||
  url = `${protocol}//${window.location.host}${baseURL}/api/command${url}?auth=${store.state.jwt}`
 | 
			
		||||
  url = removePrefix(url);
 | 
			
		||||
  url = `${protocol}//${window.location.host}${baseURL}/api/command${url}?auth=${store.state.jwt}`;
 | 
			
		||||
 | 
			
		||||
  let conn = new window.WebSocket(url)
 | 
			
		||||
  conn.onopen = () => conn.send(command)
 | 
			
		||||
  conn.onmessage = onmessage
 | 
			
		||||
  conn.onclose = onclose
 | 
			
		||||
  let conn = new window.WebSocket(url);
 | 
			
		||||
  conn.onopen = () => conn.send(command);
 | 
			
		||||
  conn.onmessage = onmessage;
 | 
			
		||||
  conn.onclose = onclose;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,147 +1,156 @@
 | 
			
		|||
import { fetchURL, removePrefix } from './utils'
 | 
			
		||||
import { baseURL } from '@/utils/constants'
 | 
			
		||||
import store from '@/store'
 | 
			
		||||
import { fetchURL, removePrefix } from "./utils";
 | 
			
		||||
import { baseURL } from "@/utils/constants";
 | 
			
		||||
import store from "@/store";
 | 
			
		||||
 | 
			
		||||
export async function fetch (url) {
 | 
			
		||||
  url = removePrefix(url)
 | 
			
		||||
export async function fetch(url) {
 | 
			
		||||
  url = removePrefix(url);
 | 
			
		||||
 | 
			
		||||
  const res = await fetchURL(`/api/resources${url}`, {})
 | 
			
		||||
  const res = await fetchURL(`/api/resources${url}`, {});
 | 
			
		||||
 | 
			
		||||
  if (res.status === 200) {
 | 
			
		||||
    let data = await res.json()
 | 
			
		||||
    data.url = `/files${url}`
 | 
			
		||||
    let data = await res.json();
 | 
			
		||||
    data.url = `/files${url}`;
 | 
			
		||||
 | 
			
		||||
    if (data.isDir) {
 | 
			
		||||
      if (!data.url.endsWith('/')) data.url += '/'
 | 
			
		||||
      if (!data.url.endsWith("/")) data.url += "/";
 | 
			
		||||
      data.items = data.items.map((item, index) => {
 | 
			
		||||
        item.index = index
 | 
			
		||||
        item.url = `${data.url}${encodeURIComponent(item.name)}`
 | 
			
		||||
        item.index = index;
 | 
			
		||||
        item.url = `${data.url}${encodeURIComponent(item.name)}`;
 | 
			
		||||
 | 
			
		||||
        if (item.isDir) {
 | 
			
		||||
          item.url += '/'
 | 
			
		||||
          item.url += "/";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return item
 | 
			
		||||
      })
 | 
			
		||||
        return item;
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return data
 | 
			
		||||
    return data;
 | 
			
		||||
  } else {
 | 
			
		||||
    throw new Error(res.status)
 | 
			
		||||
    throw new Error(res.status);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function resourceAction (url, method, content) {
 | 
			
		||||
  url = removePrefix(url)
 | 
			
		||||
async function resourceAction(url, method, content) {
 | 
			
		||||
  url = removePrefix(url);
 | 
			
		||||
 | 
			
		||||
  let opts = { method }
 | 
			
		||||
  let opts = { method };
 | 
			
		||||
 | 
			
		||||
  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) {
 | 
			
		||||
    throw new Error(await res.text())
 | 
			
		||||
    throw new Error(await res.text());
 | 
			
		||||
  } else {
 | 
			
		||||
    return res
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function remove (url) {
 | 
			
		||||
  return resourceAction(url, 'DELETE')
 | 
			
		||||
export async function remove(url) {
 | 
			
		||||
  return resourceAction(url, "DELETE");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function put (url, content = '') {
 | 
			
		||||
  return resourceAction(url, 'PUT', content)
 | 
			
		||||
export async function put(url, content = "") {
 | 
			
		||||
  return resourceAction(url, "PUT", content);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function download (format, ...files) {
 | 
			
		||||
  let url = `${baseURL}/api/raw`
 | 
			
		||||
export function download(format, ...files) {
 | 
			
		||||
  let url = `${baseURL}/api/raw`;
 | 
			
		||||
 | 
			
		||||
  if (files.length === 1) {
 | 
			
		||||
    url += removePrefix(files[0]) + '?'
 | 
			
		||||
    url += removePrefix(files[0]) + "?";
 | 
			
		||||
  } else {
 | 
			
		||||
    let arg = ''
 | 
			
		||||
    let arg = "";
 | 
			
		||||
 | 
			
		||||
    for (let file of files) {
 | 
			
		||||
      arg += removePrefix(file) + ','
 | 
			
		||||
      arg += removePrefix(file) + ",";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    arg = arg.substring(0, arg.length - 1)
 | 
			
		||||
    arg = encodeURIComponent(arg)
 | 
			
		||||
    url += `/?files=${arg}&`
 | 
			
		||||
    arg = arg.substring(0, arg.length - 1);
 | 
			
		||||
    arg = encodeURIComponent(arg);
 | 
			
		||||
    url += `/?files=${arg}&`;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (format) {
 | 
			
		||||
    url += `algo=${format}&`
 | 
			
		||||
    url += `algo=${format}&`;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (store.state.jwt){
 | 
			
		||||
    url += `auth=${store.state.jwt}&`
 | 
			
		||||
  if (store.state.jwt) {
 | 
			
		||||
    url += `auth=${store.state.jwt}&`;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  window.open(url)
 | 
			
		||||
  window.open(url);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function post (url, content = '', overwrite = false, onupload) {
 | 
			
		||||
  url = removePrefix(url)
 | 
			
		||||
export async function post(url, content = "", overwrite = false, onupload) {
 | 
			
		||||
  url = removePrefix(url);
 | 
			
		||||
 | 
			
		||||
  let bufferContent
 | 
			
		||||
  if (content instanceof Blob && !['http:', 'https:'].includes(window.location.protocol)) {
 | 
			
		||||
    bufferContent = await new Response(content).arrayBuffer()
 | 
			
		||||
  let bufferContent;
 | 
			
		||||
  if (
 | 
			
		||||
    content instanceof Blob &&
 | 
			
		||||
    !["http:", "https:"].includes(window.location.protocol)
 | 
			
		||||
  ) {
 | 
			
		||||
    bufferContent = await new Response(content).arrayBuffer();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return new Promise((resolve, reject) => {
 | 
			
		||||
    let request = new XMLHttpRequest()
 | 
			
		||||
    request.open('POST', `${baseURL}/api/resources${url}?override=${overwrite}`, true)
 | 
			
		||||
    request.setRequestHeader('X-Auth', store.state.jwt)
 | 
			
		||||
    let request = new XMLHttpRequest();
 | 
			
		||||
    request.open(
 | 
			
		||||
      "POST",
 | 
			
		||||
      `${baseURL}/api/resources${url}?override=${overwrite}`,
 | 
			
		||||
      true
 | 
			
		||||
    );
 | 
			
		||||
    request.setRequestHeader("X-Auth", store.state.jwt);
 | 
			
		||||
 | 
			
		||||
    if (typeof onupload === 'function') {
 | 
			
		||||
      request.upload.onprogress = onupload
 | 
			
		||||
    if (typeof onupload === "function") {
 | 
			
		||||
      request.upload.onprogress = onupload;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    request.onload = () => {
 | 
			
		||||
      if (request.status === 200) {
 | 
			
		||||
        resolve(request.responseText)
 | 
			
		||||
        resolve(request.responseText);
 | 
			
		||||
      } else if (request.status === 409) {
 | 
			
		||||
        reject(request.status)
 | 
			
		||||
        reject(request.status);
 | 
			
		||||
      } else {
 | 
			
		||||
        reject(request.responseText)
 | 
			
		||||
        reject(request.responseText);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    request.onerror = (error) => {
 | 
			
		||||
      reject(error)
 | 
			
		||||
    }
 | 
			
		||||
      reject(error);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    request.send(bufferContent || content)
 | 
			
		||||
  })
 | 
			
		||||
    request.send(bufferContent || content);
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function moveCopy (items, copy = false, overwrite = false, rename = false) {
 | 
			
		||||
  let promises = []
 | 
			
		||||
function moveCopy(items, copy = false, overwrite = false, rename = false) {
 | 
			
		||||
  let promises = [];
 | 
			
		||||
 | 
			
		||||
  for (let item of items) {
 | 
			
		||||
    const from = item.from
 | 
			
		||||
    const to = encodeURIComponent(removePrefix(item.to))
 | 
			
		||||
    const url = `${from}?action=${copy ? 'copy' : 'rename'}&destination=${to}&override=${overwrite}&rename=${rename}`
 | 
			
		||||
    promises.push(resourceAction(url, 'PATCH'))
 | 
			
		||||
    const from = item.from;
 | 
			
		||||
    const to = encodeURIComponent(removePrefix(item.to));
 | 
			
		||||
    const url = `${from}?action=${
 | 
			
		||||
      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) {
 | 
			
		||||
  return moveCopy(items, false, overwrite, rename)
 | 
			
		||||
export function move(items, overwrite = false, rename = false) {
 | 
			
		||||
  return moveCopy(items, false, overwrite, rename);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function copy (items, overwrite = false, rename = false) {
 | 
			
		||||
  return moveCopy(items, true, overwrite, rename)
 | 
			
		||||
export function copy(items, overwrite = false, rename = false) {
 | 
			
		||||
  return moveCopy(items, true, overwrite, rename);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function checksum (url, algo) {
 | 
			
		||||
  const data = await resourceAction(`${url}?checksum=${algo}`, 'GET')
 | 
			
		||||
  return (await data.json()).checksums[algo]
 | 
			
		||||
export async function checksum(url, algo) {
 | 
			
		||||
  const data = await resourceAction(`${url}?checksum=${algo}`, "GET");
 | 
			
		||||
  return (await data.json()).checksums[algo];
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,17 +1,9 @@
 | 
			
		|||
import * as files from './files'
 | 
			
		||||
import * as share from './share'
 | 
			
		||||
import * as users from './users'
 | 
			
		||||
import * as settings from './settings'
 | 
			
		||||
import * as pub from './pub'
 | 
			
		||||
import search from './search'
 | 
			
		||||
import commands from './commands'
 | 
			
		||||
import * as files from "./files";
 | 
			
		||||
import * as share from "./share";
 | 
			
		||||
import * as users from "./users";
 | 
			
		||||
import * as settings from "./settings";
 | 
			
		||||
import * as pub from "./pub";
 | 
			
		||||
import search from "./search";
 | 
			
		||||
import commands from "./commands";
 | 
			
		||||
 | 
			
		||||
export {
 | 
			
		||||
  files,
 | 
			
		||||
  share,
 | 
			
		||||
  users,
 | 
			
		||||
  settings,
 | 
			
		||||
  pub,
 | 
			
		||||
  commands,
 | 
			
		||||
  search
 | 
			
		||||
}
 | 
			
		||||
export { files, share, users, settings, pub, commands, search };
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,61 +1,61 @@
 | 
			
		|||
import { fetchURL, removePrefix } from './utils'
 | 
			
		||||
import { baseURL } from '@/utils/constants'
 | 
			
		||||
import { fetchURL, removePrefix } from "./utils";
 | 
			
		||||
import { baseURL } from "@/utils/constants";
 | 
			
		||||
 | 
			
		||||
export async function fetch (url, password = "") {
 | 
			
		||||
  url = removePrefix(url)
 | 
			
		||||
export async function fetch(url, password = "") {
 | 
			
		||||
  url = removePrefix(url);
 | 
			
		||||
 | 
			
		||||
  const res = await fetchURL(`/api/public/share${url}`, {
 | 
			
		||||
    headers: {'X-SHARE-PASSWORD': password},
 | 
			
		||||
  })
 | 
			
		||||
    headers: { "X-SHARE-PASSWORD": password },
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  if (res.status === 200) {
 | 
			
		||||
    let data = await res.json()
 | 
			
		||||
    data.url = `/share${url}`
 | 
			
		||||
    let data = await res.json();
 | 
			
		||||
    data.url = `/share${url}`;
 | 
			
		||||
 | 
			
		||||
    if (data.isDir) {
 | 
			
		||||
      if (!data.url.endsWith('/')) data.url += '/'
 | 
			
		||||
      if (!data.url.endsWith("/")) data.url += "/";
 | 
			
		||||
      data.items = data.items.map((item, index) => {
 | 
			
		||||
        item.index = index
 | 
			
		||||
        item.url = `${data.url}${encodeURIComponent(item.name)}`
 | 
			
		||||
        item.index = index;
 | 
			
		||||
        item.url = `${data.url}${encodeURIComponent(item.name)}`;
 | 
			
		||||
 | 
			
		||||
        if (item.isDir) {
 | 
			
		||||
          item.url += '/'
 | 
			
		||||
          item.url += "/";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return item
 | 
			
		||||
      })
 | 
			
		||||
        return item;
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return data
 | 
			
		||||
    return data;
 | 
			
		||||
  } else {
 | 
			
		||||
    throw new Error(res.status)
 | 
			
		||||
    throw new Error(res.status);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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) {
 | 
			
		||||
    url += encodeURIComponent(files[0]) + '?'
 | 
			
		||||
    url += encodeURIComponent(files[0]) + "?";
 | 
			
		||||
  } else {
 | 
			
		||||
    let arg = ''
 | 
			
		||||
    let arg = "";
 | 
			
		||||
 | 
			
		||||
    for (let file of files) {
 | 
			
		||||
      arg += encodeURIComponent(file)  + ','
 | 
			
		||||
      arg += encodeURIComponent(file) + ",";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    arg = arg.substring(0, arg.length - 1)
 | 
			
		||||
    arg = encodeURIComponent(arg)
 | 
			
		||||
    url += `/?files=${arg}&`
 | 
			
		||||
    arg = arg.substring(0, arg.length - 1);
 | 
			
		||||
    arg = encodeURIComponent(arg);
 | 
			
		||||
    url += `/?files=${arg}&`;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (format) {
 | 
			
		||||
    url += `algo=${format}&`
 | 
			
		||||
    url += `algo=${format}&`;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (token) {
 | 
			
		||||
    url += `token=${token}&`
 | 
			
		||||
    url += `token=${token}&`;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  window.open(url)
 | 
			
		||||
}
 | 
			
		||||
  window.open(url);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,31 +1,31 @@
 | 
			
		|||
import { fetchURL, removePrefix } from './utils'
 | 
			
		||||
import url from '../utils/url'
 | 
			
		||||
import { fetchURL, removePrefix } from "./utils";
 | 
			
		||||
import url from "../utils/url";
 | 
			
		||||
 | 
			
		||||
export default async function search (base, query) {
 | 
			
		||||
  base = removePrefix(base)
 | 
			
		||||
  query = encodeURIComponent(query)
 | 
			
		||||
export default async function search(base, query) {
 | 
			
		||||
  base = removePrefix(base);
 | 
			
		||||
  query = encodeURIComponent(query);
 | 
			
		||||
 | 
			
		||||
  if (!base.endsWith('/')) {
 | 
			
		||||
    base += '/'
 | 
			
		||||
  if (!base.endsWith("/")) {
 | 
			
		||||
    base += "/";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  let res = await fetchURL(`/api/search${base}?query=${query}`, {})
 | 
			
		||||
  let res = await fetchURL(`/api/search${base}?query=${query}`, {});
 | 
			
		||||
 | 
			
		||||
  if (res.status === 200) {
 | 
			
		||||
    let data = await res.json()
 | 
			
		||||
    let data = await res.json();
 | 
			
		||||
 | 
			
		||||
    data = data.map((item) => {
 | 
			
		||||
      item.url = `/files${base}` + url.encodePath(item.path)
 | 
			
		||||
      item.url = `/files${base}` + url.encodePath(item.path);
 | 
			
		||||
 | 
			
		||||
      if (item.dir) {
 | 
			
		||||
        item.url += '/'
 | 
			
		||||
        item.url += "/";
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return item
 | 
			
		||||
    })
 | 
			
		||||
      return item;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return data
 | 
			
		||||
    return data;
 | 
			
		||||
  } 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 () {
 | 
			
		||||
  return fetchJSON(`/api/settings`, {})
 | 
			
		||||
export function get() {
 | 
			
		||||
  return fetchJSON(`/api/settings`, {});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function update (settings) {
 | 
			
		||||
export async function update(settings) {
 | 
			
		||||
  const res = await fetchURL(`/api/settings`, {
 | 
			
		||||
    method: 'PUT',
 | 
			
		||||
    body: JSON.stringify(settings)
 | 
			
		||||
  })
 | 
			
		||||
    method: "PUT",
 | 
			
		||||
    body: JSON.stringify(settings),
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  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() {
 | 
			
		||||
  return fetchJSON('/api/shares')
 | 
			
		||||
  return fetchJSON("/api/shares");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function get(url) {
 | 
			
		||||
  url = removePrefix(url)
 | 
			
		||||
  return fetchJSON(`/api/share${url}`)
 | 
			
		||||
  url = removePrefix(url);
 | 
			
		||||
  return fetchJSON(`/api/share${url}`);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function remove(hash) {
 | 
			
		||||
  const res = await fetchURL(`/api/share/${hash}`, {
 | 
			
		||||
    method: 'DELETE'
 | 
			
		||||
  })
 | 
			
		||||
    method: "DELETE",
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  if (res.status !== 200) {
 | 
			
		||||
    throw new Error(res.status)
 | 
			
		||||
    throw new Error(res.status);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function create(url, password = '', expires = '', unit = 'hours') {
 | 
			
		||||
  url = removePrefix(url)
 | 
			
		||||
  url = `/api/share${url}`
 | 
			
		||||
  if (expires !== '') {
 | 
			
		||||
    url += `?expires=${expires}&unit=${unit}`
 | 
			
		||||
export async function create(url, password = "", expires = "", unit = "hours") {
 | 
			
		||||
  url = removePrefix(url);
 | 
			
		||||
  url = `/api/share${url}`;
 | 
			
		||||
  if (expires !== "") {
 | 
			
		||||
    url += `?expires=${expires}&unit=${unit}`;
 | 
			
		||||
  }
 | 
			
		||||
  let body = '{}';
 | 
			
		||||
  if (password != '' || expires !== '' || unit !== 'hours') {
 | 
			
		||||
    body = JSON.stringify({password: password, expires: expires, unit: unit})
 | 
			
		||||
  let body = "{}";
 | 
			
		||||
  if (password != "" || expires !== "" || unit !== "hours") {
 | 
			
		||||
    body = JSON.stringify({ password: password, expires: expires, unit: unit });
 | 
			
		||||
  }
 | 
			
		||||
  return fetchJSON(url, {
 | 
			
		||||
    method: 'POST',
 | 
			
		||||
    method: "POST",
 | 
			
		||||
    body: body,
 | 
			
		||||
  })
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,52 +1,51 @@
 | 
			
		|||
import { fetchURL, fetchJSON } from './utils'
 | 
			
		||||
import { fetchURL, fetchJSON } from "./utils";
 | 
			
		||||
 | 
			
		||||
export async function getAll () {
 | 
			
		||||
  return fetchJSON(`/api/users`, {})
 | 
			
		||||
export async function getAll() {
 | 
			
		||||
  return fetchJSON(`/api/users`, {});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function get (id) {
 | 
			
		||||
  return fetchJSON(`/api/users/${id}`, {})
 | 
			
		||||
export async function get(id) {
 | 
			
		||||
  return fetchJSON(`/api/users/${id}`, {});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function create (user) {
 | 
			
		||||
export async function create(user) {
 | 
			
		||||
  const res = await fetchURL(`/api/users`, {
 | 
			
		||||
    method: 'POST',
 | 
			
		||||
    method: "POST",
 | 
			
		||||
    body: JSON.stringify({
 | 
			
		||||
      what: 'user',
 | 
			
		||||
      what: "user",
 | 
			
		||||
      which: [],
 | 
			
		||||
      data: user
 | 
			
		||||
    })
 | 
			
		||||
  })
 | 
			
		||||
      data: user,
 | 
			
		||||
    }),
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  if (res.status === 201) {
 | 
			
		||||
    return res.headers.get('Location')
 | 
			
		||||
    return res.headers.get("Location");
 | 
			
		||||
  } 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}`, {
 | 
			
		||||
    method: 'PUT',
 | 
			
		||||
    method: "PUT",
 | 
			
		||||
    body: JSON.stringify({
 | 
			
		||||
      what: 'user',
 | 
			
		||||
      what: "user",
 | 
			
		||||
      which: which,
 | 
			
		||||
      data: user
 | 
			
		||||
    })
 | 
			
		||||
  })
 | 
			
		||||
      data: user,
 | 
			
		||||
    }),
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  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}`, {
 | 
			
		||||
    method: 'DELETE'
 | 
			
		||||
  })
 | 
			
		||||
    method: "DELETE",
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  if (res.status !== 200) {
 | 
			
		||||
    throw new Error(res.status)
 | 
			
		||||
    throw new Error(res.status);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,43 +1,42 @@
 | 
			
		|||
import store from '@/store'
 | 
			
		||||
import { renew } from '@/utils/auth'
 | 
			
		||||
import { baseURL } from '@/utils/constants'
 | 
			
		||||
import store from "@/store";
 | 
			
		||||
import { renew } from "@/utils/auth";
 | 
			
		||||
import { baseURL } from "@/utils/constants";
 | 
			
		||||
 | 
			
		||||
export async function fetchURL (url, opts) {
 | 
			
		||||
  opts = opts || {}
 | 
			
		||||
  opts.headers = opts.headers || {}
 | 
			
		||||
export async function fetchURL(url, opts) {
 | 
			
		||||
  opts = opts || {};
 | 
			
		||||
  opts.headers = opts.headers || {};
 | 
			
		||||
 | 
			
		||||
  let { headers, ...rest } = opts
 | 
			
		||||
  let { headers, ...rest } = opts;
 | 
			
		||||
 | 
			
		||||
  const res = await fetch(`${baseURL}${url}`, {
 | 
			
		||||
    headers: {
 | 
			
		||||
      'X-Auth': store.state.jwt,
 | 
			
		||||
      ...headers
 | 
			
		||||
      "X-Auth": store.state.jwt,
 | 
			
		||||
      ...headers,
 | 
			
		||||
    },
 | 
			
		||||
    ...rest
 | 
			
		||||
  })
 | 
			
		||||
    ...rest,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  if (res.headers.get('X-Renew-Token') === 'true') {
 | 
			
		||||
    await renew(store.state.jwt)
 | 
			
		||||
  if (res.headers.get("X-Renew-Token") === "true") {
 | 
			
		||||
    await renew(store.state.jwt);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return res
 | 
			
		||||
  return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function fetchJSON (url, opts) {
 | 
			
		||||
  const res = await fetchURL(url, opts)
 | 
			
		||||
export async function fetchJSON(url, opts) {
 | 
			
		||||
  const res = await fetchURL(url, opts);
 | 
			
		||||
 | 
			
		||||
  if (res.status === 200) {
 | 
			
		||||
    return res.json()
 | 
			
		||||
    return res.json();
 | 
			
		||||
  } else {
 | 
			
		||||
    throw new Error(res.status)
 | 
			
		||||
    throw new Error(res.status);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function removePrefix (url) {
 | 
			
		||||
  url = url.split('/').splice(2).join('/')
 | 
			
		||||
export function removePrefix(url) {
 | 
			
		||||
  url = url.split("/").splice(2).join("/");
 | 
			
		||||
 | 
			
		||||
  if (url === '') url = '/'
 | 
			
		||||
  if (url[0] !== '/') url = '/' + url
 | 
			
		||||
  return url
 | 
			
		||||
  if (url === "") url = "/";
 | 
			
		||||
  if (url[0] !== "/") url = "/" + url;
 | 
			
		||||
  return url;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,11 +1,18 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <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>
 | 
			
		||||
    </component>
 | 
			
		||||
 | 
			
		||||
    <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>
 | 
			
		||||
    </span>
 | 
			
		||||
  </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -13,55 +20,56 @@
 | 
			
		|||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'breadcrumbs',
 | 
			
		||||
  props: [
 | 
			
		||||
    'base',
 | 
			
		||||
    'noLink'
 | 
			
		||||
  ],
 | 
			
		||||
  name: "breadcrumbs",
 | 
			
		||||
  props: ["base", "noLink"],
 | 
			
		||||
  computed: {
 | 
			
		||||
    items () {
 | 
			
		||||
      const relativePath = this.$route.path.replace(this.base, '')
 | 
			
		||||
      let parts = relativePath.split('/')
 | 
			
		||||
    items() {
 | 
			
		||||
      const relativePath = this.$route.path.replace(this.base, "");
 | 
			
		||||
      let parts = relativePath.split("/");
 | 
			
		||||
 | 
			
		||||
      if (parts[0] === '') {
 | 
			
		||||
        parts.shift()
 | 
			
		||||
      if (parts[0] === "") {
 | 
			
		||||
        parts.shift();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (parts[parts.length - 1] === '') {
 | 
			
		||||
        parts.pop()
 | 
			
		||||
      if (parts[parts.length - 1] === "") {
 | 
			
		||||
        parts.pop();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      let breadcrumbs = []
 | 
			
		||||
      let breadcrumbs = [];
 | 
			
		||||
 | 
			
		||||
      for (let i = 0; i < parts.length; i++) {
 | 
			
		||||
        if (i === 0) {
 | 
			
		||||
          breadcrumbs.push({ name: decodeURIComponent(parts[i]), url: this.base + '/' + parts[i] + '/' })
 | 
			
		||||
        } else  {
 | 
			
		||||
          breadcrumbs.push({ name: decodeURIComponent(parts[i]), url: breadcrumbs[i - 1].url + parts[i] + '/' })
 | 
			
		||||
          breadcrumbs.push({
 | 
			
		||||
            name: decodeURIComponent(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) {
 | 
			
		||||
        while (breadcrumbs.length !== 4) {
 | 
			
		||||
          breadcrumbs.shift()
 | 
			
		||||
          breadcrumbs.shift();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        breadcrumbs[0].name = '...'
 | 
			
		||||
        breadcrumbs[0].name = "...";
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return breadcrumbs
 | 
			
		||||
      return breadcrumbs;
 | 
			
		||||
    },
 | 
			
		||||
    element () {
 | 
			
		||||
    element() {
 | 
			
		||||
      if (this.noLink !== undefined) {
 | 
			
		||||
        return 'span'
 | 
			
		||||
        return "span";
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return 'router-link'
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
      return "router-link";
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style>
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
<style></style>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div id="search" @click="open" v-bind:class="{ active , ongoing }">
 | 
			
		||||
  <div id="search" @click="open" v-bind:class="{ active, ongoing }">
 | 
			
		||||
    <div id="input">
 | 
			
		||||
      <button
 | 
			
		||||
        v-if="active"
 | 
			
		||||
| 
						 | 
				
			
			@ -20,7 +20,7 @@
 | 
			
		|||
        v-model.trim="value"
 | 
			
		||||
        :aria-label="$t('search.search')"
 | 
			
		||||
        :placeholder="$t('search.search')"
 | 
			
		||||
      >
 | 
			
		||||
      />
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div id="result" ref="result">
 | 
			
		||||
| 
						 | 
				
			
			@ -30,25 +30,25 @@
 | 
			
		|||
 | 
			
		||||
          <template v-if="value.length === 0">
 | 
			
		||||
            <div class="boxes">
 | 
			
		||||
              <h3>{{ $t('search.types') }}</h3>
 | 
			
		||||
              <h3>{{ $t("search.types") }}</h3>
 | 
			
		||||
              <div>
 | 
			
		||||
                <div
 | 
			
		||||
                  tabindex="0"
 | 
			
		||||
                  v-for="(v,k) in boxes"
 | 
			
		||||
                  v-for="(v, k) in boxes"
 | 
			
		||||
                  :key="k"
 | 
			
		||||
                  role="button"
 | 
			
		||||
                  @click="init('type:'+k)"
 | 
			
		||||
                  :aria-label="$t('search.'+v.label)"
 | 
			
		||||
                  @click="init('type:' + k)"
 | 
			
		||||
                  :aria-label="$t('search.' + v.label)"
 | 
			
		||||
                >
 | 
			
		||||
                  <i class="material-icons">{{v.icon}}</i>
 | 
			
		||||
                  <p>{{ $t('search.'+v.label) }}</p>
 | 
			
		||||
                  <i class="material-icons">{{ v.icon }}</i>
 | 
			
		||||
                  <p>{{ $t("search." + v.label) }}</p>
 | 
			
		||||
                </div>
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
          </template>
 | 
			
		||||
        </template>
 | 
			
		||||
        <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">
 | 
			
		||||
              <i v-if="s.dir" class="material-icons">folder</i>
 | 
			
		||||
              <i v-else class="material-icons">insert_drive_file</i>
 | 
			
		||||
| 
						 | 
				
			
			@ -65,20 +65,20 @@
 | 
			
		|||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { mapState, mapGetters, mapMutations } from "vuex"
 | 
			
		||||
import url from "@/utils/url"
 | 
			
		||||
import { search } from "@/api"
 | 
			
		||||
import { mapState, mapGetters, mapMutations } from "vuex";
 | 
			
		||||
import url from "@/utils/url";
 | 
			
		||||
import { search } from "@/api";
 | 
			
		||||
 | 
			
		||||
var boxes = {
 | 
			
		||||
  image: { label: "images", icon: "insert_photo" },
 | 
			
		||||
  audio: { label: "music", icon: "volume_up" },
 | 
			
		||||
  video: { label: "video", icon: "movie" },
 | 
			
		||||
  pdf: { label: "pdf", icon: "picture_as_pdf" }
 | 
			
		||||
}
 | 
			
		||||
  pdf: { label: "pdf", icon: "picture_as_pdf" },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "search",
 | 
			
		||||
  data: function() {
 | 
			
		||||
  data: function () {
 | 
			
		||||
    return {
 | 
			
		||||
      value: "",
 | 
			
		||||
      active: false,
 | 
			
		||||
| 
						 | 
				
			
			@ -86,111 +86,116 @@ export default {
 | 
			
		|||
      results: [],
 | 
			
		||||
      reload: false,
 | 
			
		||||
      resultsCount: 50,
 | 
			
		||||
      scrollable: null
 | 
			
		||||
    }
 | 
			
		||||
      scrollable: null,
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  watch: {
 | 
			
		||||
    show (val, old) {
 | 
			
		||||
      this.active = val === "search"
 | 
			
		||||
    show(val, old) {
 | 
			
		||||
      this.active = val === "search";
 | 
			
		||||
 | 
			
		||||
      if (old === "search" && !this.active) {
 | 
			
		||||
        if (this.reload) {
 | 
			
		||||
          this.setReload(true)
 | 
			
		||||
          this.setReload(true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        document.body.style.overflow = "auto"
 | 
			
		||||
        this.reset()
 | 
			
		||||
        this.value = ''
 | 
			
		||||
        this.active = false
 | 
			
		||||
        this.$refs.input.blur()
 | 
			
		||||
        document.body.style.overflow = "auto";
 | 
			
		||||
        this.reset();
 | 
			
		||||
        this.value = "";
 | 
			
		||||
        this.active = false;
 | 
			
		||||
        this.$refs.input.blur();
 | 
			
		||||
      } else if (this.active) {
 | 
			
		||||
        this.reload = false
 | 
			
		||||
        this.$refs.input.focus()
 | 
			
		||||
        document.body.style.overflow = "hidden"
 | 
			
		||||
        this.reload = false;
 | 
			
		||||
        this.$refs.input.focus();
 | 
			
		||||
        document.body.style.overflow = "hidden";
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    value () {
 | 
			
		||||
    value() {
 | 
			
		||||
      if (this.results.length) {
 | 
			
		||||
        this.reset()
 | 
			
		||||
        this.reset();
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapState(["user", "show"]),
 | 
			
		||||
    ...mapGetters(["isListing"]),
 | 
			
		||||
    boxes() {
 | 
			
		||||
      return boxes
 | 
			
		||||
      return boxes;
 | 
			
		||||
    },
 | 
			
		||||
    isEmpty() {
 | 
			
		||||
      return this.results.length === 0
 | 
			
		||||
      return this.results.length === 0;
 | 
			
		||||
    },
 | 
			
		||||
    text() {
 | 
			
		||||
      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() {
 | 
			
		||||
    this.$refs.result.addEventListener('scroll', event => {
 | 
			
		||||
      if (event.target.offsetHeight + event.target.scrollTop >= event.target.scrollHeight - 100) {
 | 
			
		||||
        this.resultsCount += 50
 | 
			
		||||
    this.$refs.result.addEventListener("scroll", (event) => {
 | 
			
		||||
      if (
 | 
			
		||||
        event.target.offsetHeight + event.target.scrollTop >=
 | 
			
		||||
        event.target.scrollHeight - 100
 | 
			
		||||
      ) {
 | 
			
		||||
        this.resultsCount += 50;
 | 
			
		||||
      }
 | 
			
		||||
    })
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    ...mapMutations(["showHover", "closeHovers", "setReload"]),
 | 
			
		||||
    open() {
 | 
			
		||||
      this.showHover("search")
 | 
			
		||||
      this.showHover("search");
 | 
			
		||||
    },
 | 
			
		||||
    close(event) {
 | 
			
		||||
      event.stopPropagation()
 | 
			
		||||
      event.preventDefault()
 | 
			
		||||
      this.closeHovers()
 | 
			
		||||
      event.stopPropagation();
 | 
			
		||||
      event.preventDefault();
 | 
			
		||||
      this.closeHovers();
 | 
			
		||||
    },
 | 
			
		||||
    keyup(event) {
 | 
			
		||||
      if (event.keyCode === 27) {
 | 
			
		||||
        this.close(event)
 | 
			
		||||
        return
 | 
			
		||||
        this.close(event);
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this.results.length = 0
 | 
			
		||||
      this.results.length = 0;
 | 
			
		||||
    },
 | 
			
		||||
    init (string) {
 | 
			
		||||
      this.value = `${string} `
 | 
			
		||||
      this.$refs.input.focus()
 | 
			
		||||
    init(string) {
 | 
			
		||||
      this.value = `${string} `;
 | 
			
		||||
      this.$refs.input.focus();
 | 
			
		||||
    },
 | 
			
		||||
    reset () {
 | 
			
		||||
      this.ongoing = false
 | 
			
		||||
      this.resultsCount = 50
 | 
			
		||||
      this.results = []
 | 
			
		||||
    reset() {
 | 
			
		||||
      this.ongoing = false;
 | 
			
		||||
      this.resultsCount = 50;
 | 
			
		||||
      this.results = [];
 | 
			
		||||
    },
 | 
			
		||||
    async submit(event) {
 | 
			
		||||
      event.preventDefault()
 | 
			
		||||
      event.preventDefault();
 | 
			
		||||
 | 
			
		||||
      if (this.value === '') {
 | 
			
		||||
        return
 | 
			
		||||
      if (this.value === "") {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      let path = this.$route.path
 | 
			
		||||
      let path = this.$route.path;
 | 
			
		||||
      if (!this.isListing) {
 | 
			
		||||
        path = url.removeLastDir(path) + "/"
 | 
			
		||||
        path = url.removeLastDir(path) + "/";
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this.ongoing = true
 | 
			
		||||
      this.ongoing = true;
 | 
			
		||||
 | 
			
		||||
      try {
 | 
			
		||||
        this.results = await search(path, this.value)
 | 
			
		||||
        this.results = await search(path, this.value);
 | 
			
		||||
      } catch (error) {
 | 
			
		||||
        this.$showError(error)
 | 
			
		||||
        this.$showError(error);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this.ongoing = false
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
      this.ongoing = false;
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,12 +1,21 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div @click="focus" 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>
 | 
			
		||||
  <div
 | 
			
		||||
    @click="focus"
 | 
			
		||||
    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>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="shell__result" :class="{ 'shell__result--hidden': !canInput }" >
 | 
			
		||||
      <div class="shell__prompt"><i class="material-icons">chevron_right</i></div>
 | 
			
		||||
    <div class="shell__result" :class="{ 'shell__result--hidden': !canInput }">
 | 
			
		||||
      <div class="shell__prompt">
 | 
			
		||||
        <i class="material-icons">chevron_right</i>
 | 
			
		||||
      </div>
 | 
			
		||||
      <pre
 | 
			
		||||
        tabindex="0"
 | 
			
		||||
        ref="input"
 | 
			
		||||
| 
						 | 
				
			
			@ -14,102 +23,103 @@
 | 
			
		|||
        contenteditable="true"
 | 
			
		||||
        @keydown.prevent.38="historyUp"
 | 
			
		||||
        @keydown.prevent.40="historyDown"
 | 
			
		||||
        @keypress.prevent.enter="submit" />
 | 
			
		||||
        @keypress.prevent.enter="submit"
 | 
			
		||||
      />
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { mapMutations, mapState, mapGetters } from 'vuex'
 | 
			
		||||
import { commands } from '@/api'
 | 
			
		||||
import { mapMutations, mapState, mapGetters } from "vuex";
 | 
			
		||||
import { commands } from "@/api";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'shell',
 | 
			
		||||
  name: "shell",
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapState([ 'user', 'showShell' ]),
 | 
			
		||||
    ...mapGetters([ 'isFiles', 'isLogged' ]),
 | 
			
		||||
    ...mapState(["user", "showShell"]),
 | 
			
		||||
    ...mapGetters(["isFiles", "isLogged"]),
 | 
			
		||||
    path: function () {
 | 
			
		||||
      if (this.isFiles) {
 | 
			
		||||
        return this.$route.path
 | 
			
		||||
        return this.$route.path;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return ''
 | 
			
		||||
    }
 | 
			
		||||
      return "";
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  data: () => ({
 | 
			
		||||
    content: [],
 | 
			
		||||
    history: [],
 | 
			
		||||
    historyPos: 0,
 | 
			
		||||
    canInput: true
 | 
			
		||||
    canInput: true,
 | 
			
		||||
  }),
 | 
			
		||||
  methods: {
 | 
			
		||||
    ...mapMutations([ 'toggleShell' ]),
 | 
			
		||||
    ...mapMutations(["toggleShell"]),
 | 
			
		||||
    scroll: function () {
 | 
			
		||||
      this.$refs.scrollable.scrollTop = this.$refs.scrollable.scrollHeight
 | 
			
		||||
      this.$refs.scrollable.scrollTop = this.$refs.scrollable.scrollHeight;
 | 
			
		||||
    },
 | 
			
		||||
    focus: function () {
 | 
			
		||||
      this.$refs.input.focus()
 | 
			
		||||
      this.$refs.input.focus();
 | 
			
		||||
    },
 | 
			
		||||
    historyUp () {
 | 
			
		||||
    historyUp() {
 | 
			
		||||
      if (this.historyPos > 0) {
 | 
			
		||||
        this.$refs.input.innerText = this.history[--this.historyPos]
 | 
			
		||||
        this.focus()
 | 
			
		||||
        this.$refs.input.innerText = this.history[--this.historyPos];
 | 
			
		||||
        this.focus();
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    historyDown () {
 | 
			
		||||
    historyDown() {
 | 
			
		||||
      if (this.historyPos >= 0 && this.historyPos < this.history.length - 1) {
 | 
			
		||||
        this.$refs.input.innerText = this.history[++this.historyPos]
 | 
			
		||||
        this.focus()
 | 
			
		||||
        this.$refs.input.innerText = this.history[++this.historyPos];
 | 
			
		||||
        this.focus();
 | 
			
		||||
      } else {
 | 
			
		||||
        this.historyPos = this.history.length
 | 
			
		||||
        this.$refs.input.innerText = ''
 | 
			
		||||
        this.historyPos = this.history.length;
 | 
			
		||||
        this.$refs.input.innerText = "";
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    submit: function (event) {
 | 
			
		||||
      const cmd = event.target.innerText.trim()
 | 
			
		||||
      const cmd = event.target.innerText.trim();
 | 
			
		||||
 | 
			
		||||
      if (cmd === '') {
 | 
			
		||||
        return
 | 
			
		||||
      if (cmd === "") {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (cmd === 'clear') {
 | 
			
		||||
        this.content = []
 | 
			
		||||
        event.target.innerHTML = ''
 | 
			
		||||
        return
 | 
			
		||||
      if (cmd === "clear") {
 | 
			
		||||
        this.content = [];
 | 
			
		||||
        event.target.innerHTML = "";
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (cmd === 'exit') {
 | 
			
		||||
        event.target.innerHTML = ''
 | 
			
		||||
        this.toggleShell()
 | 
			
		||||
        return
 | 
			
		||||
      if (cmd === "exit") {
 | 
			
		||||
        event.target.innerHTML = "";
 | 
			
		||||
        this.toggleShell();
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this.canInput = false
 | 
			
		||||
      event.target.innerHTML = ''
 | 
			
		||||
      this.canInput = false;
 | 
			
		||||
      event.target.innerHTML = "";
 | 
			
		||||
 | 
			
		||||
      let results = {
 | 
			
		||||
        text: `${cmd}\n\n`
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
      this.history.push(cmd)
 | 
			
		||||
      this.historyPos = this.history.length
 | 
			
		||||
      this.content.push(results)
 | 
			
		||||
        text: `${cmd}\n\n`,
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      this.history.push(cmd);
 | 
			
		||||
      this.historyPos = this.history.length;
 | 
			
		||||
      this.content.push(results);
 | 
			
		||||
 | 
			
		||||
      commands(
 | 
			
		||||
        this.path,
 | 
			
		||||
        cmd,
 | 
			
		||||
        event => {
 | 
			
		||||
          results.text += `${event.data}\n`
 | 
			
		||||
          this.scroll()
 | 
			
		||||
        (event) => {
 | 
			
		||||
          results.text += `${event.data}\n`;
 | 
			
		||||
          this.scroll();
 | 
			
		||||
        },
 | 
			
		||||
        () => {
 | 
			
		||||
          results.text = results.text.trimEnd()
 | 
			
		||||
          this.canInput = true
 | 
			
		||||
          this.$refs.input.focus()
 | 
			
		||||
          this.scroll()
 | 
			
		||||
          results.text = results.text.trimEnd();
 | 
			
		||||
          this.canInput = true;
 | 
			
		||||
          this.$refs.input.focus();
 | 
			
		||||
          this.scroll();
 | 
			
		||||
        }
 | 
			
		||||
      )
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
      );
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,82 +1,134 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <nav :class="{active}">
 | 
			
		||||
  <nav :class="{ active }">
 | 
			
		||||
    <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>
 | 
			
		||||
        <span>{{ $t('sidebar.myFiles') }}</span>
 | 
			
		||||
        <span>{{ $t("sidebar.myFiles") }}</span>
 | 
			
		||||
      </router-link>
 | 
			
		||||
 | 
			
		||||
      <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>
 | 
			
		||||
          <span>{{ $t('sidebar.newFolder') }}</span>
 | 
			
		||||
          <span>{{ $t("sidebar.newFolder") }}</span>
 | 
			
		||||
        </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>
 | 
			
		||||
          <span>{{ $t('sidebar.newFile') }}</span>
 | 
			
		||||
          <span>{{ $t("sidebar.newFile") }}</span>
 | 
			
		||||
        </button>
 | 
			
		||||
      </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>
 | 
			
		||||
          <span>{{ $t('sidebar.settings') }}</span>
 | 
			
		||||
          <span>{{ $t("sidebar.settings") }}</span>
 | 
			
		||||
        </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>
 | 
			
		||||
          <span>{{ $t('sidebar.logout') }}</span>
 | 
			
		||||
          <span>{{ $t("sidebar.logout") }}</span>
 | 
			
		||||
        </button>
 | 
			
		||||
      </div>
 | 
			
		||||
    </template>
 | 
			
		||||
    <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>
 | 
			
		||||
        <span>{{ $t('sidebar.login') }}</span>
 | 
			
		||||
        <span>{{ $t("sidebar.login") }}</span>
 | 
			
		||||
      </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>
 | 
			
		||||
        <span>{{ $t('sidebar.signup') }}</span>
 | 
			
		||||
        <span>{{ $t("sidebar.signup") }}</span>
 | 
			
		||||
      </router-link>
 | 
			
		||||
    </template>
 | 
			
		||||
 | 
			
		||||
    <p class="credits">
 | 
			
		||||
      <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>
 | 
			
		||||
      <span><a @click="help">{{ $t('sidebar.help') }}</a></span>
 | 
			
		||||
      <span
 | 
			
		||||
        ><a @click="help">{{ $t("sidebar.help") }}</a></span
 | 
			
		||||
      >
 | 
			
		||||
    </p>
 | 
			
		||||
  </nav>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { mapState, mapGetters } from 'vuex'
 | 
			
		||||
import * as auth from '@/utils/auth'
 | 
			
		||||
import { version, signup, disableExternal, noAuth, authMethod } from '@/utils/constants'
 | 
			
		||||
import { mapState, mapGetters } from "vuex";
 | 
			
		||||
import * as auth from "@/utils/auth";
 | 
			
		||||
import {
 | 
			
		||||
  version,
 | 
			
		||||
  signup,
 | 
			
		||||
  disableExternal,
 | 
			
		||||
  noAuth,
 | 
			
		||||
  authMethod,
 | 
			
		||||
} from "@/utils/constants";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'sidebar',
 | 
			
		||||
  name: "sidebar",
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapState([ 'user' ]),
 | 
			
		||||
    ...mapGetters([ 'isLogged' ]),
 | 
			
		||||
    active () {
 | 
			
		||||
      return this.$store.state.show === 'sidebar'
 | 
			
		||||
    ...mapState(["user"]),
 | 
			
		||||
    ...mapGetters(["isLogged"]),
 | 
			
		||||
    active() {
 | 
			
		||||
      return this.$store.state.show === "sidebar";
 | 
			
		||||
    },
 | 
			
		||||
    signup: () => signup,
 | 
			
		||||
    version: () => version,
 | 
			
		||||
    disableExternal: () => disableExternal,
 | 
			
		||||
    noAuth: () => noAuth,
 | 
			
		||||
    authMethod: () => authMethod
 | 
			
		||||
    authMethod: () => authMethod,
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    help () {
 | 
			
		||||
      this.$store.commit('showHover', 'help')
 | 
			
		||||
    help() {
 | 
			
		||||
      this.$store.commit("showHover", "help");
 | 
			
		||||
    },
 | 
			
		||||
    logout: auth.logout
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
    logout: auth.logout,
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,40 +10,45 @@
 | 
			
		|||
    @mouseup="mouseUp"
 | 
			
		||||
    @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>
 | 
			
		||||
</template>
 | 
			
		||||
<script>
 | 
			
		||||
import throttle from 'lodash.throttle'
 | 
			
		||||
import UTIF from 'utif'
 | 
			
		||||
import throttle from "lodash.throttle";
 | 
			
		||||
import UTIF from "utif";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  props: {
 | 
			
		||||
    src: String,
 | 
			
		||||
    moveDisabledTime: {
 | 
			
		||||
      type: Number,
 | 
			
		||||
      default: () => 200
 | 
			
		||||
      default: () => 200,
 | 
			
		||||
    },
 | 
			
		||||
    maxScale: {
 | 
			
		||||
      type: Number,
 | 
			
		||||
      default: () => 4
 | 
			
		||||
      default: () => 4,
 | 
			
		||||
    },
 | 
			
		||||
    minScale: {
 | 
			
		||||
      type: Number,
 | 
			
		||||
      default: () => 0.25
 | 
			
		||||
      default: () => 0.25,
 | 
			
		||||
    },
 | 
			
		||||
    classList: {
 | 
			
		||||
      type: Array,
 | 
			
		||||
      default: () => []
 | 
			
		||||
      default: () => [],
 | 
			
		||||
    },
 | 
			
		||||
    zoomStep: {
 | 
			
		||||
      type: Number,
 | 
			
		||||
      default: () => 0.25
 | 
			
		||||
      default: () => 0.25,
 | 
			
		||||
    },
 | 
			
		||||
    autofill: {
 | 
			
		||||
      type: Boolean,
 | 
			
		||||
      default: () => false
 | 
			
		||||
    }
 | 
			
		||||
      default: () => false,
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
| 
						 | 
				
			
			@ -57,204 +62,208 @@ export default {
 | 
			
		|||
      imageLoaded: false,
 | 
			
		||||
      position: {
 | 
			
		||||
        center: { x: 0, y: 0 },
 | 
			
		||||
        relative: { x: 0, y: 0 }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
        relative: { x: 0, y: 0 },
 | 
			
		||||
      },
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  mounted() {
 | 
			
		||||
    if (!this.decodeUTIF()) {
 | 
			
		||||
      this.$refs.imgex.src = this.src
 | 
			
		||||
      this.$refs.imgex.src = this.src;
 | 
			
		||||
    }
 | 
			
		||||
    let container = this.$refs.container
 | 
			
		||||
    this.classList.forEach(className => container.classList.add(className))
 | 
			
		||||
    let container = this.$refs.container;
 | 
			
		||||
    this.classList.forEach((className) => container.classList.add(className));
 | 
			
		||||
    // set width and height if they are zero
 | 
			
		||||
    if (getComputedStyle(container).width === "0px") {
 | 
			
		||||
      container.style.width = "100%"
 | 
			
		||||
      container.style.width = "100%";
 | 
			
		||||
    }
 | 
			
		||||
    if (getComputedStyle(container).height === "0px") {
 | 
			
		||||
      container.style.height = "100%"
 | 
			
		||||
      container.style.height = "100%";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    window.addEventListener('resize', this.onResize)
 | 
			
		||||
    window.addEventListener("resize", this.onResize);
 | 
			
		||||
  },
 | 
			
		||||
  beforeDestroy () {
 | 
			
		||||
    window.removeEventListener('resize', this.onResize)
 | 
			
		||||
    document.removeEventListener('mouseup', this.onMouseUp)
 | 
			
		||||
  beforeDestroy() {
 | 
			
		||||
    window.removeEventListener("resize", this.onResize);
 | 
			
		||||
    document.removeEventListener("mouseup", this.onMouseUp);
 | 
			
		||||
  },
 | 
			
		||||
  watch: {
 | 
			
		||||
    src: function () {
 | 
			
		||||
      this.scale = 1
 | 
			
		||||
      this.setZoom()
 | 
			
		||||
      this.setCenter()
 | 
			
		||||
    }
 | 
			
		||||
      this.scale = 1;
 | 
			
		||||
      this.setZoom();
 | 
			
		||||
      this.setCenter();
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    // Modified from UTIF.replaceIMG
 | 
			
		||||
    decodeUTIF() {
 | 
			
		||||
      const sufs = ["tif", "tiff", "dng", "cr2", "nef"]
 | 
			
		||||
      let suff = document.location.pathname.split(".").pop().toLowerCase()
 | 
			
		||||
      if (sufs.indexOf(suff) == -1) return false
 | 
			
		||||
      let xhr = new XMLHttpRequest()
 | 
			
		||||
      UTIF._xhrs.push(xhr)
 | 
			
		||||
      UTIF._imgs.push(this.$refs.imgex)
 | 
			
		||||
      xhr.open("GET", this.src)
 | 
			
		||||
      xhr.responseType = "arraybuffer"
 | 
			
		||||
      xhr.onload = UTIF._imgLoaded
 | 
			
		||||
      xhr.send()
 | 
			
		||||
      return true
 | 
			
		||||
      const sufs = ["tif", "tiff", "dng", "cr2", "nef"];
 | 
			
		||||
      let suff = document.location.pathname.split(".").pop().toLowerCase();
 | 
			
		||||
      if (sufs.indexOf(suff) == -1) return false;
 | 
			
		||||
      let xhr = new XMLHttpRequest();
 | 
			
		||||
      UTIF._xhrs.push(xhr);
 | 
			
		||||
      UTIF._imgs.push(this.$refs.imgex);
 | 
			
		||||
      xhr.open("GET", this.src);
 | 
			
		||||
      xhr.responseType = "arraybuffer";
 | 
			
		||||
      xhr.onload = UTIF._imgLoaded;
 | 
			
		||||
      xhr.send();
 | 
			
		||||
      return true;
 | 
			
		||||
    },
 | 
			
		||||
    onLoad() {
 | 
			
		||||
      let img = this.$refs.imgex
 | 
			
		||||
      let img = this.$refs.imgex;
 | 
			
		||||
 | 
			
		||||
      this.imageLoaded = true
 | 
			
		||||
      this.imageLoaded = true;
 | 
			
		||||
 | 
			
		||||
      if (img === undefined) {
 | 
			
		||||
        return
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      img.classList.remove('image-ex-img-center')
 | 
			
		||||
      this.setCenter()
 | 
			
		||||
      img.classList.add('image-ex-img-ready')
 | 
			
		||||
      img.classList.remove("image-ex-img-center");
 | 
			
		||||
      this.setCenter();
 | 
			
		||||
      img.classList.add("image-ex-img-ready");
 | 
			
		||||
 | 
			
		||||
      document.addEventListener('mouseup', this.onMouseUp)
 | 
			
		||||
      document.addEventListener("mouseup", this.onMouseUp);
 | 
			
		||||
    },
 | 
			
		||||
    onMouseUp() {
 | 
			
		||||
      this.inDrag = false
 | 
			
		||||
      this.inDrag = false;
 | 
			
		||||
    },
 | 
			
		||||
    onResize: throttle(function() {
 | 
			
		||||
    onResize: throttle(function () {
 | 
			
		||||
      if (this.imageLoaded) {
 | 
			
		||||
        this.setCenter()
 | 
			
		||||
        this.doMove(this.position.relative.x, this.position.relative.y)
 | 
			
		||||
        this.setCenter();
 | 
			
		||||
        this.doMove(this.position.relative.x, this.position.relative.y);
 | 
			
		||||
      }
 | 
			
		||||
    }, 100),
 | 
			
		||||
    setCenter() {
 | 
			
		||||
      let container = this.$refs.container
 | 
			
		||||
      let img = this.$refs.imgex
 | 
			
		||||
      let container = this.$refs.container;
 | 
			
		||||
      let img = this.$refs.imgex;
 | 
			
		||||
 | 
			
		||||
      this.position.center.x = Math.floor((container.clientWidth - img.clientWidth) / 2)
 | 
			
		||||
      this.position.center.y = Math.floor((container.clientHeight - img.clientHeight) / 2)
 | 
			
		||||
      this.position.center.x = Math.floor(
 | 
			
		||||
        (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.top = this.position.center.y + 'px'
 | 
			
		||||
      img.style.left = this.position.center.x + "px";
 | 
			
		||||
      img.style.top = this.position.center.y + "px";
 | 
			
		||||
    },
 | 
			
		||||
    mousedownStart(event) {
 | 
			
		||||
      this.lastX = null
 | 
			
		||||
      this.lastY = null
 | 
			
		||||
      this.inDrag = true
 | 
			
		||||
      event.preventDefault()
 | 
			
		||||
      this.lastX = null;
 | 
			
		||||
      this.lastY = null;
 | 
			
		||||
      this.inDrag = true;
 | 
			
		||||
      event.preventDefault();
 | 
			
		||||
    },
 | 
			
		||||
    mouseMove(event) {
 | 
			
		||||
      if (!this.inDrag) return
 | 
			
		||||
      this.doMove(event.movementX, event.movementY)
 | 
			
		||||
      event.preventDefault()
 | 
			
		||||
      if (!this.inDrag) return;
 | 
			
		||||
      this.doMove(event.movementX, event.movementY);
 | 
			
		||||
      event.preventDefault();
 | 
			
		||||
    },
 | 
			
		||||
    mouseUp(event) {
 | 
			
		||||
      this.inDrag = false
 | 
			
		||||
      event.preventDefault()
 | 
			
		||||
      this.inDrag = false;
 | 
			
		||||
      event.preventDefault();
 | 
			
		||||
    },
 | 
			
		||||
    touchStart(event) {
 | 
			
		||||
      this.lastX = null
 | 
			
		||||
      this.lastY = null
 | 
			
		||||
      this.lastTouchDistance = null
 | 
			
		||||
      this.lastX = null;
 | 
			
		||||
      this.lastY = null;
 | 
			
		||||
      this.lastTouchDistance = null;
 | 
			
		||||
      if (event.targetTouches.length < 2) {
 | 
			
		||||
        setTimeout(() => {
 | 
			
		||||
          this.touches = 0
 | 
			
		||||
        }, 300)
 | 
			
		||||
        this.touches++
 | 
			
		||||
          this.touches = 0;
 | 
			
		||||
        }, 300);
 | 
			
		||||
        this.touches++;
 | 
			
		||||
        if (this.touches > 1) {
 | 
			
		||||
          this.zoomAuto(event)
 | 
			
		||||
          this.zoomAuto(event);
 | 
			
		||||
        }
 | 
			
		||||
      }    
 | 
			
		||||
      event.preventDefault()
 | 
			
		||||
      }
 | 
			
		||||
      event.preventDefault();
 | 
			
		||||
    },
 | 
			
		||||
    zoomAuto(event) {
 | 
			
		||||
      switch (this.scale) {
 | 
			
		||||
        case 1:
 | 
			
		||||
          this.scale = 2
 | 
			
		||||
          break
 | 
			
		||||
          this.scale = 2;
 | 
			
		||||
          break;
 | 
			
		||||
        case 2:
 | 
			
		||||
          this.scale = 4
 | 
			
		||||
          break
 | 
			
		||||
          this.scale = 4;
 | 
			
		||||
          break;
 | 
			
		||||
        default:
 | 
			
		||||
        case 4:
 | 
			
		||||
          this.scale = 1
 | 
			
		||||
          this.setCenter()
 | 
			
		||||
          break
 | 
			
		||||
          this.scale = 1;
 | 
			
		||||
          this.setCenter();
 | 
			
		||||
          break;
 | 
			
		||||
      }
 | 
			
		||||
      this.setZoom()
 | 
			
		||||
      event.preventDefault()
 | 
			
		||||
      this.setZoom();
 | 
			
		||||
      event.preventDefault();
 | 
			
		||||
    },
 | 
			
		||||
    touchMove(event) {
 | 
			
		||||
      event.preventDefault()
 | 
			
		||||
      event.preventDefault();
 | 
			
		||||
      if (this.lastX === null) {
 | 
			
		||||
        this.lastX = event.targetTouches[0].pageX
 | 
			
		||||
        this.lastY = event.targetTouches[0].pageY
 | 
			
		||||
        return
 | 
			
		||||
        this.lastX = event.targetTouches[0].pageX;
 | 
			
		||||
        this.lastY = event.targetTouches[0].pageY;
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      let step = this.$refs.imgex.width / 5
 | 
			
		||||
      let step = this.$refs.imgex.width / 5;
 | 
			
		||||
      if (event.targetTouches.length === 2) {
 | 
			
		||||
        this.moveDisabled = true
 | 
			
		||||
        clearTimeout(this.disabledTimer)
 | 
			
		||||
        this.moveDisabled = true;
 | 
			
		||||
        clearTimeout(this.disabledTimer);
 | 
			
		||||
        this.disabledTimer = setTimeout(
 | 
			
		||||
          () => (this.moveDisabled = false),
 | 
			
		||||
          this.moveDisabledTime
 | 
			
		||||
        )
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        let p1 = event.targetTouches[0]
 | 
			
		||||
        let p2 = event.targetTouches[1]
 | 
			
		||||
        let p1 = event.targetTouches[0];
 | 
			
		||||
        let p2 = event.targetTouches[1];
 | 
			
		||||
        let touchDistance = Math.sqrt(
 | 
			
		||||
          Math.pow(p2.pageX - p1.pageX, 2) + Math.pow(p2.pageY - p1.pageY, 2)
 | 
			
		||||
        )
 | 
			
		||||
        );
 | 
			
		||||
        if (!this.lastTouchDistance) {
 | 
			
		||||
          this.lastTouchDistance = touchDistance
 | 
			
		||||
          return
 | 
			
		||||
          this.lastTouchDistance = touchDistance;
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
        this.scale += (touchDistance - this.lastTouchDistance) / step
 | 
			
		||||
        this.lastTouchDistance = touchDistance
 | 
			
		||||
        this.setZoom()
 | 
			
		||||
        this.scale += (touchDistance - this.lastTouchDistance) / step;
 | 
			
		||||
        this.lastTouchDistance = touchDistance;
 | 
			
		||||
        this.setZoom();
 | 
			
		||||
      } else if (event.targetTouches.length === 1) {
 | 
			
		||||
        if (this.moveDisabled) return
 | 
			
		||||
        let x = event.targetTouches[0].pageX - this.lastX
 | 
			
		||||
        let y = event.targetTouches[0].pageY - this.lastY
 | 
			
		||||
        if (Math.abs(x) >= step && Math.abs(y) >= step) return
 | 
			
		||||
        this.lastX = event.targetTouches[0].pageX
 | 
			
		||||
        this.lastY = event.targetTouches[0].pageY
 | 
			
		||||
        this.doMove(x, y)
 | 
			
		||||
        if (this.moveDisabled) return;
 | 
			
		||||
        let x = event.targetTouches[0].pageX - this.lastX;
 | 
			
		||||
        let y = event.targetTouches[0].pageY - this.lastY;
 | 
			
		||||
        if (Math.abs(x) >= step && Math.abs(y) >= step) return;
 | 
			
		||||
        this.lastX = event.targetTouches[0].pageX;
 | 
			
		||||
        this.lastY = event.targetTouches[0].pageY;
 | 
			
		||||
        this.doMove(x, y);
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    doMove(x, y) {
 | 
			
		||||
      let style = this.$refs.imgex.style
 | 
			
		||||
      let posX = this.pxStringToNumber(style.left) + x
 | 
			
		||||
      let posY = this.pxStringToNumber(style.top) + y
 | 
			
		||||
      let style = this.$refs.imgex.style;
 | 
			
		||||
      let posX = this.pxStringToNumber(style.left) + x;
 | 
			
		||||
      let posY = this.pxStringToNumber(style.top) + y;
 | 
			
		||||
 | 
			
		||||
      style.left = posX + 'px'
 | 
			
		||||
      style.top = posY + 'px'
 | 
			
		||||
      style.left = posX + "px";
 | 
			
		||||
      style.top = posY + "px";
 | 
			
		||||
 | 
			
		||||
      this.position.relative.x =  Math.abs(this.position.center.x - posX)
 | 
			
		||||
      this.position.relative.y =  Math.abs(this.position.center.y - posY)
 | 
			
		||||
      this.position.relative.x = Math.abs(this.position.center.x - posX);
 | 
			
		||||
      this.position.relative.y = Math.abs(this.position.center.y - posY);
 | 
			
		||||
 | 
			
		||||
      if (posX < this.position.center.x) {
 | 
			
		||||
        this.position.relative.x = this.position.relative.x * -1
 | 
			
		||||
        this.position.relative.x = this.position.relative.x * -1;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      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) {
 | 
			
		||||
      this.scale += (event.wheelDeltaY / 100) * this.zoomStep
 | 
			
		||||
      this.setZoom()
 | 
			
		||||
      this.scale += (event.wheelDeltaY / 100) * this.zoomStep;
 | 
			
		||||
      this.setZoom();
 | 
			
		||||
    },
 | 
			
		||||
    setZoom() {
 | 
			
		||||
      this.scale = this.scale < this.minScale ? this.minScale : this.scale
 | 
			
		||||
      this.scale = this.scale > this.maxScale ? this.maxScale : this.scale
 | 
			
		||||
      this.$refs.imgex.style.transform = `scale(${this.scale})`
 | 
			
		||||
      this.scale = this.scale < this.minScale ? this.minScale : this.scale;
 | 
			
		||||
      this.scale = this.scale > this.maxScale ? this.maxScale : this.scale;
 | 
			
		||||
      this.$refs.imgex.style.transform = `scale(${this.scale})`;
 | 
			
		||||
    },
 | 
			
		||||
    pxStringToNumber(style) {
 | 
			
		||||
      return +style.replace("px", "")
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
      return +style.replace("px", "");
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
<style>
 | 
			
		||||
.image-ex-container {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,19 +1,24 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div class="item"
 | 
			
		||||
  role="button"
 | 
			
		||||
  tabindex="0"
 | 
			
		||||
  :draggable="isDraggable"
 | 
			
		||||
  @dragstart="dragStart"
 | 
			
		||||
  @dragover="dragOver"
 | 
			
		||||
  @drop="drop"
 | 
			
		||||
  @click="itemClick"
 | 
			
		||||
  @dblclick="dblclick"
 | 
			
		||||
  @touchstart="touchstart"
 | 
			
		||||
  :data-dir="isDir"
 | 
			
		||||
  :aria-label="name"
 | 
			
		||||
  :aria-selected="isSelected">
 | 
			
		||||
  <div
 | 
			
		||||
    class="item"
 | 
			
		||||
    role="button"
 | 
			
		||||
    tabindex="0"
 | 
			
		||||
    :draggable="isDraggable"
 | 
			
		||||
    @dragstart="dragStart"
 | 
			
		||||
    @dragover="dragOver"
 | 
			
		||||
    @drop="drop"
 | 
			
		||||
    @click="itemClick"
 | 
			
		||||
    @dblclick="dblclick"
 | 
			
		||||
    @touchstart="touchstart"
 | 
			
		||||
    :data-dir="isDir"
 | 
			
		||||
    :aria-label="name"
 | 
			
		||||
    :aria-selected="isSelected"
 | 
			
		||||
  >
 | 
			
		||||
    <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>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -31,203 +36,221 @@
 | 
			
		|||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { baseURL, enableThumbs } from '@/utils/constants'
 | 
			
		||||
import { mapMutations, mapGetters, mapState } from 'vuex'
 | 
			
		||||
import filesize from 'filesize'
 | 
			
		||||
import moment from 'moment'
 | 
			
		||||
import { files as api } from '@/api'
 | 
			
		||||
import * as upload  from '@/utils/upload'
 | 
			
		||||
import { baseURL, enableThumbs } from "@/utils/constants";
 | 
			
		||||
import { mapMutations, mapGetters, mapState } from "vuex";
 | 
			
		||||
import filesize from "filesize";
 | 
			
		||||
import moment from "moment";
 | 
			
		||||
import { files as api } from "@/api";
 | 
			
		||||
import * as upload from "@/utils/upload";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'item',
 | 
			
		||||
  name: "item",
 | 
			
		||||
  data: function () {
 | 
			
		||||
    return {
 | 
			
		||||
      touches: 0
 | 
			
		||||
    }
 | 
			
		||||
      touches: 0,
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  props: ['name', 'isDir', 'url', 'type', 'size', 'modified', 'index', 'readOnly'],
 | 
			
		||||
  props: [
 | 
			
		||||
    "name",
 | 
			
		||||
    "isDir",
 | 
			
		||||
    "url",
 | 
			
		||||
    "type",
 | 
			
		||||
    "size",
 | 
			
		||||
    "modified",
 | 
			
		||||
    "index",
 | 
			
		||||
    "readOnly",
 | 
			
		||||
  ],
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapState(['user', 'selected', 'req', 'jwt']),
 | 
			
		||||
    ...mapGetters(['selectedCount']),
 | 
			
		||||
    singleClick () {
 | 
			
		||||
      return this.readOnly == undefined && this.user.singleClick
 | 
			
		||||
    ...mapState(["user", "selected", "req", "jwt"]),
 | 
			
		||||
    ...mapGetters(["selectedCount"]),
 | 
			
		||||
    singleClick() {
 | 
			
		||||
      return this.readOnly == undefined && this.user.singleClick;
 | 
			
		||||
    },
 | 
			
		||||
    isSelected () {
 | 
			
		||||
      return (this.selected.indexOf(this.index) !== -1)
 | 
			
		||||
    isSelected() {
 | 
			
		||||
      return this.selected.indexOf(this.index) !== -1;
 | 
			
		||||
    },
 | 
			
		||||
    icon () {
 | 
			
		||||
      if (this.isDir) return 'folder'
 | 
			
		||||
      if (this.type === 'image') return 'insert_photo'
 | 
			
		||||
      if (this.type === 'audio') return 'volume_up'
 | 
			
		||||
      if (this.type === 'video') return 'movie'
 | 
			
		||||
      return 'insert_drive_file'
 | 
			
		||||
    icon() {
 | 
			
		||||
      if (this.isDir) return "folder";
 | 
			
		||||
      if (this.type === "image") return "insert_photo";
 | 
			
		||||
      if (this.type === "audio") return "volume_up";
 | 
			
		||||
      if (this.type === "video") return "movie";
 | 
			
		||||
      return "insert_drive_file";
 | 
			
		||||
    },
 | 
			
		||||
    isDraggable () {
 | 
			
		||||
      return this.readOnly == undefined && this.user.perm.rename
 | 
			
		||||
    isDraggable() {
 | 
			
		||||
      return this.readOnly == undefined && this.user.perm.rename;
 | 
			
		||||
    },
 | 
			
		||||
    canDrop () {
 | 
			
		||||
      if (!this.isDir || this.readOnly !== undefined) return false
 | 
			
		||||
    canDrop() {
 | 
			
		||||
      if (!this.isDir || this.readOnly !== undefined) return false;
 | 
			
		||||
 | 
			
		||||
      for (let i of this.selected) {
 | 
			
		||||
        if (this.req.items[i].url === this.url) {
 | 
			
		||||
          return false
 | 
			
		||||
          return false;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return true
 | 
			
		||||
      return true;
 | 
			
		||||
    },
 | 
			
		||||
    thumbnailUrl () {
 | 
			
		||||
      const path = this.url.replace(/^\/files\//, '')
 | 
			
		||||
    thumbnailUrl() {
 | 
			
		||||
      const path = this.url.replace(/^\/files\//, "");
 | 
			
		||||
 | 
			
		||||
      // 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: {
 | 
			
		||||
    ...mapMutations(['addSelected', 'removeSelected', 'resetSelected']),
 | 
			
		||||
    ...mapMutations(["addSelected", "removeSelected", "resetSelected"]),
 | 
			
		||||
    humanSize: function () {
 | 
			
		||||
      return filesize(this.size)
 | 
			
		||||
      return filesize(this.size);
 | 
			
		||||
    },
 | 
			
		||||
    humanTime: function () {
 | 
			
		||||
      return moment(this.modified).fromNow()
 | 
			
		||||
      return moment(this.modified).fromNow();
 | 
			
		||||
    },
 | 
			
		||||
    dragStart: function () {
 | 
			
		||||
      if (this.selectedCount === 0) {
 | 
			
		||||
        this.addSelected(this.index)
 | 
			
		||||
        return
 | 
			
		||||
        this.addSelected(this.index);
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (!this.isSelected) {
 | 
			
		||||
        this.resetSelected()
 | 
			
		||||
        this.addSelected(this.index)
 | 
			
		||||
        this.resetSelected();
 | 
			
		||||
        this.addSelected(this.index);
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    dragOver: function (event) {
 | 
			
		||||
      if (!this.canDrop) return
 | 
			
		||||
      if (!this.canDrop) return;
 | 
			
		||||
 | 
			
		||||
      event.preventDefault()
 | 
			
		||||
      let el = event.target
 | 
			
		||||
      event.preventDefault();
 | 
			
		||||
      let el = event.target;
 | 
			
		||||
 | 
			
		||||
      for (let i = 0; i < 5; i++) {
 | 
			
		||||
        if (!el.classList.contains('item')) {
 | 
			
		||||
          el = el.parentElement
 | 
			
		||||
        if (!el.classList.contains("item")) {
 | 
			
		||||
          el = el.parentElement;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      el.style.opacity = 1
 | 
			
		||||
      el.style.opacity = 1;
 | 
			
		||||
    },
 | 
			
		||||
    drop: async function (event) {
 | 
			
		||||
      if (!this.canDrop) return
 | 
			
		||||
      event.preventDefault()
 | 
			
		||||
      if (!this.canDrop) return;
 | 
			
		||||
      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++) {
 | 
			
		||||
        if (el !== null && !el.classList.contains('item')) {
 | 
			
		||||
          el = el.parentElement
 | 
			
		||||
        if (el !== null && !el.classList.contains("item")) {
 | 
			
		||||
          el = el.parentElement;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      let items = []
 | 
			
		||||
      let items = [];
 | 
			
		||||
 | 
			
		||||
      for (let i of this.selected) {
 | 
			
		||||
        items.push({
 | 
			
		||||
          from: this.req.items[i].url,
 | 
			
		||||
          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 path = this.$route.path + base
 | 
			
		||||
      let baseItems = (await api.fetch(path)).items
 | 
			
		||||
      let base = el.querySelector(".name").innerHTML + "/";
 | 
			
		||||
      let path = this.$route.path + base;
 | 
			
		||||
      let baseItems = (await api.fetch(path)).items;
 | 
			
		||||
 | 
			
		||||
      let action = (overwrite, rename) => {
 | 
			
		||||
        api.move(items, overwrite, rename).then(() => {
 | 
			
		||||
          this.$store.commit('setReload', true)
 | 
			
		||||
        }).catch(this.$showError)
 | 
			
		||||
      }
 | 
			
		||||
        api
 | 
			
		||||
          .move(items, overwrite, rename)
 | 
			
		||||
          .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 rename = false
 | 
			
		||||
      let overwrite = false;
 | 
			
		||||
      let rename = false;
 | 
			
		||||
 | 
			
		||||
      if (conflict) {
 | 
			
		||||
        this.$store.commit('showHover', {
 | 
			
		||||
          prompt: 'replace-rename',
 | 
			
		||||
        this.$store.commit("showHover", {
 | 
			
		||||
          prompt: "replace-rename",
 | 
			
		||||
          confirm: (event, option) => {
 | 
			
		||||
            overwrite = option == 'overwrite'
 | 
			
		||||
            rename = option == 'rename'
 | 
			
		||||
            overwrite = option == "overwrite";
 | 
			
		||||
            rename = option == "rename";
 | 
			
		||||
 | 
			
		||||
            event.preventDefault()
 | 
			
		||||
            this.$store.commit('closeHovers')
 | 
			
		||||
            action(overwrite, rename)
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
            event.preventDefault();
 | 
			
		||||
            this.$store.commit("closeHovers");
 | 
			
		||||
            action(overwrite, rename);
 | 
			
		||||
          },
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      action(overwrite, rename)
 | 
			
		||||
      action(overwrite, rename);
 | 
			
		||||
    },
 | 
			
		||||
    itemClick: function(event) {
 | 
			
		||||
      if (this.singleClick && !this.$store.state.multiple) this.open()
 | 
			
		||||
      else this.click(event)
 | 
			
		||||
    itemClick: function (event) {
 | 
			
		||||
      if (this.singleClick && !this.$store.state.multiple) this.open();
 | 
			
		||||
      else this.click(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) {
 | 
			
		||||
        this.removeSelected(this.index)
 | 
			
		||||
        return
 | 
			
		||||
        this.removeSelected(this.index);
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (event.shiftKey && this.selected.length > 0) {
 | 
			
		||||
        let fi = 0
 | 
			
		||||
        let la = 0
 | 
			
		||||
        let fi = 0;
 | 
			
		||||
        let la = 0;
 | 
			
		||||
 | 
			
		||||
        if (this.index > this.selected[0]) {
 | 
			
		||||
          fi = this.selected[0] + 1
 | 
			
		||||
          la = this.index
 | 
			
		||||
          fi = this.selected[0] + 1;
 | 
			
		||||
          la = this.index;
 | 
			
		||||
        } else {
 | 
			
		||||
          fi = this.index
 | 
			
		||||
          la = this.selected[0] - 1
 | 
			
		||||
          fi = this.index;
 | 
			
		||||
          la = this.selected[0] - 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (; fi <= la; fi++) {
 | 
			
		||||
          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()
 | 
			
		||||
      this.addSelected(this.index)
 | 
			
		||||
      if (
 | 
			
		||||
        !this.singleClick &&
 | 
			
		||||
        !event.ctrlKey &&
 | 
			
		||||
        !event.metaKey &&
 | 
			
		||||
        !this.$store.state.multiple
 | 
			
		||||
      )
 | 
			
		||||
        this.resetSelected();
 | 
			
		||||
      this.addSelected(this.index);
 | 
			
		||||
    },
 | 
			
		||||
    dblclick: function () {
 | 
			
		||||
      if (!this.singleClick) this.open()
 | 
			
		||||
      if (!this.singleClick) this.open();
 | 
			
		||||
    },
 | 
			
		||||
    touchstart () {
 | 
			
		||||
    touchstart() {
 | 
			
		||||
      setTimeout(() => {
 | 
			
		||||
        this.touches = 0
 | 
			
		||||
      }, 300)
 | 
			
		||||
        this.touches = 0;
 | 
			
		||||
      }, 300);
 | 
			
		||||
 | 
			
		||||
      this.touches++
 | 
			
		||||
      this.touches++;
 | 
			
		||||
      if (this.touches > 1) {
 | 
			
		||||
        this.open()
 | 
			
		||||
        this.open();
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    open: function () {
 | 
			
		||||
      this.$router.push({path: this.url})
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
      this.$router.push({ path: this.url });
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
<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>
 | 
			
		||||
    <span>{{ label }}</span>
 | 
			
		||||
    <span v-if="counter > 0" class="counter">{{ counter }}</span>
 | 
			
		||||
| 
						 | 
				
			
			@ -8,25 +8,18 @@
 | 
			
		|||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'action',
 | 
			
		||||
  props: [
 | 
			
		||||
    'icon',
 | 
			
		||||
    'label',
 | 
			
		||||
    'counter',
 | 
			
		||||
    'show'
 | 
			
		||||
  ],
 | 
			
		||||
  name: "action",
 | 
			
		||||
  props: ["icon", "label", "counter", "show"],
 | 
			
		||||
  methods: {
 | 
			
		||||
    action: function () {
 | 
			
		||||
      if (this.show) {
 | 
			
		||||
        this.$store.commit('showHover', this.show)
 | 
			
		||||
        this.$store.commit("showHover", this.show);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this.$emit('action')
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
      this.$emit("action");
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style>
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
<style></style>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,13 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <header>
 | 
			
		||||
    <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 />
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -9,39 +15,44 @@
 | 
			
		|||
      <slot name="actions" />
 | 
			
		||||
    </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>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<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 {
 | 
			
		||||
  name: 'header-bar',
 | 
			
		||||
  props: [
 | 
			
		||||
    'showLogo',
 | 
			
		||||
    'showMenu',
 | 
			
		||||
  ],
 | 
			
		||||
  name: "header-bar",
 | 
			
		||||
  props: ["showLogo", "showMenu"],
 | 
			
		||||
  components: {
 | 
			
		||||
    Action
 | 
			
		||||
    Action,
 | 
			
		||||
  },
 | 
			
		||||
  data: function () {
 | 
			
		||||
    return {
 | 
			
		||||
      logoURL
 | 
			
		||||
    }
 | 
			
		||||
      logoURL,
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    openSidebar () {
 | 
			
		||||
      this.$store.commit('showHover', 'sidebar')
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
    openSidebar() {
 | 
			
		||||
      this.$store.commit("showHover", "sidebar");
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style>
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
<style></style>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,108 +1,119 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div class="card floating">
 | 
			
		||||
    <div class="card-title">
 | 
			
		||||
      <h2>{{ $t('prompts.copy') }}</h2>
 | 
			
		||||
      <h2>{{ $t("prompts.copy") }}</h2>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="card-content">
 | 
			
		||||
      <p>{{ $t('prompts.copyMessage') }}</p>
 | 
			
		||||
      <file-list @update:selected="val => dest = val"></file-list>
 | 
			
		||||
      <p>{{ $t("prompts.copyMessage") }}</p>
 | 
			
		||||
      <file-list @update:selected="(val) => (dest = val)"></file-list>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="card-action">
 | 
			
		||||
      <button class="button button--flat button--grey"
 | 
			
		||||
      <button
 | 
			
		||||
        class="button button--flat button--grey"
 | 
			
		||||
        @click="$store.commit('closeHovers')"
 | 
			
		||||
        :aria-label="$t('buttons.cancel')"
 | 
			
		||||
        :title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
 | 
			
		||||
      <button class="button button--flat"
 | 
			
		||||
        :title="$t('buttons.cancel')"
 | 
			
		||||
      >
 | 
			
		||||
        {{ $t("buttons.cancel") }}
 | 
			
		||||
      </button>
 | 
			
		||||
      <button
 | 
			
		||||
        class="button button--flat"
 | 
			
		||||
        @click="copy"
 | 
			
		||||
        :aria-label="$t('buttons.copy')"
 | 
			
		||||
        :title="$t('buttons.copy')">{{ $t('buttons.copy') }}</button>
 | 
			
		||||
        :title="$t('buttons.copy')"
 | 
			
		||||
      >
 | 
			
		||||
        {{ $t("buttons.copy") }}
 | 
			
		||||
      </button>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { mapState } from 'vuex'
 | 
			
		||||
import FileList from './FileList'
 | 
			
		||||
import { files as api } from '@/api'
 | 
			
		||||
import buttons from '@/utils/buttons'
 | 
			
		||||
import * as upload  from '@/utils/upload'
 | 
			
		||||
import { mapState } from "vuex";
 | 
			
		||||
import FileList from "./FileList";
 | 
			
		||||
import { files as api } from "@/api";
 | 
			
		||||
import buttons from "@/utils/buttons";
 | 
			
		||||
import * as upload from "@/utils/upload";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'copy',
 | 
			
		||||
  name: "copy",
 | 
			
		||||
  components: { FileList },
 | 
			
		||||
  data: function () {
 | 
			
		||||
    return {
 | 
			
		||||
      current: window.location.pathname,
 | 
			
		||||
      dest: null
 | 
			
		||||
    }
 | 
			
		||||
      dest: null,
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  computed: mapState(['req', 'selected']),
 | 
			
		||||
  computed: mapState(["req", "selected"]),
 | 
			
		||||
  methods: {
 | 
			
		||||
    copy: async function (event) {
 | 
			
		||||
      event.preventDefault()
 | 
			
		||||
      let items = []
 | 
			
		||||
      event.preventDefault();
 | 
			
		||||
      let items = [];
 | 
			
		||||
 | 
			
		||||
      // Create a new promise for each file.
 | 
			
		||||
      for (let item of this.selected) {
 | 
			
		||||
        items.push({
 | 
			
		||||
          from: this.req.items[item].url,
 | 
			
		||||
          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) => {
 | 
			
		||||
        buttons.loading('copy')
 | 
			
		||||
        buttons.loading("copy");
 | 
			
		||||
 | 
			
		||||
        await api.copy(items, overwrite, rename).then(() => {
 | 
			
		||||
          buttons.success('copy')
 | 
			
		||||
        await api
 | 
			
		||||
          .copy(items, overwrite, rename)
 | 
			
		||||
          .then(() => {
 | 
			
		||||
            buttons.success("copy");
 | 
			
		||||
 | 
			
		||||
          if (this.$route.path === this.dest) {
 | 
			
		||||
            this.$store.commit('setReload', true)
 | 
			
		||||
            if (this.$route.path === this.dest) {
 | 
			
		||||
              this.$store.commit("setReload", true);
 | 
			
		||||
 | 
			
		||||
            return
 | 
			
		||||
          }
 | 
			
		||||
              return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
          this.$router.push({ path: this.dest })
 | 
			
		||||
        }).catch((e) => {
 | 
			
		||||
          buttons.done('copy')
 | 
			
		||||
          this.$showError(e)
 | 
			
		||||
        })
 | 
			
		||||
      }
 | 
			
		||||
            this.$router.push({ path: this.dest });
 | 
			
		||||
          })
 | 
			
		||||
          .catch((e) => {
 | 
			
		||||
            buttons.done("copy");
 | 
			
		||||
            this.$showError(e);
 | 
			
		||||
          });
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      if (this.$route.path === this.dest) {
 | 
			
		||||
        this.$store.commit('closeHovers')
 | 
			
		||||
        action(false, true)
 | 
			
		||||
        this.$store.commit("closeHovers");
 | 
			
		||||
        action(false, true);
 | 
			
		||||
 | 
			
		||||
        return
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      let dstItems = (await api.fetch(this.dest)).items
 | 
			
		||||
      let conflict = upload.checkConflict(items, dstItems)
 | 
			
		||||
      let dstItems = (await api.fetch(this.dest)).items;
 | 
			
		||||
      let conflict = upload.checkConflict(items, dstItems);
 | 
			
		||||
 | 
			
		||||
      let overwrite = false
 | 
			
		||||
      let rename = false
 | 
			
		||||
      let overwrite = false;
 | 
			
		||||
      let rename = false;
 | 
			
		||||
 | 
			
		||||
      if (conflict) {
 | 
			
		||||
        this.$store.commit('showHover', {
 | 
			
		||||
          prompt: 'replace-rename',
 | 
			
		||||
        this.$store.commit("showHover", {
 | 
			
		||||
          prompt: "replace-rename",
 | 
			
		||||
          confirm: (event, option) => {
 | 
			
		||||
            overwrite = option == 'overwrite'
 | 
			
		||||
            rename = option == 'rename'
 | 
			
		||||
            overwrite = option == "overwrite";
 | 
			
		||||
            rename = option == "rename";
 | 
			
		||||
 | 
			
		||||
            event.preventDefault()
 | 
			
		||||
            this.$store.commit('closeHovers')
 | 
			
		||||
            action(overwrite, rename)
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
            event.preventDefault();
 | 
			
		||||
            this.$store.commit("closeHovers");
 | 
			
		||||
            action(overwrite, rename);
 | 
			
		||||
          },
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      action(overwrite, rename)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
      action(overwrite, rename);
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,68 +1,80 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div class="card floating">
 | 
			
		||||
    <div class="card-content">
 | 
			
		||||
      <p v-if="req.kind !== 'listing'">{{ $t('prompts.deleteMessageSingle') }}</p>
 | 
			
		||||
      <p v-else>{{ $t('prompts.deleteMessageMultiple', { count: selectedCount}) }}</p>
 | 
			
		||||
      <p v-if="req.kind !== 'listing'">
 | 
			
		||||
        {{ $t("prompts.deleteMessageSingle") }}
 | 
			
		||||
      </p>
 | 
			
		||||
      <p v-else>
 | 
			
		||||
        {{ $t("prompts.deleteMessageMultiple", { count: selectedCount }) }}
 | 
			
		||||
      </p>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="card-action">
 | 
			
		||||
      <button @click="$store.commit('closeHovers')"
 | 
			
		||||
      <button
 | 
			
		||||
        @click="$store.commit('closeHovers')"
 | 
			
		||||
        class="button button--flat button--grey"
 | 
			
		||||
        :aria-label="$t('buttons.cancel')"
 | 
			
		||||
        :title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
 | 
			
		||||
      <button @click="submit"
 | 
			
		||||
        :title="$t('buttons.cancel')"
 | 
			
		||||
      >
 | 
			
		||||
        {{ $t("buttons.cancel") }}
 | 
			
		||||
      </button>
 | 
			
		||||
      <button
 | 
			
		||||
        @click="submit"
 | 
			
		||||
        class="button button--flat button--red"
 | 
			
		||||
        :aria-label="$t('buttons.delete')"
 | 
			
		||||
        :title="$t('buttons.delete')">{{ $t('buttons.delete') }}</button>
 | 
			
		||||
        :title="$t('buttons.delete')"
 | 
			
		||||
      >
 | 
			
		||||
        {{ $t("buttons.delete") }}
 | 
			
		||||
      </button>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import {mapGetters, mapMutations, mapState} from 'vuex'
 | 
			
		||||
import { files as api } from '@/api'
 | 
			
		||||
import buttons from '@/utils/buttons'
 | 
			
		||||
import { mapGetters, mapMutations, mapState } from "vuex";
 | 
			
		||||
import { files as api } from "@/api";
 | 
			
		||||
import buttons from "@/utils/buttons";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'delete',
 | 
			
		||||
  name: "delete",
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapGetters(['isListing', 'selectedCount']),
 | 
			
		||||
    ...mapState(['req', 'selected', 'showConfirm'])
 | 
			
		||||
    ...mapGetters(["isListing", "selectedCount"]),
 | 
			
		||||
    ...mapState(["req", "selected", "showConfirm"]),
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    ...mapMutations(['closeHovers']),
 | 
			
		||||
    ...mapMutations(["closeHovers"]),
 | 
			
		||||
    submit: async function () {
 | 
			
		||||
      buttons.loading('delete')
 | 
			
		||||
      buttons.loading("delete");
 | 
			
		||||
 | 
			
		||||
      try {
 | 
			
		||||
        if (!this.isListing) {
 | 
			
		||||
          await api.remove(this.$route.path)
 | 
			
		||||
          buttons.success('delete')
 | 
			
		||||
          await api.remove(this.$route.path);
 | 
			
		||||
          buttons.success("delete");
 | 
			
		||||
 | 
			
		||||
          this.showConfirm()
 | 
			
		||||
          this.closeHovers()
 | 
			
		||||
          return
 | 
			
		||||
          this.showConfirm();
 | 
			
		||||
          this.closeHovers();
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.closeHovers()
 | 
			
		||||
        this.closeHovers();
 | 
			
		||||
 | 
			
		||||
        if (this.selectedCount === 0) {
 | 
			
		||||
          return
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let promises = []
 | 
			
		||||
        let promises = [];
 | 
			
		||||
        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)
 | 
			
		||||
        buttons.success('delete')
 | 
			
		||||
        this.$store.commit('setReload', true)
 | 
			
		||||
        await Promise.all(promises);
 | 
			
		||||
        buttons.success("delete");
 | 
			
		||||
        this.$store.commit("setReload", true);
 | 
			
		||||
      } catch (e) {
 | 
			
		||||
        buttons.done('delete')
 | 
			
		||||
        this.$showError(e)
 | 
			
		||||
        if (this.isListing) this.$store.commit('setReload', true)
 | 
			
		||||
        buttons.done("delete");
 | 
			
		||||
        this.$showError(e);
 | 
			
		||||
        if (this.isListing) this.$store.commit("setReload", true);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,35 +1,43 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div class="card floating" id="download">
 | 
			
		||||
    <div class="card-title">
 | 
			
		||||
      <h2>{{ $t('prompts.download') }}</h2>
 | 
			
		||||
      <h2>{{ $t("prompts.download") }}</h2>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <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>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { mapState } from 'vuex'
 | 
			
		||||
import { mapState } from "vuex";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'download',
 | 
			
		||||
  name: "download",
 | 
			
		||||
  data: function () {
 | 
			
		||||
    return {
 | 
			
		||||
      formats: {
 | 
			
		||||
        zip: 'zip',
 | 
			
		||||
        tar: 'tar',
 | 
			
		||||
        targz: 'tar.gz',
 | 
			
		||||
        tarbz2: 'tar.bz2',
 | 
			
		||||
        tarxz: 'tar.xz',
 | 
			
		||||
        tarlz4: 'tar.lz4',
 | 
			
		||||
        tarsz: 'tar.sz'
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
        zip: "zip",
 | 
			
		||||
        tar: "tar",
 | 
			
		||||
        targz: "tar.gz",
 | 
			
		||||
        tarbz2: "tar.bz2",
 | 
			
		||||
        tarxz: "tar.xz",
 | 
			
		||||
        tarlz4: "tar.lz4",
 | 
			
		||||
        tarsz: "tar.sz",
 | 
			
		||||
      },
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  computed: mapState(['showConfirm'])
 | 
			
		||||
}
 | 
			
		||||
  computed: mapState(["showConfirm"]),
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,132 +1,138 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div>
 | 
			
		||||
    <ul class="file-list">
 | 
			
		||||
      <li @click="itemClick"
 | 
			
		||||
      <li
 | 
			
		||||
        @click="itemClick"
 | 
			
		||||
        @touchstart="touchstart"
 | 
			
		||||
        @dblclick="next"
 | 
			
		||||
        role="button"
 | 
			
		||||
        tabindex="0"
 | 
			
		||||
        :aria-label="item.name"
 | 
			
		||||
        :aria-selected="selected == item.url"
 | 
			
		||||
        :key="item.name" v-for="item in items"
 | 
			
		||||
        :data-url="item.url">{{ item.name }}</li>
 | 
			
		||||
        :key="item.name"
 | 
			
		||||
        v-for="item in items"
 | 
			
		||||
        :data-url="item.url"
 | 
			
		||||
      >
 | 
			
		||||
        {{ item.name }}
 | 
			
		||||
      </li>
 | 
			
		||||
    </ul>
 | 
			
		||||
 | 
			
		||||
    <p>{{ $t('prompts.currentlyNavigating') }} <code>{{ nav }}</code>.</p>
 | 
			
		||||
    <p>
 | 
			
		||||
      {{ $t("prompts.currentlyNavigating") }} <code>{{ nav }}</code
 | 
			
		||||
      >.
 | 
			
		||||
    </p>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { mapState } from 'vuex'
 | 
			
		||||
import url from '@/utils/url'
 | 
			
		||||
import { files } from '@/api'
 | 
			
		||||
import { mapState } from "vuex";
 | 
			
		||||
import url from "@/utils/url";
 | 
			
		||||
import { files } from "@/api";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'file-list',
 | 
			
		||||
  name: "file-list",
 | 
			
		||||
  data: function () {
 | 
			
		||||
    return {
 | 
			
		||||
      items: [],
 | 
			
		||||
      touches: {
 | 
			
		||||
        id: '',
 | 
			
		||||
        count: 0
 | 
			
		||||
        id: "",
 | 
			
		||||
        count: 0,
 | 
			
		||||
      },
 | 
			
		||||
      selected: null,
 | 
			
		||||
      current: window.location.pathname
 | 
			
		||||
    }
 | 
			
		||||
      current: window.location.pathname,
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapState([ 'req', 'user' ]),
 | 
			
		||||
    nav () {
 | 
			
		||||
      return decodeURIComponent(this.current)
 | 
			
		||||
    }
 | 
			
		||||
    ...mapState(["req", "user"]),
 | 
			
		||||
    nav() {
 | 
			
		||||
      return decodeURIComponent(this.current);
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  mounted () {
 | 
			
		||||
    this.fillOptions(this.req)
 | 
			
		||||
  mounted() {
 | 
			
		||||
    this.fillOptions(this.req);
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    fillOptions (req) {
 | 
			
		||||
    fillOptions(req) {
 | 
			
		||||
      // Sets the current path and resets
 | 
			
		||||
      // the current items.
 | 
			
		||||
      this.current = req.url
 | 
			
		||||
      this.items = []
 | 
			
		||||
      this.current = req.url;
 | 
			
		||||
      this.items = [];
 | 
			
		||||
 | 
			
		||||
      this.$emit('update:selected', this.current)
 | 
			
		||||
      this.$emit("update:selected", this.current);
 | 
			
		||||
 | 
			
		||||
      // If the path isn't the root path,
 | 
			
		||||
      // show a button to navigate to the previous
 | 
			
		||||
      // directory.
 | 
			
		||||
      if (req.url !== '/files/') {
 | 
			
		||||
      if (req.url !== "/files/") {
 | 
			
		||||
        this.items.push({
 | 
			
		||||
          name: '..',
 | 
			
		||||
          url: url.removeLastDir(req.url) + '/'
 | 
			
		||||
        })
 | 
			
		||||
          name: "..",
 | 
			
		||||
          url: url.removeLastDir(req.url) + "/",
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // If this folder is empty, finish here.
 | 
			
		||||
      if (req.items === null) return
 | 
			
		||||
      if (req.items === null) return;
 | 
			
		||||
 | 
			
		||||
      // Otherwise we add every directory to the
 | 
			
		||||
      // move options.
 | 
			
		||||
      for (let item of req.items) {
 | 
			
		||||
        if (!item.isDir) continue
 | 
			
		||||
        if (!item.isDir) continue;
 | 
			
		||||
 | 
			
		||||
        this.items.push({
 | 
			
		||||
          name: item.name,
 | 
			
		||||
          url: item.url
 | 
			
		||||
        })
 | 
			
		||||
          url: item.url,
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    next: function (event) {
 | 
			
		||||
      // Retrieves the URL of the directory the user
 | 
			
		||||
      // just clicked in and fill the options with its
 | 
			
		||||
      // content.
 | 
			
		||||
      let uri = event.currentTarget.dataset.url
 | 
			
		||||
      let uri = event.currentTarget.dataset.url;
 | 
			
		||||
 | 
			
		||||
      files.fetch(uri)
 | 
			
		||||
        .then(this.fillOptions)
 | 
			
		||||
        .catch(this.$showError)
 | 
			
		||||
      files.fetch(uri).then(this.fillOptions).catch(this.$showError);
 | 
			
		||||
    },
 | 
			
		||||
    touchstart (event) {
 | 
			
		||||
      let url = event.currentTarget.dataset.url
 | 
			
		||||
    touchstart(event) {
 | 
			
		||||
      let url = event.currentTarget.dataset.url;
 | 
			
		||||
 | 
			
		||||
      // In 300 milliseconds, we shall reset the count.
 | 
			
		||||
      setTimeout(() => {
 | 
			
		||||
        this.touches.count = 0
 | 
			
		||||
      }, 300)
 | 
			
		||||
        this.touches.count = 0;
 | 
			
		||||
      }, 300);
 | 
			
		||||
 | 
			
		||||
      // If the element the user is touching
 | 
			
		||||
      // is different from the last one he touched,
 | 
			
		||||
      // reset the count.
 | 
			
		||||
      if (this.touches.id !== url) {
 | 
			
		||||
        this.touches.id = url
 | 
			
		||||
        this.touches.count = 1
 | 
			
		||||
        return
 | 
			
		||||
        this.touches.id = url;
 | 
			
		||||
        this.touches.count = 1;
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this.touches.count++
 | 
			
		||||
      this.touches.count++;
 | 
			
		||||
 | 
			
		||||
      // If there is more than one touch already,
 | 
			
		||||
      // open the next screen.
 | 
			
		||||
      if (this.touches.count > 1) {
 | 
			
		||||
        this.next(event)
 | 
			
		||||
        this.next(event);
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    itemClick: function (event) {
 | 
			
		||||
      if (this.user.singleClick) this.next(event)
 | 
			
		||||
      else this.select(event)
 | 
			
		||||
      if (this.user.singleClick) this.next(event);
 | 
			
		||||
      else this.select(event);
 | 
			
		||||
    },
 | 
			
		||||
    select: function (event) {
 | 
			
		||||
      // If the element is already selected, unselect it.
 | 
			
		||||
      if (this.selected === event.currentTarget.dataset.url) {
 | 
			
		||||
        this.selected = null
 | 
			
		||||
        this.$emit('update:selected', this.current)
 | 
			
		||||
        return
 | 
			
		||||
        this.selected = null;
 | 
			
		||||
        this.$emit("update:selected", this.current);
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // Otherwise select the element.
 | 
			
		||||
      this.selected = event.currentTarget.dataset.url
 | 
			
		||||
      this.$emit('update:selected', this.selected)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
      this.selected = event.currentTarget.dataset.url;
 | 
			
		||||
      this.$emit("update:selected", this.selected);
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,34 +1,37 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div class="card floating help">
 | 
			
		||||
    <div class="card-title">
 | 
			
		||||
      <h2>{{ $t('help.help') }}</h2>
 | 
			
		||||
      <h2>{{ $t("help.help") }}</h2>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="card-content">
 | 
			
		||||
      <ul>
 | 
			
		||||
        <li><strong>F1</strong> - {{ $t('help.f1') }}</li>
 | 
			
		||||
        <li><strong>F2</strong> - {{ $t('help.f2') }}</li>
 | 
			
		||||
        <li><strong>DEL</strong> - {{ $t('help.del') }}</li>
 | 
			
		||||
        <li><strong>ESC</strong> - {{ $t('help.esc') }}</li>
 | 
			
		||||
        <li><strong>CTRL + S</strong> - {{ $t('help.ctrl.s') }}</li>
 | 
			
		||||
        <li><strong>CTRL + F</strong> - {{ $t('help.ctrl.f') }}</li>
 | 
			
		||||
        <li><strong>CTRL + Click</strong> - {{ $t('help.ctrl.click') }}</li>
 | 
			
		||||
        <li><strong>Click</strong> - {{ $t('help.click') }}</li>
 | 
			
		||||
        <li><strong>Double click</strong> - {{ $t('help.doubleClick') }}</li>
 | 
			
		||||
        <li><strong>F1</strong> - {{ $t("help.f1") }}</li>
 | 
			
		||||
        <li><strong>F2</strong> - {{ $t("help.f2") }}</li>
 | 
			
		||||
        <li><strong>DEL</strong> - {{ $t("help.del") }}</li>
 | 
			
		||||
        <li><strong>ESC</strong> - {{ $t("help.esc") }}</li>
 | 
			
		||||
        <li><strong>CTRL + S</strong> - {{ $t("help.ctrl.s") }}</li>
 | 
			
		||||
        <li><strong>CTRL + F</strong> - {{ $t("help.ctrl.f") }}</li>
 | 
			
		||||
        <li><strong>CTRL + Click</strong> - {{ $t("help.ctrl.click") }}</li>
 | 
			
		||||
        <li><strong>Click</strong> - {{ $t("help.click") }}</li>
 | 
			
		||||
        <li><strong>Double click</strong> - {{ $t("help.doubleClick") }}</li>
 | 
			
		||||
      </ul>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="card-action">
 | 
			
		||||
      <button type="submit"
 | 
			
		||||
      <button
 | 
			
		||||
        type="submit"
 | 
			
		||||
        @click="$store.commit('closeHovers')"
 | 
			
		||||
        class="button button--flat"
 | 
			
		||||
        :aria-label="$t('buttons.ok')"
 | 
			
		||||
        :title="$t('buttons.ok')">{{ $t('buttons.ok') }}</button>
 | 
			
		||||
        :title="$t('buttons.ok')"
 | 
			
		||||
      >
 | 
			
		||||
        {{ $t("buttons.ok") }}
 | 
			
		||||
      </button>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default { name: 'help' }
 | 
			
		||||
export default { name: "help" };
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,99 +1,149 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div class="card floating">
 | 
			
		||||
    <div class="card-title">
 | 
			
		||||
      <h2>{{ $t('prompts.fileInfo') }}</h2>
 | 
			
		||||
      <h2>{{ $t("prompts.fileInfo") }}</h2>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <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 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>
 | 
			
		||||
      <p class="break-word" v-if="selected.length < 2">
 | 
			
		||||
        <strong>{{ $t("prompts.displayName") }}</strong> {{ name }}
 | 
			
		||||
      </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">
 | 
			
		||||
        <p><strong>{{ $t('prompts.numberFiles') }}:</strong> {{ req.numFiles }}</p>
 | 
			
		||||
        <p><strong>{{ $t('prompts.numberDirs') }}:</strong> {{ req.numDirs }}</p>
 | 
			
		||||
        <p>
 | 
			
		||||
          <strong>{{ $t("prompts.numberFiles") }}:</strong> {{ req.numFiles }}
 | 
			
		||||
        </p>
 | 
			
		||||
        <p>
 | 
			
		||||
          <strong>{{ $t("prompts.numberDirs") }}:</strong> {{ req.numDirs }}
 | 
			
		||||
        </p>
 | 
			
		||||
      </template>
 | 
			
		||||
 | 
			
		||||
      <template v-if="!dir">
 | 
			
		||||
        <p><strong>MD5: </strong><code><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>
 | 
			
		||||
        <p>
 | 
			
		||||
          <strong>MD5: </strong
 | 
			
		||||
          ><code
 | 
			
		||||
            ><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>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="card-action">
 | 
			
		||||
      <button type="submit"
 | 
			
		||||
      <button
 | 
			
		||||
        type="submit"
 | 
			
		||||
        @click="$store.commit('closeHovers')"
 | 
			
		||||
        class="button button--flat"
 | 
			
		||||
        :aria-label="$t('buttons.ok')"
 | 
			
		||||
        :title="$t('buttons.ok')">{{ $t('buttons.ok') }}</button>
 | 
			
		||||
        :title="$t('buttons.ok')"
 | 
			
		||||
      >
 | 
			
		||||
        {{ $t("buttons.ok") }}
 | 
			
		||||
      </button>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import {mapState, mapGetters} from 'vuex'
 | 
			
		||||
import filesize from 'filesize'
 | 
			
		||||
import moment from 'moment'
 | 
			
		||||
import { files as api } from '@/api'
 | 
			
		||||
import { mapState, mapGetters } from "vuex";
 | 
			
		||||
import filesize from "filesize";
 | 
			
		||||
import moment from "moment";
 | 
			
		||||
import { files as api } from "@/api";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'info',
 | 
			
		||||
  name: "info",
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapState(['req', 'selected']),
 | 
			
		||||
    ...mapGetters(['selectedCount', 'isListing']),
 | 
			
		||||
    ...mapState(["req", "selected"]),
 | 
			
		||||
    ...mapGetters(["selectedCount", "isListing"]),
 | 
			
		||||
    humanSize: function () {
 | 
			
		||||
      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) {
 | 
			
		||||
        sum += this.req.items[selected].size
 | 
			
		||||
        sum += this.req.items[selected].size;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return filesize(sum)
 | 
			
		||||
      return filesize(sum);
 | 
			
		||||
    },
 | 
			
		||||
    humanTime: function () {
 | 
			
		||||
      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 () {
 | 
			
		||||
      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 () {
 | 
			
		||||
      return this.selectedCount > 1 || (this.selectedCount === 0
 | 
			
		||||
        ? this.req.isDir
 | 
			
		||||
        : this.req.items[this.selected[0]].isDir)
 | 
			
		||||
    }
 | 
			
		||||
      return (
 | 
			
		||||
        this.selectedCount > 1 ||
 | 
			
		||||
        (this.selectedCount === 0
 | 
			
		||||
          ? this.req.isDir
 | 
			
		||||
          : this.req.items[this.selected[0]].isDir)
 | 
			
		||||
      );
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    checksum: async function (event, algo) {
 | 
			
		||||
      event.preventDefault()
 | 
			
		||||
      event.preventDefault();
 | 
			
		||||
 | 
			
		||||
      let link
 | 
			
		||||
      let link;
 | 
			
		||||
 | 
			
		||||
      if (this.selectedCount) {
 | 
			
		||||
        link = this.req.items[this.selected[0]].url
 | 
			
		||||
        link = this.req.items[this.selected[0]].url;
 | 
			
		||||
      } else {
 | 
			
		||||
        link = this.$route.path
 | 
			
		||||
        link = this.$route.path;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      try {
 | 
			
		||||
        const hash = await api.checksum(link, algo)
 | 
			
		||||
        const hash = await api.checksum(link, algo);
 | 
			
		||||
        // eslint-disable-next-line
 | 
			
		||||
        event.target.innerHTML = hash
 | 
			
		||||
      } catch (e) {
 | 
			
		||||
        this.$showError(e)
 | 
			
		||||
        this.$showError(e);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,93 +1,104 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div class="card floating">
 | 
			
		||||
    <div class="card-title">
 | 
			
		||||
      <h2>{{ $t('prompts.move') }}</h2>
 | 
			
		||||
      <h2>{{ $t("prompts.move") }}</h2>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="card-content">
 | 
			
		||||
      <file-list @update:selected="val => dest = val"></file-list>
 | 
			
		||||
      <file-list @update:selected="(val) => (dest = val)"></file-list>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="card-action">
 | 
			
		||||
      <button class="button button--flat button--grey"
 | 
			
		||||
      <button
 | 
			
		||||
        class="button button--flat button--grey"
 | 
			
		||||
        @click="$store.commit('closeHovers')"
 | 
			
		||||
        :aria-label="$t('buttons.cancel')"
 | 
			
		||||
        :title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
 | 
			
		||||
      <button class="button button--flat"
 | 
			
		||||
        :title="$t('buttons.cancel')"
 | 
			
		||||
      >
 | 
			
		||||
        {{ $t("buttons.cancel") }}
 | 
			
		||||
      </button>
 | 
			
		||||
      <button
 | 
			
		||||
        class="button button--flat"
 | 
			
		||||
        @click="move"
 | 
			
		||||
        :disabled="$route.path === dest"
 | 
			
		||||
        :aria-label="$t('buttons.move')"
 | 
			
		||||
        :title="$t('buttons.move')">{{ $t('buttons.move') }}</button>
 | 
			
		||||
        :title="$t('buttons.move')"
 | 
			
		||||
      >
 | 
			
		||||
        {{ $t("buttons.move") }}
 | 
			
		||||
      </button>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { mapState } from 'vuex'
 | 
			
		||||
import FileList from './FileList'
 | 
			
		||||
import { files as api } from '@/api'
 | 
			
		||||
import buttons from '@/utils/buttons'
 | 
			
		||||
import * as upload  from '@/utils/upload'
 | 
			
		||||
import { mapState } from "vuex";
 | 
			
		||||
import FileList from "./FileList";
 | 
			
		||||
import { files as api } from "@/api";
 | 
			
		||||
import buttons from "@/utils/buttons";
 | 
			
		||||
import * as upload from "@/utils/upload";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'move',
 | 
			
		||||
  name: "move",
 | 
			
		||||
  components: { FileList },
 | 
			
		||||
  data: function () {
 | 
			
		||||
    return {
 | 
			
		||||
      current: window.location.pathname,
 | 
			
		||||
      dest: null
 | 
			
		||||
    }
 | 
			
		||||
      dest: null,
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  computed: mapState(['req', 'selected']),
 | 
			
		||||
  computed: mapState(["req", "selected"]),
 | 
			
		||||
  methods: {
 | 
			
		||||
    move: async function (event) {
 | 
			
		||||
      event.preventDefault()
 | 
			
		||||
      let items = []
 | 
			
		||||
      event.preventDefault();
 | 
			
		||||
      let items = [];
 | 
			
		||||
 | 
			
		||||
      for (let item of this.selected) {
 | 
			
		||||
        items.push({
 | 
			
		||||
          from: this.req.items[item].url,
 | 
			
		||||
          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) => {
 | 
			
		||||
        buttons.loading('move')
 | 
			
		||||
        buttons.loading("move");
 | 
			
		||||
 | 
			
		||||
        await api.move(items, overwrite, rename).then(() => {
 | 
			
		||||
          buttons.success('move')
 | 
			
		||||
          this.$router.push({ path: this.dest })
 | 
			
		||||
        }).catch((e) => {
 | 
			
		||||
          buttons.done('move')
 | 
			
		||||
          this.$showError(e)
 | 
			
		||||
        })
 | 
			
		||||
      }
 | 
			
		||||
        await api
 | 
			
		||||
          .move(items, overwrite, rename)
 | 
			
		||||
          .then(() => {
 | 
			
		||||
            buttons.success("move");
 | 
			
		||||
            this.$router.push({ path: this.dest });
 | 
			
		||||
          })
 | 
			
		||||
          .catch((e) => {
 | 
			
		||||
            buttons.done("move");
 | 
			
		||||
            this.$showError(e);
 | 
			
		||||
          });
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      let dstItems = (await api.fetch(this.dest)).items
 | 
			
		||||
      let conflict = upload.checkConflict(items, dstItems)
 | 
			
		||||
      let dstItems = (await api.fetch(this.dest)).items;
 | 
			
		||||
      let conflict = upload.checkConflict(items, dstItems);
 | 
			
		||||
 | 
			
		||||
      let overwrite = false
 | 
			
		||||
      let rename = false
 | 
			
		||||
      let overwrite = false;
 | 
			
		||||
      let rename = false;
 | 
			
		||||
 | 
			
		||||
      if (conflict) {
 | 
			
		||||
        this.$store.commit('showHover', {
 | 
			
		||||
          prompt: 'replace-rename',
 | 
			
		||||
        this.$store.commit("showHover", {
 | 
			
		||||
          prompt: "replace-rename",
 | 
			
		||||
          confirm: (event, option) => {
 | 
			
		||||
            overwrite = option == 'overwrite'
 | 
			
		||||
            rename = option == 'rename'
 | 
			
		||||
            overwrite = option == "overwrite";
 | 
			
		||||
            rename = option == "rename";
 | 
			
		||||
 | 
			
		||||
            event.preventDefault()
 | 
			
		||||
            this.$store.commit('closeHovers')
 | 
			
		||||
            action(overwrite, rename)
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
            event.preventDefault();
 | 
			
		||||
            this.$store.commit("closeHovers");
 | 
			
		||||
            action(overwrite, rename);
 | 
			
		||||
          },
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      action(overwrite, rename)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
      action(overwrite, rename);
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,12 +1,18 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div class="card floating">
 | 
			
		||||
    <div class="card-title">
 | 
			
		||||
      <h2>{{ $t('prompts.newDir') }}</h2>
 | 
			
		||||
      <h2>{{ $t("prompts.newDir") }}</h2>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="card-content">
 | 
			
		||||
      <p>{{ $t('prompts.newDirMessage') }}</p>
 | 
			
		||||
      <input class="input input--block" type="text" @keyup.enter="submit" v-model.trim="name" v-focus>
 | 
			
		||||
      <p>{{ $t("prompts.newDirMessage") }}</p>
 | 
			
		||||
      <input
 | 
			
		||||
        class="input input--block"
 | 
			
		||||
        type="text"
 | 
			
		||||
        @keyup.enter="submit"
 | 
			
		||||
        v-model.trim="name"
 | 
			
		||||
        v-focus
 | 
			
		||||
      />
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="card-action">
 | 
			
		||||
| 
						 | 
				
			
			@ -15,57 +21,60 @@
 | 
			
		|||
        @click="$store.commit('closeHovers')"
 | 
			
		||||
        :aria-label="$t('buttons.cancel')"
 | 
			
		||||
        :title="$t('buttons.cancel')"
 | 
			
		||||
      >{{ $t('buttons.cancel') }}</button>
 | 
			
		||||
      >
 | 
			
		||||
        {{ $t("buttons.cancel") }}
 | 
			
		||||
      </button>
 | 
			
		||||
      <button
 | 
			
		||||
        class="button button--flat"
 | 
			
		||||
        :aria-label="$t('buttons.create')"
 | 
			
		||||
        :title="$t('buttons.create')"
 | 
			
		||||
        @click="submit"
 | 
			
		||||
      >{{ $t('buttons.create') }}</button>
 | 
			
		||||
      >
 | 
			
		||||
        {{ $t("buttons.create") }}
 | 
			
		||||
      </button>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { mapGetters } from 'vuex'
 | 
			
		||||
import { files as api } from '@/api'
 | 
			
		||||
import url from '@/utils/url'
 | 
			
		||||
import { mapGetters } from "vuex";
 | 
			
		||||
import { files as api } from "@/api";
 | 
			
		||||
import url from "@/utils/url";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'new-dir',
 | 
			
		||||
  data: function() {
 | 
			
		||||
  name: "new-dir",
 | 
			
		||||
  data: function () {
 | 
			
		||||
    return {
 | 
			
		||||
      name: ''
 | 
			
		||||
      name: "",
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapGetters([ 'isFiles', 'isListing' ])
 | 
			
		||||
    ...mapGetters(["isFiles", "isListing"]),
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    submit: async function(event) {
 | 
			
		||||
      event.preventDefault()
 | 
			
		||||
      if (this.new === '') return
 | 
			
		||||
    submit: async function (event) {
 | 
			
		||||
      event.preventDefault();
 | 
			
		||||
      if (this.new === "") return;
 | 
			
		||||
 | 
			
		||||
      // Build the path of the new directory.
 | 
			
		||||
      let uri = this.isFiles ? this.$route.path + '/' : '/'
 | 
			
		||||
      let uri = this.isFiles ? this.$route.path + "/" : "/";
 | 
			
		||||
 | 
			
		||||
      if (!this.isListing) {
 | 
			
		||||
        uri = url.removeLastDir(uri) + '/'
 | 
			
		||||
        uri = url.removeLastDir(uri) + "/";
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      uri += encodeURIComponent(this.name) + '/'
 | 
			
		||||
      uri = uri.replace('//', '/')
 | 
			
		||||
      uri += encodeURIComponent(this.name) + "/";
 | 
			
		||||
      uri = uri.replace("//", "/");
 | 
			
		||||
 | 
			
		||||
      try {
 | 
			
		||||
        await api.post(uri)
 | 
			
		||||
        this.$router.push({ path: uri })
 | 
			
		||||
        await api.post(uri);
 | 
			
		||||
        this.$router.push({ path: uri });
 | 
			
		||||
      } catch (e) {
 | 
			
		||||
        this.$showError(e)
 | 
			
		||||
        this.$showError(e);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this.$store.commit('closeHovers')
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
      this.$store.commit("closeHovers");
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,12 +1,18 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div class="card floating">
 | 
			
		||||
    <div class="card-title">
 | 
			
		||||
      <h2>{{ $t('prompts.newFile') }}</h2>
 | 
			
		||||
      <h2>{{ $t("prompts.newFile") }}</h2>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="card-content">
 | 
			
		||||
      <p>{{ $t('prompts.newFileMessage') }}</p>
 | 
			
		||||
      <input class="input input--block" v-focus type="text" @keyup.enter="submit" v-model.trim="name">
 | 
			
		||||
      <p>{{ $t("prompts.newFileMessage") }}</p>
 | 
			
		||||
      <input
 | 
			
		||||
        class="input input--block"
 | 
			
		||||
        v-focus
 | 
			
		||||
        type="text"
 | 
			
		||||
        @keyup.enter="submit"
 | 
			
		||||
        v-model.trim="name"
 | 
			
		||||
      />
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="card-action">
 | 
			
		||||
| 
						 | 
				
			
			@ -15,57 +21,60 @@
 | 
			
		|||
        @click="$store.commit('closeHovers')"
 | 
			
		||||
        :aria-label="$t('buttons.cancel')"
 | 
			
		||||
        :title="$t('buttons.cancel')"
 | 
			
		||||
      >{{ $t('buttons.cancel') }}</button>
 | 
			
		||||
      >
 | 
			
		||||
        {{ $t("buttons.cancel") }}
 | 
			
		||||
      </button>
 | 
			
		||||
      <button
 | 
			
		||||
        class="button button--flat"
 | 
			
		||||
        @click="submit"
 | 
			
		||||
        :aria-label="$t('buttons.create')"
 | 
			
		||||
        :title="$t('buttons.create')"
 | 
			
		||||
      >{{ $t('buttons.create') }}</button>
 | 
			
		||||
      >
 | 
			
		||||
        {{ $t("buttons.create") }}
 | 
			
		||||
      </button>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { mapGetters } from 'vuex'
 | 
			
		||||
import { files as api } from '@/api'
 | 
			
		||||
import url from '@/utils/url'
 | 
			
		||||
import { mapGetters } from "vuex";
 | 
			
		||||
import { files as api } from "@/api";
 | 
			
		||||
import url from "@/utils/url";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'new-file',
 | 
			
		||||
  data: function() {
 | 
			
		||||
  name: "new-file",
 | 
			
		||||
  data: function () {
 | 
			
		||||
    return {
 | 
			
		||||
      name: ''
 | 
			
		||||
      name: "",
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapGetters([ 'isFiles', 'isListing' ])
 | 
			
		||||
    ...mapGetters(["isFiles", "isListing"]),
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    submit: async function(event) {
 | 
			
		||||
      event.preventDefault()
 | 
			
		||||
      if (this.new === '') return
 | 
			
		||||
    submit: async function (event) {
 | 
			
		||||
      event.preventDefault();
 | 
			
		||||
      if (this.new === "") return;
 | 
			
		||||
 | 
			
		||||
      // Build the path of the new directory.
 | 
			
		||||
      let uri = this.isFiles ? this.$route.path + '/' : '/'
 | 
			
		||||
      let uri = this.isFiles ? this.$route.path + "/" : "/";
 | 
			
		||||
 | 
			
		||||
      if (!this.isListing) {
 | 
			
		||||
        uri = url.removeLastDir(uri) + '/'
 | 
			
		||||
        uri = url.removeLastDir(uri) + "/";
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      uri += encodeURIComponent(this.name)
 | 
			
		||||
      uri = uri.replace('//', '/')
 | 
			
		||||
      uri += encodeURIComponent(this.name);
 | 
			
		||||
      uri = uri.replace("//", "/");
 | 
			
		||||
 | 
			
		||||
      try {
 | 
			
		||||
        await api.post(uri)
 | 
			
		||||
        this.$router.push({ path: uri })
 | 
			
		||||
        await api.post(uri);
 | 
			
		||||
        this.$router.push({ path: uri });
 | 
			
		||||
      } catch (e) {
 | 
			
		||||
        this.$showError(e)
 | 
			
		||||
        this.$showError(e);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this.$store.commit('closeHovers')
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
      this.$store.commit("closeHovers");
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,25 +6,25 @@
 | 
			
		|||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import Help from './Help'
 | 
			
		||||
import Info from './Info'
 | 
			
		||||
import Delete from './Delete'
 | 
			
		||||
import Rename from './Rename'
 | 
			
		||||
import Download from './Download'
 | 
			
		||||
import Move from './Move'
 | 
			
		||||
import Copy from './Copy'
 | 
			
		||||
import NewFile from './NewFile'
 | 
			
		||||
import NewDir from './NewDir'
 | 
			
		||||
import Replace from './Replace'
 | 
			
		||||
import ReplaceRename from './ReplaceRename'
 | 
			
		||||
import Share from './Share'
 | 
			
		||||
import Upload from './Upload'
 | 
			
		||||
import ShareDelete from './ShareDelete'
 | 
			
		||||
import { mapState } from 'vuex'
 | 
			
		||||
import buttons from '@/utils/buttons'
 | 
			
		||||
import Help from "./Help";
 | 
			
		||||
import Info from "./Info";
 | 
			
		||||
import Delete from "./Delete";
 | 
			
		||||
import Rename from "./Rename";
 | 
			
		||||
import Download from "./Download";
 | 
			
		||||
import Move from "./Move";
 | 
			
		||||
import Copy from "./Copy";
 | 
			
		||||
import NewFile from "./NewFile";
 | 
			
		||||
import NewDir from "./NewDir";
 | 
			
		||||
import Replace from "./Replace";
 | 
			
		||||
import ReplaceRename from "./ReplaceRename";
 | 
			
		||||
import Share from "./Share";
 | 
			
		||||
import Upload from "./Upload";
 | 
			
		||||
import ShareDelete from "./ShareDelete";
 | 
			
		||||
import { mapState } from "vuex";
 | 
			
		||||
import buttons from "@/utils/buttons";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'prompts',
 | 
			
		||||
  name: "prompts",
 | 
			
		||||
  components: {
 | 
			
		||||
    Info,
 | 
			
		||||
    Delete,
 | 
			
		||||
| 
						 | 
				
			
			@ -39,74 +39,75 @@ export default {
 | 
			
		|||
    Replace,
 | 
			
		||||
    ReplaceRename,
 | 
			
		||||
    Upload,
 | 
			
		||||
    ShareDelete
 | 
			
		||||
    ShareDelete,
 | 
			
		||||
  },
 | 
			
		||||
  data: function () {
 | 
			
		||||
    return {
 | 
			
		||||
      pluginData: {
 | 
			
		||||
        buttons,
 | 
			
		||||
        'store': this.$store,
 | 
			
		||||
        'router': this.$router
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
        store: this.$store,
 | 
			
		||||
        router: this.$router,
 | 
			
		||||
      },
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  created () {
 | 
			
		||||
    window.addEventListener('keydown', (event) => {
 | 
			
		||||
      if (this.show == null)
 | 
			
		||||
      return
 | 
			
		||||
  created() {
 | 
			
		||||
    window.addEventListener("keydown", (event) => {
 | 
			
		||||
      if (this.show == null) return;
 | 
			
		||||
 | 
			
		||||
      let prompt = this.$refs.currentComponent;
 | 
			
		||||
 | 
			
		||||
      // Enter
 | 
			
		||||
      if (event.keyCode == 13) {
 | 
			
		||||
        switch (this.show) {
 | 
			
		||||
          case 'delete':
 | 
			
		||||
            prompt.submit()
 | 
			
		||||
          case "delete":
 | 
			
		||||
            prompt.submit();
 | 
			
		||||
            break;
 | 
			
		||||
          case 'copy':
 | 
			
		||||
            prompt.copy(event)
 | 
			
		||||
          case "copy":
 | 
			
		||||
            prompt.copy(event);
 | 
			
		||||
            break;
 | 
			
		||||
          case 'move':
 | 
			
		||||
            prompt.move(event)
 | 
			
		||||
          case "move":
 | 
			
		||||
            prompt.move(event);
 | 
			
		||||
            break;
 | 
			
		||||
          case 'replace':
 | 
			
		||||
            prompt.showConfirm(event)
 | 
			
		||||
          case "replace":
 | 
			
		||||
            prompt.showConfirm(event);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      }
 | 
			
		||||
    })
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapState(['show', 'plugins']),
 | 
			
		||||
    ...mapState(["show", "plugins"]),
 | 
			
		||||
    currentComponent: function () {
 | 
			
		||||
      const matched = [
 | 
			
		||||
        'info',
 | 
			
		||||
        'help',
 | 
			
		||||
        'delete',
 | 
			
		||||
        'rename',
 | 
			
		||||
        'move',
 | 
			
		||||
        'copy',
 | 
			
		||||
        'newFile',
 | 
			
		||||
        'newDir',
 | 
			
		||||
        'download',
 | 
			
		||||
        'replace',
 | 
			
		||||
        'replace-rename',
 | 
			
		||||
        'share',
 | 
			
		||||
        'upload',
 | 
			
		||||
        'share-delete'
 | 
			
		||||
      ].indexOf(this.show) >= 0;
 | 
			
		||||
      const matched =
 | 
			
		||||
        [
 | 
			
		||||
          "info",
 | 
			
		||||
          "help",
 | 
			
		||||
          "delete",
 | 
			
		||||
          "rename",
 | 
			
		||||
          "move",
 | 
			
		||||
          "copy",
 | 
			
		||||
          "newFile",
 | 
			
		||||
          "newDir",
 | 
			
		||||
          "download",
 | 
			
		||||
          "replace",
 | 
			
		||||
          "replace-rename",
 | 
			
		||||
          "share",
 | 
			
		||||
          "upload",
 | 
			
		||||
          "share-delete",
 | 
			
		||||
        ].indexOf(this.show) >= 0;
 | 
			
		||||
 | 
			
		||||
      return matched && this.show || null;
 | 
			
		||||
      return (matched && this.show) || null;
 | 
			
		||||
    },
 | 
			
		||||
    showOverlay: function () {
 | 
			
		||||
      return (this.show !== null && this.show !== 'search' && this.show !== 'more')
 | 
			
		||||
    }
 | 
			
		||||
      return (
 | 
			
		||||
        this.show !== null && this.show !== "search" && this.show !== "more"
 | 
			
		||||
      );
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    resetPrompts () {
 | 
			
		||||
      this.$store.commit('closeHovers')
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
    resetPrompts() {
 | 
			
		||||
      this.$store.commit("closeHovers");
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,89 +1,107 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div class="card floating">
 | 
			
		||||
    <div class="card-title">
 | 
			
		||||
      <h2>{{ $t('prompts.rename') }}</h2>
 | 
			
		||||
      <h2>{{ $t("prompts.rename") }}</h2>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="card-content">
 | 
			
		||||
      <p>{{ $t('prompts.renameMessage') }} <code>{{ oldName() }}</code>:</p>
 | 
			
		||||
      <input class="input input--block" v-focus type="text" @keyup.enter="submit" v-model.trim="name">
 | 
			
		||||
      <p>
 | 
			
		||||
        {{ $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 class="card-action">
 | 
			
		||||
      <button class="button button--flat button--grey"
 | 
			
		||||
      <button
 | 
			
		||||
        class="button button--flat button--grey"
 | 
			
		||||
        @click="$store.commit('closeHovers')"
 | 
			
		||||
        :aria-label="$t('buttons.cancel')"
 | 
			
		||||
        :title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
 | 
			
		||||
      <button @click="submit"
 | 
			
		||||
        :title="$t('buttons.cancel')"
 | 
			
		||||
      >
 | 
			
		||||
        {{ $t("buttons.cancel") }}
 | 
			
		||||
      </button>
 | 
			
		||||
      <button
 | 
			
		||||
        @click="submit"
 | 
			
		||||
        class="button button--flat"
 | 
			
		||||
        type="submit"
 | 
			
		||||
        :aria-label="$t('buttons.rename')"
 | 
			
		||||
        :title="$t('buttons.rename')">{{ $t('buttons.rename') }}</button>
 | 
			
		||||
        :title="$t('buttons.rename')"
 | 
			
		||||
      >
 | 
			
		||||
        {{ $t("buttons.rename") }}
 | 
			
		||||
      </button>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { mapState, mapGetters } from 'vuex'
 | 
			
		||||
import url from '@/utils/url'
 | 
			
		||||
import { files as api } from '@/api'
 | 
			
		||||
import { mapState, mapGetters } from "vuex";
 | 
			
		||||
import url from "@/utils/url";
 | 
			
		||||
import { files as api } from "@/api";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'rename',
 | 
			
		||||
  name: "rename",
 | 
			
		||||
  data: function () {
 | 
			
		||||
    return {
 | 
			
		||||
      name: ''
 | 
			
		||||
    }
 | 
			
		||||
      name: "",
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  created () {
 | 
			
		||||
    this.name = this.oldName()
 | 
			
		||||
  created() {
 | 
			
		||||
    this.name = this.oldName();
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapState(['req', 'selected', 'selectedCount']),
 | 
			
		||||
    ...mapGetters(['isListing'])
 | 
			
		||||
    ...mapState(["req", "selected", "selectedCount"]),
 | 
			
		||||
    ...mapGetters(["isListing"]),
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    cancel: function () {
 | 
			
		||||
      this.$store.commit('closeHovers')
 | 
			
		||||
      this.$store.commit("closeHovers");
 | 
			
		||||
    },
 | 
			
		||||
    oldName: function () {
 | 
			
		||||
      if (!this.isListing) {
 | 
			
		||||
        return this.req.name
 | 
			
		||||
        return this.req.name;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (this.selectedCount === 0 || this.selectedCount > 1) {
 | 
			
		||||
        // 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 () {
 | 
			
		||||
      let oldLink = ''
 | 
			
		||||
      let newLink = ''
 | 
			
		||||
      let oldLink = "";
 | 
			
		||||
      let newLink = "";
 | 
			
		||||
 | 
			
		||||
      if (!this.isListing) {
 | 
			
		||||
        oldLink = this.req.url
 | 
			
		||||
        oldLink = this.req.url;
 | 
			
		||||
      } 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 {
 | 
			
		||||
        await api.move([{ from: oldLink, to: newLink }])
 | 
			
		||||
        await api.move([{ from: oldLink, to: newLink }]);
 | 
			
		||||
        if (!this.isListing) {
 | 
			
		||||
          this.$router.push({ path: newLink })
 | 
			
		||||
          return
 | 
			
		||||
          this.$router.push({ path: newLink });
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.$store.commit('setReload', true)
 | 
			
		||||
        this.$store.commit("setReload", true);
 | 
			
		||||
      } catch (e) {
 | 
			
		||||
        this.$showError(e)
 | 
			
		||||
        this.$showError(e);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this.$store.commit('closeHovers')
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
      this.$store.commit("closeHovers");
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,31 +1,39 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div class="card floating">
 | 
			
		||||
    <div class="card-title">
 | 
			
		||||
      <h2>{{ $t('prompts.replace') }}</h2>
 | 
			
		||||
      <h2>{{ $t("prompts.replace") }}</h2>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="card-content">
 | 
			
		||||
      <p>{{ $t('prompts.replaceMessage') }}</p>
 | 
			
		||||
      <p>{{ $t("prompts.replaceMessage") }}</p>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="card-action">
 | 
			
		||||
      <button class="button button--flat button--grey"
 | 
			
		||||
      <button
 | 
			
		||||
        class="button button--flat button--grey"
 | 
			
		||||
        @click="$store.commit('closeHovers')"
 | 
			
		||||
        :aria-label="$t('buttons.cancel')"
 | 
			
		||||
        :title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
 | 
			
		||||
      <button class="button button--flat button--red"
 | 
			
		||||
        :title="$t('buttons.cancel')"
 | 
			
		||||
      >
 | 
			
		||||
        {{ $t("buttons.cancel") }}
 | 
			
		||||
      </button>
 | 
			
		||||
      <button
 | 
			
		||||
        class="button button--flat button--red"
 | 
			
		||||
        @click="showConfirm"
 | 
			
		||||
        :aria-label="$t('buttons.replace')"
 | 
			
		||||
        :title="$t('buttons.replace')">{{ $t('buttons.replace') }}</button>
 | 
			
		||||
        :title="$t('buttons.replace')"
 | 
			
		||||
      >
 | 
			
		||||
        {{ $t("buttons.replace") }}
 | 
			
		||||
      </button>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { mapState } from 'vuex'
 | 
			
		||||
import { mapState } from "vuex";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'replace',
 | 
			
		||||
  computed: mapState(['showConfirm'])
 | 
			
		||||
}
 | 
			
		||||
  name: "replace",
 | 
			
		||||
  computed: mapState(["showConfirm"]),
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,35 +1,47 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div class="card floating">
 | 
			
		||||
    <div class="card-title">
 | 
			
		||||
      <h2>{{ $t('prompts.replace') }}</h2>
 | 
			
		||||
      <h2>{{ $t("prompts.replace") }}</h2>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="card-content">
 | 
			
		||||
      <p>{{ $t('prompts.replaceMessage') }}</p>
 | 
			
		||||
      <p>{{ $t("prompts.replaceMessage") }}</p>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="card-action">
 | 
			
		||||
      <button class="button button--flat button--grey"
 | 
			
		||||
      <button
 | 
			
		||||
        class="button button--flat button--grey"
 | 
			
		||||
        @click="$store.commit('closeHovers')"
 | 
			
		||||
        :aria-label="$t('buttons.cancel')"
 | 
			
		||||
        :title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
 | 
			
		||||
      <button class="button button--flat button--blue"
 | 
			
		||||
        :title="$t('buttons.cancel')"
 | 
			
		||||
      >
 | 
			
		||||
        {{ $t("buttons.cancel") }}
 | 
			
		||||
      </button>
 | 
			
		||||
      <button
 | 
			
		||||
        class="button button--flat button--blue"
 | 
			
		||||
        @click="(event) => showConfirm(event, 'rename')"
 | 
			
		||||
        :aria-label="$t('buttons.rename')"
 | 
			
		||||
        :title="$t('buttons.rename')">{{ $t('buttons.rename') }}</button>
 | 
			
		||||
      <button class="button button--flat button--red"
 | 
			
		||||
        :title="$t('buttons.rename')"
 | 
			
		||||
      >
 | 
			
		||||
        {{ $t("buttons.rename") }}
 | 
			
		||||
      </button>
 | 
			
		||||
      <button
 | 
			
		||||
        class="button button--flat button--red"
 | 
			
		||||
        @click="(event) => showConfirm(event, 'overwrite')"
 | 
			
		||||
        :aria-label="$t('buttons.replace')"
 | 
			
		||||
        :title="$t('buttons.replace')">{{ $t('buttons.replace') }}</button>
 | 
			
		||||
        :title="$t('buttons.replace')"
 | 
			
		||||
      >
 | 
			
		||||
        {{ $t("buttons.replace") }}
 | 
			
		||||
      </button>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { mapState } from 'vuex'
 | 
			
		||||
import { mapState } from "vuex";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'replace-rename',
 | 
			
		||||
  computed: mapState(['showConfirm'])
 | 
			
		||||
}
 | 
			
		||||
  name: "replace-rename",
 | 
			
		||||
  computed: mapState(["showConfirm"]),
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div class="card floating share__promt__card" id="share">
 | 
			
		||||
    <div class="card-title">
 | 
			
		||||
      <h2>{{ $t('buttons.share') }}</h2>
 | 
			
		||||
      <h2>{{ $t("buttons.share") }}</h2>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <template v-if="listing">
 | 
			
		||||
| 
						 | 
				
			
			@ -9,7 +9,7 @@
 | 
			
		|||
        <table>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <th>#</th>
 | 
			
		||||
            <th>{{ $t('settings.shareDuration') }}</th>
 | 
			
		||||
            <th>{{ $t("settings.shareDuration") }}</th>
 | 
			
		||||
            <th></th>
 | 
			
		||||
            <th></th>
 | 
			
		||||
          </tr>
 | 
			
		||||
| 
						 | 
				
			
			@ -17,188 +17,219 @@
 | 
			
		|||
          <tr v-for="link in links" :key="link.hash">
 | 
			
		||||
            <td>{{ link.hash }}</td>
 | 
			
		||||
            <td>
 | 
			
		||||
              <template v-if="link.expire !== 0">{{ humanTime(link.expire) }}</template>
 | 
			
		||||
              <template v-else>{{ $t('permanent') }}</template>
 | 
			
		||||
              <template v-if="link.expire !== 0">{{
 | 
			
		||||
                humanTime(link.expire)
 | 
			
		||||
              }}</template>
 | 
			
		||||
              <template v-else>{{ $t("permanent") }}</template>
 | 
			
		||||
            </td>
 | 
			
		||||
            <td class="small">
 | 
			
		||||
              <button class="action copy-clipboard"
 | 
			
		||||
              <button
 | 
			
		||||
                class="action copy-clipboard"
 | 
			
		||||
                :data-clipboard-text="buildLink(link.hash)"
 | 
			
		||||
                :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 class="small">
 | 
			
		||||
              <button class="action"
 | 
			
		||||
              <button
 | 
			
		||||
                class="action"
 | 
			
		||||
                @click="deleteLink($event, link)"
 | 
			
		||||
                :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>
 | 
			
		||||
          </tr>
 | 
			
		||||
        </table>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <div class="card-action">
 | 
			
		||||
        <button class="button button--flat button--grey"
 | 
			
		||||
        <button
 | 
			
		||||
          class="button button--flat button--grey"
 | 
			
		||||
          @click="$store.commit('closeHovers')"
 | 
			
		||||
          :aria-label="$t('buttons.close')"
 | 
			
		||||
          :title="$t('buttons.close')">{{ $t('buttons.close') }}</button>
 | 
			
		||||
        <button class="button button--flat button--blue"
 | 
			
		||||
          :title="$t('buttons.close')"
 | 
			
		||||
        >
 | 
			
		||||
          {{ $t("buttons.close") }}
 | 
			
		||||
        </button>
 | 
			
		||||
        <button
 | 
			
		||||
          class="button button--flat button--blue"
 | 
			
		||||
          @click="() => switchListing()"
 | 
			
		||||
          :aria-label="$t('buttons.new')"
 | 
			
		||||
          :title="$t('buttons.new')">{{ $t('buttons.new') }}</button>
 | 
			
		||||
          :title="$t('buttons.new')"
 | 
			
		||||
        >
 | 
			
		||||
          {{ $t("buttons.new") }}
 | 
			
		||||
        </button>
 | 
			
		||||
      </div>
 | 
			
		||||
    </template>
 | 
			
		||||
 | 
			
		||||
    <template v-else>
 | 
			
		||||
      <div class="card-content">
 | 
			
		||||
        <p>{{ $t('settings.shareDuration') }}</p>
 | 
			
		||||
        <p>{{ $t("settings.shareDuration") }}</p>
 | 
			
		||||
        <div class="input-group input">
 | 
			
		||||
            <input v-focus
 | 
			
		||||
              type="number"
 | 
			
		||||
              max="2147483647"
 | 
			
		||||
              min="1"
 | 
			
		||||
              @keyup.enter="submit"
 | 
			
		||||
              v-model.trim="time">
 | 
			
		||||
            <select class="right" v-model="unit" :aria-label="$t('time.unit')">
 | 
			
		||||
              <option value="seconds">{{ $t('time.seconds') }}</option>
 | 
			
		||||
              <option value="minutes">{{ $t('time.minutes') }}</option>
 | 
			
		||||
              <option value="hours">{{ $t('time.hours') }}</option>
 | 
			
		||||
              <option value="days">{{ $t('time.days') }}</option>
 | 
			
		||||
            </select>
 | 
			
		||||
          <input
 | 
			
		||||
            v-focus
 | 
			
		||||
            type="number"
 | 
			
		||||
            max="2147483647"
 | 
			
		||||
            min="1"
 | 
			
		||||
            @keyup.enter="submit"
 | 
			
		||||
            v-model.trim="time"
 | 
			
		||||
          />
 | 
			
		||||
          <select class="right" v-model="unit" :aria-label="$t('time.unit')">
 | 
			
		||||
            <option value="seconds">{{ $t("time.seconds") }}</option>
 | 
			
		||||
            <option value="minutes">{{ $t("time.minutes") }}</option>
 | 
			
		||||
            <option value="hours">{{ $t("time.hours") }}</option>
 | 
			
		||||
            <option value="days">{{ $t("time.days") }}</option>
 | 
			
		||||
          </select>
 | 
			
		||||
        </div>
 | 
			
		||||
        <p>{{ $t('prompts.optionalPassword') }}</p>
 | 
			
		||||
        <input class="input input--block" type="password" v-model.trim="password">
 | 
			
		||||
        <p>{{ $t("prompts.optionalPassword") }}</p>
 | 
			
		||||
        <input
 | 
			
		||||
          class="input input--block"
 | 
			
		||||
          type="password"
 | 
			
		||||
          v-model.trim="password"
 | 
			
		||||
        />
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <div class="card-action">
 | 
			
		||||
        <button class="button button--flat button--grey"
 | 
			
		||||
        <button
 | 
			
		||||
          class="button button--flat button--grey"
 | 
			
		||||
          @click="() => switchListing()"
 | 
			
		||||
          :aria-label="$t('buttons.cancel')"
 | 
			
		||||
          :title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
 | 
			
		||||
        <button class="button button--flat button--blue"
 | 
			
		||||
          :title="$t('buttons.cancel')"
 | 
			
		||||
        >
 | 
			
		||||
          {{ $t("buttons.cancel") }}
 | 
			
		||||
        </button>
 | 
			
		||||
        <button
 | 
			
		||||
          class="button button--flat button--blue"
 | 
			
		||||
          @click="submit"
 | 
			
		||||
          :aria-label="$t('buttons.share')"
 | 
			
		||||
          :title="$t('buttons.share')">{{ $t('buttons.share') }}</button>
 | 
			
		||||
          :title="$t('buttons.share')"
 | 
			
		||||
        >
 | 
			
		||||
          {{ $t("buttons.share") }}
 | 
			
		||||
        </button>
 | 
			
		||||
      </div>
 | 
			
		||||
    </template>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { mapState, mapGetters } from 'vuex'
 | 
			
		||||
import { share as api } from '@/api'
 | 
			
		||||
import { baseURL } from '@/utils/constants'
 | 
			
		||||
import moment from 'moment'
 | 
			
		||||
import Clipboard from 'clipboard'
 | 
			
		||||
import { mapState, mapGetters } from "vuex";
 | 
			
		||||
import { share as api } from "@/api";
 | 
			
		||||
import { baseURL } from "@/utils/constants";
 | 
			
		||||
import moment from "moment";
 | 
			
		||||
import Clipboard from "clipboard";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'share',
 | 
			
		||||
  name: "share",
 | 
			
		||||
  data: function () {
 | 
			
		||||
    return {
 | 
			
		||||
      time: '',
 | 
			
		||||
      unit: 'hours',
 | 
			
		||||
      time: "",
 | 
			
		||||
      unit: "hours",
 | 
			
		||||
      links: [],
 | 
			
		||||
      clip: null,
 | 
			
		||||
      password: '',
 | 
			
		||||
      listing: true
 | 
			
		||||
    }
 | 
			
		||||
      password: "",
 | 
			
		||||
      listing: true,
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapState([ 'req', 'selected', 'selectedCount' ]),
 | 
			
		||||
    ...mapGetters([ 'isListing' ]),
 | 
			
		||||
    url () {
 | 
			
		||||
    ...mapState(["req", "selected", "selectedCount"]),
 | 
			
		||||
    ...mapGetters(["isListing"]),
 | 
			
		||||
    url() {
 | 
			
		||||
      if (!this.isListing) {
 | 
			
		||||
        return this.$route.path
 | 
			
		||||
        return this.$route.path;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (this.selectedCount === 0 || this.selectedCount > 1) {
 | 
			
		||||
        // 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 {
 | 
			
		||||
      const links = await api.get(this.url)
 | 
			
		||||
      this.links = links
 | 
			
		||||
      this.sort()
 | 
			
		||||
      const links = await api.get(this.url);
 | 
			
		||||
      this.links = links;
 | 
			
		||||
      this.sort();
 | 
			
		||||
 | 
			
		||||
      if (this.links.length == 0) {
 | 
			
		||||
        this.listing = false
 | 
			
		||||
        this.listing = false;
 | 
			
		||||
      }
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      this.$showError(e)
 | 
			
		||||
      this.$showError(e);
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  mounted () {
 | 
			
		||||
    this.clip = new Clipboard('.copy-clipboard')
 | 
			
		||||
    this.clip.on('success', () => {
 | 
			
		||||
      this.$showSuccess(this.$t('success.linkCopied'))
 | 
			
		||||
    })
 | 
			
		||||
  mounted() {
 | 
			
		||||
    this.clip = new Clipboard(".copy-clipboard");
 | 
			
		||||
    this.clip.on("success", () => {
 | 
			
		||||
      this.$showSuccess(this.$t("success.linkCopied"));
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
  beforeDestroy () {
 | 
			
		||||
    this.clip.destroy()
 | 
			
		||||
  beforeDestroy() {
 | 
			
		||||
    this.clip.destroy();
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    submit: async function () {
 | 
			
		||||
      let isPermanent = !this.time || this.time == 0
 | 
			
		||||
      let isPermanent = !this.time || this.time == 0;
 | 
			
		||||
 | 
			
		||||
      try {
 | 
			
		||||
        let res = null
 | 
			
		||||
        let res = null;
 | 
			
		||||
 | 
			
		||||
        if (isPermanent) {
 | 
			
		||||
          res = await api.create(this.url, this.password)
 | 
			
		||||
          res = await api.create(this.url, this.password);
 | 
			
		||||
        } 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.sort()
 | 
			
		||||
        this.links.push(res);
 | 
			
		||||
        this.sort();
 | 
			
		||||
 | 
			
		||||
        this.time = ''
 | 
			
		||||
        this.unit = 'hours'
 | 
			
		||||
        this.password = ''
 | 
			
		||||
        this.time = "";
 | 
			
		||||
        this.unit = "hours";
 | 
			
		||||
        this.password = "";
 | 
			
		||||
 | 
			
		||||
        this.listing = true
 | 
			
		||||
        this.listing = true;
 | 
			
		||||
      } catch (e) {
 | 
			
		||||
        this.$showError(e)
 | 
			
		||||
        this.$showError(e);
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    deleteLink: async function (event, link) {
 | 
			
		||||
      event.preventDefault()
 | 
			
		||||
       try {
 | 
			
		||||
        await api.remove(link.hash)
 | 
			
		||||
        this.links = this.links.filter(item => item.hash !== link.hash)
 | 
			
		||||
      event.preventDefault();
 | 
			
		||||
      try {
 | 
			
		||||
        await api.remove(link.hash);
 | 
			
		||||
        this.links = this.links.filter((item) => item.hash !== link.hash);
 | 
			
		||||
 | 
			
		||||
        if (this.links.length == 0) {
 | 
			
		||||
          this.listing = false
 | 
			
		||||
          this.listing = false;
 | 
			
		||||
        }
 | 
			
		||||
      } catch (e) {
 | 
			
		||||
        this.$showError(e)
 | 
			
		||||
        this.$showError(e);
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    humanTime (time) {
 | 
			
		||||
      return moment(time * 1000).fromNow()
 | 
			
		||||
    humanTime(time) {
 | 
			
		||||
      return moment(time * 1000).fromNow();
 | 
			
		||||
    },
 | 
			
		||||
    buildLink (hash) {
 | 
			
		||||
      return `${window.location.origin}${baseURL}/share/${hash}`
 | 
			
		||||
    buildLink(hash) {
 | 
			
		||||
      return `${window.location.origin}${baseURL}/share/${hash}`;
 | 
			
		||||
    },
 | 
			
		||||
    sort () {
 | 
			
		||||
    sort() {
 | 
			
		||||
      this.links = this.links.sort((a, b) => {
 | 
			
		||||
        if (a.expire === 0) return -1
 | 
			
		||||
        if (b.expire === 0) return 1
 | 
			
		||||
        return new Date(a.expire) - new Date(b.expire)
 | 
			
		||||
      })
 | 
			
		||||
        if (a.expire === 0) return -1;
 | 
			
		||||
        if (b.expire === 0) return 1;
 | 
			
		||||
        return new Date(a.expire) - new Date(b.expire);
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
    switchListing () {
 | 
			
		||||
    switchListing() {
 | 
			
		||||
      if (this.links.length == 0 && !this.listing) {
 | 
			
		||||
        this.$store.commit('closeHovers')
 | 
			
		||||
        this.$store.commit("closeHovers");
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this.listing = !this.listing
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
      this.listing = !this.listing;
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,33 +1,41 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div class="card floating">
 | 
			
		||||
    <div class="card-content">
 | 
			
		||||
      <p>{{ $t('prompts.deleteMessageShare', {path: ''}) }}</p>
 | 
			
		||||
      <p>{{ $t("prompts.deleteMessageShare", { path: "" }) }}</p>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="card-action">
 | 
			
		||||
      <button @click="$store.commit('closeHovers')"
 | 
			
		||||
      <button
 | 
			
		||||
        @click="$store.commit('closeHovers')"
 | 
			
		||||
        class="button button--flat button--grey"
 | 
			
		||||
        :aria-label="$t('buttons.cancel')"
 | 
			
		||||
        :title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
 | 
			
		||||
      <button @click="submit"
 | 
			
		||||
        :title="$t('buttons.cancel')"
 | 
			
		||||
      >
 | 
			
		||||
        {{ $t("buttons.cancel") }}
 | 
			
		||||
      </button>
 | 
			
		||||
      <button
 | 
			
		||||
        @click="submit"
 | 
			
		||||
        class="button button--flat button--red"
 | 
			
		||||
        :aria-label="$t('buttons.delete')"
 | 
			
		||||
        :title="$t('buttons.delete')">{{ $t('buttons.delete') }}</button>
 | 
			
		||||
        :title="$t('buttons.delete')"
 | 
			
		||||
      >
 | 
			
		||||
        {{ $t("buttons.delete") }}
 | 
			
		||||
      </button>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import {mapState} from 'vuex'
 | 
			
		||||
import { mapState } from "vuex";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'share-delete',
 | 
			
		||||
  name: "share-delete",
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapState(['showConfirm'])
 | 
			
		||||
    ...mapState(["showConfirm"]),
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    submit: function () {
 | 
			
		||||
      this.showConfirm()
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
      this.showConfirm();
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,11 +1,11 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div class="card floating">
 | 
			
		||||
    <div class="card-title">
 | 
			
		||||
      <h2>{{ $t('prompts.upload') }}</h2>
 | 
			
		||||
      <h2>{{ $t("prompts.upload") }}</h2>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="card-content">
 | 
			
		||||
      <p>{{ $t('prompts.uploadMessage') }}</p>
 | 
			
		||||
      <p>{{ $t("prompts.uploadMessage") }}</p>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="card-action full">
 | 
			
		||||
| 
						 | 
				
			
			@ -22,18 +22,17 @@
 | 
			
		|||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'upload',
 | 
			
		||||
  name: "upload",
 | 
			
		||||
  methods: {
 | 
			
		||||
    uploadFile: function () {
 | 
			
		||||
      document.getElementById('upload-input').value = ''
 | 
			
		||||
      document.getElementById('upload-input').click()
 | 
			
		||||
      document.getElementById("upload-input").value = "";
 | 
			
		||||
      document.getElementById("upload-input").click();
 | 
			
		||||
    },
 | 
			
		||||
    uploadFolder: function () {
 | 
			
		||||
      document.getElementById('upload-folder-input').value = ''
 | 
			
		||||
      document.getElementById('upload-folder-input').click()
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
      document.getElementById("upload-folder-input").value = "";
 | 
			
		||||
      document.getElementById("upload-folder-input").click();
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,28 +1,30 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div>
 | 
			
		||||
    <h3>{{ $t('settings.userCommands') }}</h3>
 | 
			
		||||
    <p class="small">{{ $t('settings.userCommandsHelp') }} <i>git svn hg</i>.</p>
 | 
			
		||||
    <input class="input input--block" type="text" v-model.trim="raw">
 | 
			
		||||
    <h3>{{ $t("settings.userCommands") }}</h3>
 | 
			
		||||
    <p class="small">
 | 
			
		||||
      {{ $t("settings.userCommandsHelp") }} <i>git svn hg</i>.
 | 
			
		||||
    </p>
 | 
			
		||||
    <input class="input input--block" type="text" v-model.trim="raw" />
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'permissions',
 | 
			
		||||
  props: ['commands'],
 | 
			
		||||
  name: "permissions",
 | 
			
		||||
  props: ["commands"],
 | 
			
		||||
  computed: {
 | 
			
		||||
    raw: {
 | 
			
		||||
      get () {
 | 
			
		||||
        return this.commands.join(' ')
 | 
			
		||||
      get() {
 | 
			
		||||
        return this.commands.join(" ");
 | 
			
		||||
      },
 | 
			
		||||
      set (value) {
 | 
			
		||||
        if (value !== '') {
 | 
			
		||||
          this.$emit('update:commands', value.split(' '))
 | 
			
		||||
      set(value) {
 | 
			
		||||
        if (value !== "") {
 | 
			
		||||
          this.$emit("update:commands", value.split(" "));
 | 
			
		||||
        } else {
 | 
			
		||||
          this.$emit('update:commands', [])
 | 
			
		||||
          this.$emit("update:commands", []);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,46 +1,50 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <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>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'languages',
 | 
			
		||||
  props: [ 'locale' ],
 | 
			
		||||
  name: "languages",
 | 
			
		||||
  props: ["locale"],
 | 
			
		||||
  data() {
 | 
			
		||||
    let dataObj = {
 | 
			
		||||
      locales: {
 | 
			
		||||
        ar: 'ar',
 | 
			
		||||
        de: 'de',
 | 
			
		||||
        en: 'en',
 | 
			
		||||
        es: 'es',
 | 
			
		||||
        fr: 'fr',
 | 
			
		||||
        is: 'is',
 | 
			
		||||
        it: 'it',
 | 
			
		||||
        ja: 'ja',
 | 
			
		||||
        ko: 'ko',
 | 
			
		||||
        'nl-be': 'nlBE',
 | 
			
		||||
        pl: 'pl',
 | 
			
		||||
        'pt-br': 'ptBR',
 | 
			
		||||
        pt: 'pt',
 | 
			
		||||
        ro: 'ro',
 | 
			
		||||
        ru: 'ru',
 | 
			
		||||
        'sv-se': 'svSE',
 | 
			
		||||
        'zh-cn': 'zhCN',
 | 
			
		||||
        'zh-tw': 'zhTW'
 | 
			
		||||
      }
 | 
			
		||||
        ar: "ar",
 | 
			
		||||
        de: "de",
 | 
			
		||||
        en: "en",
 | 
			
		||||
        es: "es",
 | 
			
		||||
        fr: "fr",
 | 
			
		||||
        is: "is",
 | 
			
		||||
        it: "it",
 | 
			
		||||
        ja: "ja",
 | 
			
		||||
        ko: "ko",
 | 
			
		||||
        "nl-be": "nlBE",
 | 
			
		||||
        pl: "pl",
 | 
			
		||||
        "pt-br": "ptBR",
 | 
			
		||||
        pt: "pt",
 | 
			
		||||
        ro: "ro",
 | 
			
		||||
        ru: "ru",
 | 
			
		||||
        "sv-se": "svSE",
 | 
			
		||||
        "zh-cn": "zhCN",
 | 
			
		||||
        "zh-tw": "zhTW",
 | 
			
		||||
      },
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    Object.defineProperty(dataObj, "locales", { configurable: false, writable: false });
 | 
			
		||||
    Object.defineProperty(dataObj, "locales", {
 | 
			
		||||
      configurable: false,
 | 
			
		||||
      writable: false,
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return dataObj;
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    change (event) {
 | 
			
		||||
      this.$emit('update:locale', event.target.value)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
    change(event) {
 | 
			
		||||
      this.$emit("update:locale", event.target.value);
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,41 +1,65 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div>
 | 
			
		||||
    <h3>{{ $t('settings.permissions') }}</h3>
 | 
			
		||||
    <p class="small">{{ $t('settings.permissionsHelp') }}</p>
 | 
			
		||||
    <h3>{{ $t("settings.permissions") }}</h3>
 | 
			
		||||
    <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><input type="checkbox" :disabled="admin" v-model="perm.delete"> {{ $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>
 | 
			
		||||
    <p>
 | 
			
		||||
      <input type="checkbox" :disabled="admin" v-model="perm.create" />
 | 
			
		||||
      {{ $t("settings.perm.create") }}
 | 
			
		||||
    </p>
 | 
			
		||||
    <p>
 | 
			
		||||
      <input type="checkbox" :disabled="admin" v-model="perm.delete" />
 | 
			
		||||
      {{ $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>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { enableExec } from '@/utils/constants'
 | 
			
		||||
import { enableExec } from "@/utils/constants";
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'permissions',
 | 
			
		||||
  props: ['perm'],
 | 
			
		||||
  name: "permissions",
 | 
			
		||||
  props: ["perm"],
 | 
			
		||||
  computed: {
 | 
			
		||||
    admin: {
 | 
			
		||||
      get () {
 | 
			
		||||
        return this.perm.admin
 | 
			
		||||
      get() {
 | 
			
		||||
        return this.perm.admin;
 | 
			
		||||
      },
 | 
			
		||||
      set (value) {
 | 
			
		||||
      set(value) {
 | 
			
		||||
        if (value) {
 | 
			
		||||
          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>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,57 +1,63 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <form class="rules small">
 | 
			
		||||
    <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.allow"><label>Allow</label>
 | 
			
		||||
      <input type="checkbox" v-model="rule.regex" /><label>Regex</label>
 | 
			
		||||
      <input type="checkbox" v-model="rule.allow" /><label>Allow</label>
 | 
			
		||||
 | 
			
		||||
      <input
 | 
			
		||||
        @keypress.enter.prevent
 | 
			
		||||
        type="text"
 | 
			
		||||
        v-if="rule.regex"
 | 
			
		||||
        v-model="rule.regexp.raw"
 | 
			
		||||
        :placeholder="$t('settings.insertRegex')" />
 | 
			
		||||
        :placeholder="$t('settings.insertRegex')"
 | 
			
		||||
      />
 | 
			
		||||
      <input
 | 
			
		||||
        @keypress.enter.prevent
 | 
			
		||||
        type="text"
 | 
			
		||||
        v-else
 | 
			
		||||
        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>
 | 
			
		||||
      <button class="button" @click="create" default="false">{{ $t('buttons.new') }}</button>
 | 
			
		||||
      <button class="button" @click="create" default="false">
 | 
			
		||||
        {{ $t("buttons.new") }}
 | 
			
		||||
      </button>
 | 
			
		||||
    </div>
 | 
			
		||||
  </form>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'rules-textarea',
 | 
			
		||||
  props: ['rules'],
 | 
			
		||||
  name: "rules-textarea",
 | 
			
		||||
  props: ["rules"],
 | 
			
		||||
  methods: {
 | 
			
		||||
    remove (event, index) {
 | 
			
		||||
      event.preventDefault()
 | 
			
		||||
      let rules = [ ...this.rules ]
 | 
			
		||||
      rules.splice(index, 1)
 | 
			
		||||
      this.$emit('update:rules', [ ...rules ])
 | 
			
		||||
    remove(event, index) {
 | 
			
		||||
      event.preventDefault();
 | 
			
		||||
      let rules = [...this.rules];
 | 
			
		||||
      rules.splice(index, 1);
 | 
			
		||||
      this.$emit("update:rules", [...rules]);
 | 
			
		||||
    },
 | 
			
		||||
    create (event) {
 | 
			
		||||
      event.preventDefault()
 | 
			
		||||
    create(event) {
 | 
			
		||||
      event.preventDefault();
 | 
			
		||||
 | 
			
		||||
      this.$emit('update:rules', [
 | 
			
		||||
      this.$emit("update:rules", [
 | 
			
		||||
        ...this.rules,
 | 
			
		||||
        {
 | 
			
		||||
          allow: true,
 | 
			
		||||
          path: '',
 | 
			
		||||
          path: "",
 | 
			
		||||
          regex: false,
 | 
			
		||||
          regexp: {
 | 
			
		||||
            raw: ''
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      ])
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
            raw: "",
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      ]);
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,18 +1,18 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <select v-on:change="change" :value="theme">
 | 
			
		||||
    <option value="">{{ $t('settings.themes.light') }}</option>
 | 
			
		||||
    <option value="dark">{{ $t('settings.themes.dark') }}</option>
 | 
			
		||||
    <option value="">{{ $t("settings.themes.light") }}</option>
 | 
			
		||||
    <option value="dark">{{ $t("settings.themes.dark") }}</option>
 | 
			
		||||
  </select>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'themes',
 | 
			
		||||
  props: [ 'theme' ],
 | 
			
		||||
  name: "themes",
 | 
			
		||||
  props: ["theme"],
 | 
			
		||||
  methods: {
 | 
			
		||||
    change (event) {
 | 
			
		||||
      this.$emit('update:theme', event.target.value)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
    change(event) {
 | 
			
		||||
      this.$emit("update:theme", event.target.value);
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,67 +1,92 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div>
 | 
			
		||||
    <p v-if="!isDefault">
 | 
			
		||||
      <label for="username">{{ $t('settings.username') }}</label>
 | 
			
		||||
      <input class="input input--block" type="text" v-model="user.username" id="username">
 | 
			
		||||
      <label for="username">{{ $t("settings.username") }}</label>
 | 
			
		||||
      <input
 | 
			
		||||
        class="input input--block"
 | 
			
		||||
        type="text"
 | 
			
		||||
        v-model="user.username"
 | 
			
		||||
        id="username"
 | 
			
		||||
      />
 | 
			
		||||
    </p>
 | 
			
		||||
 | 
			
		||||
    <p v-if="!isDefault">
 | 
			
		||||
      <label for="password">{{ $t('settings.password') }}</label>
 | 
			
		||||
      <input class="input input--block" type="password" :placeholder="passwordPlaceholder" v-model="user.password" id="password">
 | 
			
		||||
      <label for="password">{{ $t("settings.password") }}</label>
 | 
			
		||||
      <input
 | 
			
		||||
        class="input input--block"
 | 
			
		||||
        type="password"
 | 
			
		||||
        :placeholder="passwordPlaceholder"
 | 
			
		||||
        v-model="user.password"
 | 
			
		||||
        id="password"
 | 
			
		||||
      />
 | 
			
		||||
    </p>
 | 
			
		||||
 | 
			
		||||
    <p>
 | 
			
		||||
      <label for="scope">{{ $t('settings.scope') }}</label>
 | 
			
		||||
      <input class="input input--block" type="text" v-model="user.scope" id="scope">
 | 
			
		||||
      <label for="scope">{{ $t("settings.scope") }}</label>
 | 
			
		||||
      <input
 | 
			
		||||
        class="input input--block"
 | 
			
		||||
        type="text"
 | 
			
		||||
        v-model="user.scope"
 | 
			
		||||
        id="scope"
 | 
			
		||||
      />
 | 
			
		||||
    </p>
 | 
			
		||||
 | 
			
		||||
    <p>
 | 
			
		||||
      <label for="locale">{{ $t('settings.language') }}</label>
 | 
			
		||||
      <languages class="input input--block" id="locale" :locale.sync="user.locale"></languages>
 | 
			
		||||
      <label for="locale">{{ $t("settings.language") }}</label>
 | 
			
		||||
      <languages
 | 
			
		||||
        class="input input--block"
 | 
			
		||||
        id="locale"
 | 
			
		||||
        :locale.sync="user.locale"
 | 
			
		||||
      ></languages>
 | 
			
		||||
    </p>
 | 
			
		||||
 | 
			
		||||
    <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>
 | 
			
		||||
 | 
			
		||||
    <permissions :perm.sync="user.perm" />
 | 
			
		||||
    <commands v-if="isExecEnabled" :commands.sync="user.commands" />
 | 
			
		||||
 | 
			
		||||
    <div v-if="!isDefault">
 | 
			
		||||
      <h3>{{ $t('settings.rules') }}</h3>
 | 
			
		||||
      <p class="small">{{ $t('settings.rulesHelp') }}</p>
 | 
			
		||||
      <h3>{{ $t("settings.rules") }}</h3>
 | 
			
		||||
      <p class="small">{{ $t("settings.rulesHelp") }}</p>
 | 
			
		||||
      <rules :rules.sync="user.rules" />
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import Languages from './Languages'
 | 
			
		||||
import Rules from './Rules'
 | 
			
		||||
import Permissions from './Permissions'
 | 
			
		||||
import Commands from './Commands'
 | 
			
		||||
import { enableExec } from '@/utils/constants'
 | 
			
		||||
import Languages from "./Languages";
 | 
			
		||||
import Rules from "./Rules";
 | 
			
		||||
import Permissions from "./Permissions";
 | 
			
		||||
import Commands from "./Commands";
 | 
			
		||||
import { enableExec } from "@/utils/constants";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'user',
 | 
			
		||||
  name: "user",
 | 
			
		||||
  components: {
 | 
			
		||||
    Permissions,
 | 
			
		||||
    Languages,
 | 
			
		||||
    Rules,
 | 
			
		||||
    Commands
 | 
			
		||||
    Commands,
 | 
			
		||||
  },
 | 
			
		||||
  props: [ 'user', 'isNew', 'isDefault' ],
 | 
			
		||||
  props: ["user", "isNew", "isDefault"],
 | 
			
		||||
  computed: {
 | 
			
		||||
    passwordPlaceholder () {
 | 
			
		||||
      return this.isNew ? '' : this.$t('settings.avoidChanges')
 | 
			
		||||
    passwordPlaceholder() {
 | 
			
		||||
      return this.isNew ? "" : this.$t("settings.avoidChanges");
 | 
			
		||||
    },
 | 
			
		||||
    isExecEnabled: () => enableExec
 | 
			
		||||
    isExecEnabled: () => enableExec,
 | 
			
		||||
  },
 | 
			
		||||
  watch: {
 | 
			
		||||
    'user.perm.admin': function () {
 | 
			
		||||
      if (!this.user.perm.admin) return
 | 
			
		||||
      this.user.lockPassword = false
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
    "user.perm.admin": function () {
 | 
			
		||||
      if (!this.user.perm.admin) return;
 | 
			
		||||
      this.user.lockPassword = false;
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,116 +1,116 @@
 | 
			
		|||
import Vue from 'vue'
 | 
			
		||||
import VueI18n from 'vue-i18n'
 | 
			
		||||
import Vue from "vue";
 | 
			
		||||
import VueI18n from "vue-i18n";
 | 
			
		||||
 | 
			
		||||
import ar from './ar.json'
 | 
			
		||||
import de from './de.json'
 | 
			
		||||
import en from './en.json'
 | 
			
		||||
import es from './es.json'
 | 
			
		||||
import fr from './fr.json'
 | 
			
		||||
import is from './is.json'
 | 
			
		||||
import it from './it.json'
 | 
			
		||||
import ja from './ja.json'
 | 
			
		||||
import ko from './ko.json'
 | 
			
		||||
import nlBE from './nl-be.json'
 | 
			
		||||
import pl from './pl.json'
 | 
			
		||||
import pt from './pt.json'
 | 
			
		||||
import ptBR from './pt-br.json'
 | 
			
		||||
import ro from './ro.json'
 | 
			
		||||
import ru from './ru.json'
 | 
			
		||||
import svSE from './sv-se.json'
 | 
			
		||||
import zhCN from './zh-cn.json'
 | 
			
		||||
import zhTW from './zh-tw.json'
 | 
			
		||||
import ar from "./ar.json";
 | 
			
		||||
import de from "./de.json";
 | 
			
		||||
import en from "./en.json";
 | 
			
		||||
import es from "./es.json";
 | 
			
		||||
import fr from "./fr.json";
 | 
			
		||||
import is from "./is.json";
 | 
			
		||||
import it from "./it.json";
 | 
			
		||||
import ja from "./ja.json";
 | 
			
		||||
import ko from "./ko.json";
 | 
			
		||||
import nlBE from "./nl-be.json";
 | 
			
		||||
import pl from "./pl.json";
 | 
			
		||||
import pt from "./pt.json";
 | 
			
		||||
import ptBR from "./pt-br.json";
 | 
			
		||||
import ro from "./ro.json";
 | 
			
		||||
import ru from "./ru.json";
 | 
			
		||||
import svSE from "./sv-se.json";
 | 
			
		||||
import zhCN from "./zh-cn.json";
 | 
			
		||||
import zhTW from "./zh-tw.json";
 | 
			
		||||
 | 
			
		||||
Vue.use(VueI18n)
 | 
			
		||||
Vue.use(VueI18n);
 | 
			
		||||
 | 
			
		||||
export function detectLocale () {
 | 
			
		||||
  let locale = (navigator.language || navigator.browserLangugae).toLowerCase()
 | 
			
		||||
export function detectLocale() {
 | 
			
		||||
  let locale = (navigator.language || navigator.browserLangugae).toLowerCase();
 | 
			
		||||
  switch (true) {
 | 
			
		||||
    case /^ar.*/i.test(locale):
 | 
			
		||||
      locale = 'ar'
 | 
			
		||||
      break
 | 
			
		||||
      locale = "ar";
 | 
			
		||||
      break;
 | 
			
		||||
    case /^es.*/i.test(locale):
 | 
			
		||||
      locale = 'es'
 | 
			
		||||
      break
 | 
			
		||||
      locale = "es";
 | 
			
		||||
      break;
 | 
			
		||||
    case /^en.*/i.test(locale):
 | 
			
		||||
      locale = 'en'
 | 
			
		||||
      break
 | 
			
		||||
      locale = "en";
 | 
			
		||||
      break;
 | 
			
		||||
    case /^it.*/i.test(locale):
 | 
			
		||||
      locale = 'it'
 | 
			
		||||
      break
 | 
			
		||||
      locale = "it";
 | 
			
		||||
      break;
 | 
			
		||||
    case /^fr.*/i.test(locale):
 | 
			
		||||
      locale = 'fr'
 | 
			
		||||
      break
 | 
			
		||||
      locale = "fr";
 | 
			
		||||
      break;
 | 
			
		||||
    case /^pt.*/i.test(locale):
 | 
			
		||||
      locale = 'pt'
 | 
			
		||||
      break
 | 
			
		||||
      locale = "pt";
 | 
			
		||||
      break;
 | 
			
		||||
    case /^pt-BR.*/i.test(locale):
 | 
			
		||||
      locale = 'pt-br'
 | 
			
		||||
      break
 | 
			
		||||
      locale = "pt-br";
 | 
			
		||||
      break;
 | 
			
		||||
    case /^ja.*/i.test(locale):
 | 
			
		||||
      locale = 'ja'
 | 
			
		||||
      break
 | 
			
		||||
      locale = "ja";
 | 
			
		||||
      break;
 | 
			
		||||
    case /^zh-CN/i.test(locale):
 | 
			
		||||
      locale = 'zh-cn'
 | 
			
		||||
      break
 | 
			
		||||
      locale = "zh-cn";
 | 
			
		||||
      break;
 | 
			
		||||
    case /^zh-TW/i.test(locale):
 | 
			
		||||
      locale = 'zh-tw'
 | 
			
		||||
      break
 | 
			
		||||
      locale = "zh-tw";
 | 
			
		||||
      break;
 | 
			
		||||
    case /^zh.*/i.test(locale):
 | 
			
		||||
      locale = 'zh-cn'
 | 
			
		||||
      break
 | 
			
		||||
      locale = "zh-cn";
 | 
			
		||||
      break;
 | 
			
		||||
    case /^de.*/i.test(locale):
 | 
			
		||||
      locale = 'de'
 | 
			
		||||
      break
 | 
			
		||||
      locale = "de";
 | 
			
		||||
      break;
 | 
			
		||||
    case /^ru.*/i.test(locale):
 | 
			
		||||
      locale = 'ru'
 | 
			
		||||
      break
 | 
			
		||||
      locale = "ru";
 | 
			
		||||
      break;
 | 
			
		||||
    case /^pl.*/i.test(locale):
 | 
			
		||||
      locale = 'pl'
 | 
			
		||||
      break
 | 
			
		||||
      locale = "pl";
 | 
			
		||||
      break;
 | 
			
		||||
    case /^ko.*/i.test(locale):
 | 
			
		||||
      locale = 'ko'
 | 
			
		||||
      break
 | 
			
		||||
      locale = "ko";
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      locale = 'en'
 | 
			
		||||
      locale = "en";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return locale
 | 
			
		||||
  return locale;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const removeEmpty = (obj) =>
 | 
			
		||||
    Object.keys(obj)
 | 
			
		||||
        .filter((k) => obj[k] !== null && obj[k] !== undefined && obj[k] !== '') // Remove undef. and null and empty.string.
 | 
			
		||||
        .reduce(
 | 
			
		||||
            (newObj, k) =>
 | 
			
		||||
                typeof obj[k] === 'object'
 | 
			
		||||
                    ? Object.assign(newObj, { [k]: removeEmpty(obj[k]) }) // Recurse.
 | 
			
		||||
                    : Object.assign(newObj, { [k]: obj[k] }), // Copy value.
 | 
			
		||||
            {},
 | 
			
		||||
        );
 | 
			
		||||
  Object.keys(obj)
 | 
			
		||||
    .filter((k) => obj[k] !== null && obj[k] !== undefined && obj[k] !== "") // Remove undef. and null and empty.string.
 | 
			
		||||
    .reduce(
 | 
			
		||||
      (newObj, k) =>
 | 
			
		||||
        typeof obj[k] === "object"
 | 
			
		||||
          ? Object.assign(newObj, { [k]: removeEmpty(obj[k]) }) // Recurse.
 | 
			
		||||
          : Object.assign(newObj, { [k]: obj[k] }), // Copy value.
 | 
			
		||||
      {}
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
const i18n = new VueI18n({
 | 
			
		||||
  locale: detectLocale(),
 | 
			
		||||
  fallbackLocale: 'en',
 | 
			
		||||
  fallbackLocale: "en",
 | 
			
		||||
  messages: {
 | 
			
		||||
    'ar': removeEmpty(ar),
 | 
			
		||||
    'de': removeEmpty(de),
 | 
			
		||||
    'en': en,
 | 
			
		||||
    'es': removeEmpty(es),
 | 
			
		||||
    'fr': removeEmpty(fr),
 | 
			
		||||
    'is': removeEmpty(is),
 | 
			
		||||
    'it': removeEmpty(it),
 | 
			
		||||
    'ja': removeEmpty(ja),
 | 
			
		||||
    'ko': removeEmpty(ko),
 | 
			
		||||
    'nl-be': removeEmpty(nlBE),
 | 
			
		||||
    'pl': removeEmpty(pl),
 | 
			
		||||
    'pt-br': removeEmpty(ptBR),
 | 
			
		||||
    'pt': removeEmpty(pt),
 | 
			
		||||
    'ru': removeEmpty(ru),
 | 
			
		||||
    'ro': removeEmpty(ro),
 | 
			
		||||
    'sv-se': removeEmpty(svSE),
 | 
			
		||||
    'zh-cn': removeEmpty(zhCN),
 | 
			
		||||
    'zh-tw': removeEmpty(zhTW)
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
    ar: removeEmpty(ar),
 | 
			
		||||
    de: removeEmpty(de),
 | 
			
		||||
    en: en,
 | 
			
		||||
    es: removeEmpty(es),
 | 
			
		||||
    fr: removeEmpty(fr),
 | 
			
		||||
    is: removeEmpty(is),
 | 
			
		||||
    it: removeEmpty(it),
 | 
			
		||||
    ja: removeEmpty(ja),
 | 
			
		||||
    ko: removeEmpty(ko),
 | 
			
		||||
    "nl-be": removeEmpty(nlBE),
 | 
			
		||||
    pl: removeEmpty(pl),
 | 
			
		||||
    "pt-br": removeEmpty(ptBR),
 | 
			
		||||
    pt: removeEmpty(pt),
 | 
			
		||||
    ru: removeEmpty(ru),
 | 
			
		||||
    ro: removeEmpty(ro),
 | 
			
		||||
    "sv-se": removeEmpty(svSE),
 | 
			
		||||
    "zh-cn": removeEmpty(zhCN),
 | 
			
		||||
    "zh-tw": removeEmpty(zhTW),
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export default i18n
 | 
			
		||||
export default i18n;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,43 +1,43 @@
 | 
			
		|||
import { sync } from 'vuex-router-sync'
 | 
			
		||||
import store from '@/store'
 | 
			
		||||
import router from '@/router'
 | 
			
		||||
import i18n from '@/i18n'
 | 
			
		||||
import Vue from '@/utils/vue'
 | 
			
		||||
import { recaptcha, loginPage } from '@/utils/constants'
 | 
			
		||||
import { login, validateLogin } from '@/utils/auth'
 | 
			
		||||
import App from '@/App'
 | 
			
		||||
import { sync } from "vuex-router-sync";
 | 
			
		||||
import store from "@/store";
 | 
			
		||||
import router from "@/router";
 | 
			
		||||
import i18n from "@/i18n";
 | 
			
		||||
import Vue from "@/utils/vue";
 | 
			
		||||
import { recaptcha, loginPage } from "@/utils/constants";
 | 
			
		||||
import { login, validateLogin } from "@/utils/auth";
 | 
			
		||||
import App from "@/App";
 | 
			
		||||
 | 
			
		||||
sync(store, router)
 | 
			
		||||
sync(store, router);
 | 
			
		||||
 | 
			
		||||
async function start () {
 | 
			
		||||
async function start() {
 | 
			
		||||
  if (loginPage) {
 | 
			
		||||
    await validateLogin()
 | 
			
		||||
    await validateLogin();
 | 
			
		||||
  } else {
 | 
			
		||||
    await login('', '', '')
 | 
			
		||||
    await login("", "", "");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (recaptcha) {
 | 
			
		||||
    await new Promise (resolve => {
 | 
			
		||||
    await new Promise((resolve) => {
 | 
			
		||||
      const check = () => {
 | 
			
		||||
        if (typeof window.grecaptcha === 'undefined') {
 | 
			
		||||
          setTimeout(check, 100)
 | 
			
		||||
        if (typeof window.grecaptcha === "undefined") {
 | 
			
		||||
          setTimeout(check, 100);
 | 
			
		||||
        } else {
 | 
			
		||||
          resolve()
 | 
			
		||||
          resolve();
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      check()
 | 
			
		||||
    })
 | 
			
		||||
      check();
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  new Vue({
 | 
			
		||||
    el: '#app',
 | 
			
		||||
    el: "#app",
 | 
			
		||||
    store,
 | 
			
		||||
    router,
 | 
			
		||||
    i18n,
 | 
			
		||||
    template: '<App/>',
 | 
			
		||||
    components: { App }
 | 
			
		||||
  })
 | 
			
		||||
    template: "<App/>",
 | 
			
		||||
    components: { App },
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
start()
 | 
			
		||||
start();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,166 +1,166 @@
 | 
			
		|||
import Vue from 'vue'
 | 
			
		||||
import Router from 'vue-router'
 | 
			
		||||
import Login from '@/views/Login'
 | 
			
		||||
import Layout from '@/views/Layout'
 | 
			
		||||
import Files from '@/views/Files'
 | 
			
		||||
import Share from '@/views/Share'
 | 
			
		||||
import Users from '@/views/settings/Users'
 | 
			
		||||
import User from '@/views/settings/User'
 | 
			
		||||
import Settings from '@/views/Settings'
 | 
			
		||||
import GlobalSettings from '@/views/settings/Global'
 | 
			
		||||
import ProfileSettings from '@/views/settings/Profile'
 | 
			
		||||
import Shares from '@/views/settings/Shares'
 | 
			
		||||
import Errors from '@/views/Errors'
 | 
			
		||||
import store from '@/store'
 | 
			
		||||
import { baseURL } from '@/utils/constants'
 | 
			
		||||
import Vue from "vue";
 | 
			
		||||
import Router from "vue-router";
 | 
			
		||||
import Login from "@/views/Login";
 | 
			
		||||
import Layout from "@/views/Layout";
 | 
			
		||||
import Files from "@/views/Files";
 | 
			
		||||
import Share from "@/views/Share";
 | 
			
		||||
import Users from "@/views/settings/Users";
 | 
			
		||||
import User from "@/views/settings/User";
 | 
			
		||||
import Settings from "@/views/Settings";
 | 
			
		||||
import GlobalSettings from "@/views/settings/Global";
 | 
			
		||||
import ProfileSettings from "@/views/settings/Profile";
 | 
			
		||||
import Shares from "@/views/settings/Shares";
 | 
			
		||||
import Errors from "@/views/Errors";
 | 
			
		||||
import store from "@/store";
 | 
			
		||||
import { baseURL } from "@/utils/constants";
 | 
			
		||||
 | 
			
		||||
Vue.use(Router)
 | 
			
		||||
Vue.use(Router);
 | 
			
		||||
 | 
			
		||||
const router = new Router({
 | 
			
		||||
  base: baseURL,
 | 
			
		||||
  mode: 'history',
 | 
			
		||||
  mode: "history",
 | 
			
		||||
  routes: [
 | 
			
		||||
    {
 | 
			
		||||
      path: '/login',
 | 
			
		||||
      name: 'Login',
 | 
			
		||||
      path: "/login",
 | 
			
		||||
      name: "Login",
 | 
			
		||||
      component: Login,
 | 
			
		||||
      beforeEnter: (to, from, next) => {
 | 
			
		||||
        if (store.getters.isLogged) {
 | 
			
		||||
          return next({ path: '/files' })
 | 
			
		||||
          return next({ path: "/files" });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        document.title = 'Login'
 | 
			
		||||
        next()
 | 
			
		||||
      }
 | 
			
		||||
        document.title = "Login";
 | 
			
		||||
        next();
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      path: '/*',
 | 
			
		||||
      path: "/*",
 | 
			
		||||
      component: Layout,
 | 
			
		||||
      children: [
 | 
			
		||||
        {
 | 
			
		||||
          path: '/share/*',
 | 
			
		||||
          name: 'Share',
 | 
			
		||||
          component: Share
 | 
			
		||||
          path: "/share/*",
 | 
			
		||||
          name: "Share",
 | 
			
		||||
          component: Share,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          path: '/files/*',
 | 
			
		||||
          name: 'Files',
 | 
			
		||||
          path: "/files/*",
 | 
			
		||||
          name: "Files",
 | 
			
		||||
          component: Files,
 | 
			
		||||
          meta: {
 | 
			
		||||
            requiresAuth: true
 | 
			
		||||
          }
 | 
			
		||||
            requiresAuth: true,
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          path: '/settings',
 | 
			
		||||
          name: 'Settings',
 | 
			
		||||
          path: "/settings",
 | 
			
		||||
          name: "Settings",
 | 
			
		||||
          component: Settings,
 | 
			
		||||
          redirect: {
 | 
			
		||||
            path: '/settings/profile'
 | 
			
		||||
            path: "/settings/profile",
 | 
			
		||||
          },
 | 
			
		||||
          meta: {
 | 
			
		||||
            requiresAuth: true
 | 
			
		||||
            requiresAuth: true,
 | 
			
		||||
          },
 | 
			
		||||
          children: [
 | 
			
		||||
            {
 | 
			
		||||
              path: '/settings/profile',
 | 
			
		||||
              name: 'Profile Settings',
 | 
			
		||||
              component: ProfileSettings
 | 
			
		||||
              path: "/settings/profile",
 | 
			
		||||
              name: "Profile Settings",
 | 
			
		||||
              component: ProfileSettings,
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              path: '/settings/shares',
 | 
			
		||||
              name: 'Shares',
 | 
			
		||||
              component: Shares
 | 
			
		||||
              path: "/settings/shares",
 | 
			
		||||
              name: "Shares",
 | 
			
		||||
              component: Shares,
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              path: '/settings/global',
 | 
			
		||||
              name: 'Global Settings',
 | 
			
		||||
              path: "/settings/global",
 | 
			
		||||
              name: "Global Settings",
 | 
			
		||||
              component: GlobalSettings,
 | 
			
		||||
              meta: {
 | 
			
		||||
                requiresAdmin: true
 | 
			
		||||
              }
 | 
			
		||||
                requiresAdmin: true,
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              path: '/settings/users',
 | 
			
		||||
              name: 'Users',
 | 
			
		||||
              path: "/settings/users",
 | 
			
		||||
              name: "Users",
 | 
			
		||||
              component: Users,
 | 
			
		||||
              meta: {
 | 
			
		||||
                requiresAdmin: true
 | 
			
		||||
              }
 | 
			
		||||
                requiresAdmin: true,
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              path: '/settings/users/*',
 | 
			
		||||
              name: 'User',
 | 
			
		||||
              path: "/settings/users/*",
 | 
			
		||||
              name: "User",
 | 
			
		||||
              component: User,
 | 
			
		||||
              meta: {
 | 
			
		||||
                requiresAdmin: true
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          ]
 | 
			
		||||
                requiresAdmin: true,
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
          ],
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          path: '/403',
 | 
			
		||||
          name: 'Forbidden',
 | 
			
		||||
          path: "/403",
 | 
			
		||||
          name: "Forbidden",
 | 
			
		||||
          component: Errors,
 | 
			
		||||
          props: {
 | 
			
		||||
            errorCode: 403,
 | 
			
		||||
            showHeader: true
 | 
			
		||||
          }
 | 
			
		||||
            showHeader: true,
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          path: '/404',
 | 
			
		||||
          name: 'Not Found',
 | 
			
		||||
          path: "/404",
 | 
			
		||||
          name: "Not Found",
 | 
			
		||||
          component: Errors,
 | 
			
		||||
          props: {
 | 
			
		||||
            errorCode: 404,
 | 
			
		||||
            showHeader: true
 | 
			
		||||
          }
 | 
			
		||||
            showHeader: true,
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          path: '/500',
 | 
			
		||||
          name: 'Internal Server Error',
 | 
			
		||||
          path: "/500",
 | 
			
		||||
          name: "Internal Server Error",
 | 
			
		||||
          component: Errors,
 | 
			
		||||
          props: {
 | 
			
		||||
            errorCode: 500,
 | 
			
		||||
            showHeader: true
 | 
			
		||||
          }
 | 
			
		||||
            showHeader: true,
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          path: '/files',
 | 
			
		||||
          path: "/files",
 | 
			
		||||
          redirect: {
 | 
			
		||||
            path: '/files/'
 | 
			
		||||
          }
 | 
			
		||||
            path: "/files/",
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          path: '/*',
 | 
			
		||||
          redirect: to => `/files${to.path}`
 | 
			
		||||
        }
 | 
			
		||||
      ]
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
          path: "/*",
 | 
			
		||||
          redirect: (to) => `/files${to.path}`,
 | 
			
		||||
        },
 | 
			
		||||
      ],
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
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) {
 | 
			
		||||
      next({
 | 
			
		||||
        path: '/login',
 | 
			
		||||
        query: { redirect: to.fullPath }
 | 
			
		||||
      })
 | 
			
		||||
        path: "/login",
 | 
			
		||||
        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) {
 | 
			
		||||
        next({ path: '/403' })
 | 
			
		||||
        return
 | 
			
		||||
        next({ path: "/403" });
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  next()
 | 
			
		||||
})
 | 
			
		||||
  next();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export default router
 | 
			
		||||
export default router;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,16 +1,16 @@
 | 
			
		|||
const getters = {
 | 
			
		||||
  isLogged: state => state.user !== null,
 | 
			
		||||
  isFiles: state => !state.loading && state.route.name === 'Files',
 | 
			
		||||
  isLogged: (state) => state.user !== null,
 | 
			
		||||
  isFiles: (state) => !state.loading && state.route.name === "Files",
 | 
			
		||||
  isListing: (state, getters) => getters.isFiles && state.req.isDir,
 | 
			
		||||
  selectedCount: state => state.selected.length,
 | 
			
		||||
  progress : state => {
 | 
			
		||||
  selectedCount: (state) => state.selected.length,
 | 
			
		||||
  progress: (state) => {
 | 
			
		||||
    if (state.upload.progress.length == 0) {
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let sum = state.upload.progress.reduce((acc, val) => acc + val)
 | 
			
		||||
    return Math.ceil(sum / state.upload.size * 100);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
    let sum = state.upload.progress.reduce((acc, val) => acc + val);
 | 
			
		||||
    return Math.ceil((sum / state.upload.size) * 100);
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default getters
 | 
			
		||||
export default getters;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,20 +1,20 @@
 | 
			
		|||
import Vue from 'vue'
 | 
			
		||||
import Vuex from 'vuex'
 | 
			
		||||
import mutations from './mutations'
 | 
			
		||||
import getters from './getters'
 | 
			
		||||
import upload from './modules/upload'
 | 
			
		||||
import Vue from "vue";
 | 
			
		||||
import Vuex from "vuex";
 | 
			
		||||
import mutations from "./mutations";
 | 
			
		||||
import getters from "./getters";
 | 
			
		||||
import upload from "./modules/upload";
 | 
			
		||||
 | 
			
		||||
Vue.use(Vuex)
 | 
			
		||||
Vue.use(Vuex);
 | 
			
		||||
 | 
			
		||||
const state = {
 | 
			
		||||
  user: null,
 | 
			
		||||
  req: {},
 | 
			
		||||
  oldReq: {},
 | 
			
		||||
  clipboard: {
 | 
			
		||||
    key: '',
 | 
			
		||||
    items: []
 | 
			
		||||
    key: "",
 | 
			
		||||
    items: [],
 | 
			
		||||
  },
 | 
			
		||||
  jwt: '',
 | 
			
		||||
  jwt: "",
 | 
			
		||||
  progress: 0,
 | 
			
		||||
  loading: false,
 | 
			
		||||
  reload: false,
 | 
			
		||||
| 
						 | 
				
			
			@ -22,13 +22,13 @@ const state = {
 | 
			
		|||
  multiple: false,
 | 
			
		||||
  show: null,
 | 
			
		||||
  showShell: false,
 | 
			
		||||
  showConfirm: null
 | 
			
		||||
}
 | 
			
		||||
  showConfirm: null,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default new Vuex.Store({
 | 
			
		||||
  strict: true,
 | 
			
		||||
  state,
 | 
			
		||||
  getters,
 | 
			
		||||
  mutations,
 | 
			
		||||
  modules: { upload }
 | 
			
		||||
})
 | 
			
		||||
  modules: { upload },
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
import Vue from 'vue'
 | 
			
		||||
import { files as api } from '@/api'
 | 
			
		||||
import throttle from 'lodash.throttle'
 | 
			
		||||
import buttons from '@/utils/buttons'
 | 
			
		||||
import Vue from "vue";
 | 
			
		||||
import { files as api } from "@/api";
 | 
			
		||||
import throttle from "lodash.throttle";
 | 
			
		||||
import buttons from "@/utils/buttons";
 | 
			
		||||
 | 
			
		||||
const UPLOADS_LIMIT = 5;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -10,93 +10,100 @@ const state = {
 | 
			
		|||
  size: 0,
 | 
			
		||||
  progress: [],
 | 
			
		||||
  queue: [],
 | 
			
		||||
  uploads: {}
 | 
			
		||||
}
 | 
			
		||||
  uploads: {},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const mutations = {
 | 
			
		||||
  setProgress(state, { id, loaded }) {
 | 
			
		||||
    Vue.set(state.progress, id, loaded)
 | 
			
		||||
    Vue.set(state.progress, id, loaded);
 | 
			
		||||
  },
 | 
			
		||||
  reset: (state) => {
 | 
			
		||||
    state.id = 0
 | 
			
		||||
    state.size = 0
 | 
			
		||||
    state.progress = []
 | 
			
		||||
    state.id = 0;
 | 
			
		||||
    state.size = 0;
 | 
			
		||||
    state.progress = [];
 | 
			
		||||
  },
 | 
			
		||||
  addJob: (state, item) => {
 | 
			
		||||
    state.queue.push(item)
 | 
			
		||||
    state.size += item.file.size
 | 
			
		||||
    state.id++
 | 
			
		||||
    state.queue.push(item);
 | 
			
		||||
    state.size += item.file.size;
 | 
			
		||||
    state.id++;
 | 
			
		||||
  },
 | 
			
		||||
  moveJob(state) {
 | 
			
		||||
    const item = state.queue[0]
 | 
			
		||||
    state.queue.shift()
 | 
			
		||||
    Vue.set(state.uploads, item.id, item)
 | 
			
		||||
    const item = state.queue[0];
 | 
			
		||||
    state.queue.shift();
 | 
			
		||||
    Vue.set(state.uploads, item.id, item);
 | 
			
		||||
  },
 | 
			
		||||
  removeJob(state, id) {
 | 
			
		||||
    delete state.uploads[id]
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
    delete state.uploads[id];
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const beforeUnload = (event) => {
 | 
			
		||||
  event.preventDefault()
 | 
			
		||||
  event.returnValue = ''
 | 
			
		||||
}
 | 
			
		||||
  event.preventDefault();
 | 
			
		||||
  event.returnValue = "";
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const actions = {
 | 
			
		||||
  upload: (context, item) => {
 | 
			
		||||
    let uploadsCount = Object.keys(context.state.uploads).length;
 | 
			
		||||
 | 
			
		||||
    let isQueueEmpty = context.state.queue.length == 0
 | 
			
		||||
    let isUploadsEmpty = uploadsCount == 0
 | 
			
		||||
    let isQueueEmpty = context.state.queue.length == 0;
 | 
			
		||||
    let isUploadsEmpty = uploadsCount == 0;
 | 
			
		||||
 | 
			
		||||
    if (isQueueEmpty && isUploadsEmpty) {
 | 
			
		||||
      window.addEventListener('beforeunload', beforeUnload)
 | 
			
		||||
      buttons.loading('upload')
 | 
			
		||||
      window.addEventListener("beforeunload", beforeUnload);
 | 
			
		||||
      buttons.loading("upload");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    context.commit('addJob', item)
 | 
			
		||||
    context.dispatch('processUploads')
 | 
			
		||||
    context.commit("addJob", item);
 | 
			
		||||
    context.dispatch("processUploads");
 | 
			
		||||
  },
 | 
			
		||||
  finishUpload: (context, item) => {
 | 
			
		||||
    context.commit('setProgress', { id: item.id, loaded: item.file.size })
 | 
			
		||||
    context.commit('removeJob', item.id)
 | 
			
		||||
    context.dispatch('processUploads')
 | 
			
		||||
    context.commit("setProgress", { id: item.id, loaded: item.file.size });
 | 
			
		||||
    context.commit("removeJob", item.id);
 | 
			
		||||
    context.dispatch("processUploads");
 | 
			
		||||
  },
 | 
			
		||||
  processUploads: async (context) => {
 | 
			
		||||
    let uploadsCount = Object.keys(context.state.uploads).length;
 | 
			
		||||
 | 
			
		||||
    let isBellowLimit = uploadsCount < UPLOADS_LIMIT
 | 
			
		||||
    let isQueueEmpty = context.state.queue.length == 0
 | 
			
		||||
    let isUploadsEmpty = uploadsCount == 0
 | 
			
		||||
    let isBellowLimit = uploadsCount < UPLOADS_LIMIT;
 | 
			
		||||
    let isQueueEmpty = context.state.queue.length == 0;
 | 
			
		||||
    let isUploadsEmpty = uploadsCount == 0;
 | 
			
		||||
 | 
			
		||||
    let isFinished = isQueueEmpty && isUploadsEmpty
 | 
			
		||||
    let canProcess = isBellowLimit && !isQueueEmpty
 | 
			
		||||
    let isFinished = isQueueEmpty && isUploadsEmpty;
 | 
			
		||||
    let canProcess = isBellowLimit && !isQueueEmpty;
 | 
			
		||||
 | 
			
		||||
    if (isFinished) {
 | 
			
		||||
      window.removeEventListener('beforeunload', beforeUnload)
 | 
			
		||||
      buttons.success('upload')
 | 
			
		||||
      context.commit('reset')
 | 
			
		||||
      context.commit('setReload', true, { root: true })
 | 
			
		||||
      window.removeEventListener("beforeunload", beforeUnload);
 | 
			
		||||
      buttons.success("upload");
 | 
			
		||||
      context.commit("reset");
 | 
			
		||||
      context.commit("setReload", true, { root: true });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (canProcess) {
 | 
			
		||||
      const item = context.state.queue[0];
 | 
			
		||||
      context.commit('moveJob')
 | 
			
		||||
      context.commit("moveJob");
 | 
			
		||||
 | 
			
		||||
      if (item.file.isDir) {
 | 
			
		||||
        await api.post(item.path).catch(Vue.prototype.$showError)
 | 
			
		||||
        await api.post(item.path).catch(Vue.prototype.$showError);
 | 
			
		||||
      } else {
 | 
			
		||||
        let onUpload = throttle(
 | 
			
		||||
          (event) => context.commit('setProgress', { id: item.id, loaded: event.loaded }),
 | 
			
		||||
          100, { leading: true, trailing: false }
 | 
			
		||||
        )
 | 
			
		||||
          (event) =>
 | 
			
		||||
            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 moment from 'moment'
 | 
			
		||||
import * as i18n from "@/i18n";
 | 
			
		||||
import moment from "moment";
 | 
			
		||||
 | 
			
		||||
const mutations = {
 | 
			
		||||
  closeHovers: state => {
 | 
			
		||||
    state.show = null
 | 
			
		||||
    state.showConfirm = null
 | 
			
		||||
  closeHovers: (state) => {
 | 
			
		||||
    state.show = null;
 | 
			
		||||
    state.showConfirm = null;
 | 
			
		||||
  },
 | 
			
		||||
  toggleShell: (state) => {
 | 
			
		||||
    state.showShell = !state.showShell
 | 
			
		||||
    state.showShell = !state.showShell;
 | 
			
		||||
  },
 | 
			
		||||
  showHover: (state, value) => {
 | 
			
		||||
    if (typeof value !== 'object') {
 | 
			
		||||
      state.show = value
 | 
			
		||||
      return
 | 
			
		||||
    if (typeof value !== "object") {
 | 
			
		||||
      state.show = value;
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    state.show = value.prompt
 | 
			
		||||
    state.showConfirm = value.confirm
 | 
			
		||||
    state.show = value.prompt;
 | 
			
		||||
    state.showConfirm = value.confirm;
 | 
			
		||||
  },
 | 
			
		||||
  showError: (state) => {
 | 
			
		||||
    state.show = 'error'
 | 
			
		||||
    state.show = "error";
 | 
			
		||||
  },
 | 
			
		||||
  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) => {
 | 
			
		||||
    if (value === null) {
 | 
			
		||||
      state.user = null
 | 
			
		||||
      return
 | 
			
		||||
      state.user = null;
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let locale = value.locale
 | 
			
		||||
    let locale = value.locale;
 | 
			
		||||
 | 
			
		||||
    if (locale === '') {
 | 
			
		||||
      locale = i18n.detectLocale()
 | 
			
		||||
    if (locale === "") {
 | 
			
		||||
      locale = i18n.detectLocale();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    moment.locale(locale)
 | 
			
		||||
    i18n.default.locale = locale
 | 
			
		||||
    state.user = value
 | 
			
		||||
    moment.locale(locale);
 | 
			
		||||
    i18n.default.locale = locale;
 | 
			
		||||
    state.user = value;
 | 
			
		||||
  },
 | 
			
		||||
  setJWT: (state, value) => (state.jwt = value),
 | 
			
		||||
  multiple: (state, value) => (state.multiple = value),
 | 
			
		||||
  addSelected: (state, value) => (state.selected.push(value)),
 | 
			
		||||
  addSelected: (state, value) => state.selected.push(value),
 | 
			
		||||
  removeSelected: (state, value) => {
 | 
			
		||||
    let i = state.selected.indexOf(value)
 | 
			
		||||
    if (i === -1) return
 | 
			
		||||
    state.selected.splice(i, 1)
 | 
			
		||||
    let i = state.selected.indexOf(value);
 | 
			
		||||
    if (i === -1) return;
 | 
			
		||||
    state.selected.splice(i, 1);
 | 
			
		||||
  },
 | 
			
		||||
  resetSelected: (state) => {
 | 
			
		||||
    state.selected = []
 | 
			
		||||
    state.selected = [];
 | 
			
		||||
  },
 | 
			
		||||
  updateUser: (state, value) => {
 | 
			
		||||
    if (typeof value !== 'object') return
 | 
			
		||||
    if (typeof value !== "object") return;
 | 
			
		||||
 | 
			
		||||
    for (let field in value) {
 | 
			
		||||
      if (field === 'locale') {
 | 
			
		||||
        moment.locale(value[field])
 | 
			
		||||
        i18n.default.locale = value[field]
 | 
			
		||||
      if (field === "locale") {
 | 
			
		||||
        moment.locale(value[field]);
 | 
			
		||||
        i18n.default.locale = value[field];
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      state.user[field] = value[field]
 | 
			
		||||
      state.user[field] = value[field];
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  updateRequest: (state, value) => {
 | 
			
		||||
    state.oldReq = state.req
 | 
			
		||||
    state.req = value
 | 
			
		||||
    state.oldReq = state.req;
 | 
			
		||||
    state.req = value;
 | 
			
		||||
  },
 | 
			
		||||
  updateClipboard: (state, value) => {
 | 
			
		||||
    state.clipboard.key = value.key
 | 
			
		||||
    state.clipboard.items = value.items
 | 
			
		||||
    state.clipboard.path = value.path
 | 
			
		||||
    state.clipboard.key = value.key;
 | 
			
		||||
    state.clipboard.items = value.items;
 | 
			
		||||
    state.clipboard.path = value.path;
 | 
			
		||||
  },
 | 
			
		||||
  resetClipboard: (state) => {
 | 
			
		||||
    state.clipboard.key = ''
 | 
			
		||||
    state.clipboard.items = []
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
    state.clipboard.key = "";
 | 
			
		||||
    state.clipboard.items = [];
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default mutations
 | 
			
		||||
export default mutations;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,88 +1,88 @@
 | 
			
		|||
import store from '@/store'
 | 
			
		||||
import router from '@/router'
 | 
			
		||||
import { Base64 } from 'js-base64'
 | 
			
		||||
import { baseURL } from '@/utils/constants'
 | 
			
		||||
import store from "@/store";
 | 
			
		||||
import router from "@/router";
 | 
			
		||||
import { Base64 } from "js-base64";
 | 
			
		||||
import { baseURL } from "@/utils/constants";
 | 
			
		||||
 | 
			
		||||
export function parseToken (token) {
 | 
			
		||||
  const parts = token.split('.')
 | 
			
		||||
export function parseToken(token) {
 | 
			
		||||
  const parts = token.split(".");
 | 
			
		||||
 | 
			
		||||
  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)
 | 
			
		||||
  store.commit('setJWT', token)
 | 
			
		||||
  store.commit('setUser', data.user)
 | 
			
		||||
  localStorage.setItem("jwt", token);
 | 
			
		||||
  store.commit("setJWT", token);
 | 
			
		||||
  store.commit("setUser", data.user);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function validateLogin () {
 | 
			
		||||
export async function validateLogin() {
 | 
			
		||||
  try {
 | 
			
		||||
    if (localStorage.getItem('jwt')) {
 | 
			
		||||
      await renew(localStorage.getItem('jwt'))
 | 
			
		||||
    if (localStorage.getItem("jwt")) {
 | 
			
		||||
      await renew(localStorage.getItem("jwt"));
 | 
			
		||||
    }
 | 
			
		||||
  } catch (_) {
 | 
			
		||||
    console.warn('Invalid JWT token in storage') // eslint-disable-line
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function login (username, password, recaptcha) {
 | 
			
		||||
  const data = { username, password, recaptcha }
 | 
			
		||||
export async function login(username, password, recaptcha) {
 | 
			
		||||
  const data = { username, password, recaptcha };
 | 
			
		||||
 | 
			
		||||
  const res = await fetch(`${baseURL}/api/login`, {
 | 
			
		||||
    method: 'POST',
 | 
			
		||||
    method: "POST",
 | 
			
		||||
    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) {
 | 
			
		||||
    parseToken(body)
 | 
			
		||||
    parseToken(body);
 | 
			
		||||
  } 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`, {
 | 
			
		||||
    method: 'POST',
 | 
			
		||||
    method: "POST",
 | 
			
		||||
    headers: {
 | 
			
		||||
      'X-Auth': jwt,
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
      "X-Auth": jwt,
 | 
			
		||||
    },
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  const body = await res.text()
 | 
			
		||||
  const body = await res.text();
 | 
			
		||||
 | 
			
		||||
  if (res.status === 200) {
 | 
			
		||||
    parseToken(body)
 | 
			
		||||
    parseToken(body);
 | 
			
		||||
  } else {
 | 
			
		||||
    throw new Error(body)
 | 
			
		||||
    throw new Error(body);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function signup (username, password) {
 | 
			
		||||
  const data = { username, password }
 | 
			
		||||
export async function signup(username, password) {
 | 
			
		||||
  const data = { username, password };
 | 
			
		||||
 | 
			
		||||
  const res = await fetch(`${baseURL}/api/signup`, {
 | 
			
		||||
    method: 'POST',
 | 
			
		||||
    method: "POST",
 | 
			
		||||
    headers: {
 | 
			
		||||
      'Content-Type': 'application/json'
 | 
			
		||||
      "Content-Type": "application/json",
 | 
			
		||||
    },
 | 
			
		||||
    body: JSON.stringify(data)
 | 
			
		||||
  })
 | 
			
		||||
    body: JSON.stringify(data),
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  if (res.status !== 200) {
 | 
			
		||||
    throw new Error(res.status)
 | 
			
		||||
    throw new Error(res.status);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function logout () {
 | 
			
		||||
  store.commit('setJWT', '')
 | 
			
		||||
  store.commit('setUser', null)
 | 
			
		||||
  localStorage.setItem('jwt', null)
 | 
			
		||||
  router.push({path: '/login'})
 | 
			
		||||
export function logout() {
 | 
			
		||||
  store.commit("setJWT", "");
 | 
			
		||||
  store.commit("setUser", null);
 | 
			
		||||
  localStorage.setItem("jwt", null);
 | 
			
		||||
  router.push({ path: "/login" });
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,70 +1,70 @@
 | 
			
		|||
function loading (button) {
 | 
			
		||||
  let el = document.querySelector(`#${button}-button > i`)
 | 
			
		||||
function loading(button) {
 | 
			
		||||
  let el = document.querySelector(`#${button}-button > i`);
 | 
			
		||||
 | 
			
		||||
  if (el === undefined || el === null) {
 | 
			
		||||
    console.log('Error getting button ' + button) // eslint-disable-line
 | 
			
		||||
    return
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (el.innerHTML == 'autorenew' || el.innerHTML == 'done') {
 | 
			
		||||
    return
 | 
			
		||||
  if (el.innerHTML == "autorenew" || el.innerHTML == "done") {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  el.dataset.icon = el.innerHTML
 | 
			
		||||
  el.style.opacity = 0
 | 
			
		||||
  el.dataset.icon = el.innerHTML;
 | 
			
		||||
  el.style.opacity = 0;
 | 
			
		||||
 | 
			
		||||
  setTimeout(() => {
 | 
			
		||||
    el.classList.add('spin')
 | 
			
		||||
    el.innerHTML = 'autorenew'
 | 
			
		||||
    el.style.opacity = 1
 | 
			
		||||
  }, 100)
 | 
			
		||||
    el.classList.add("spin");
 | 
			
		||||
    el.innerHTML = "autorenew";
 | 
			
		||||
    el.style.opacity = 1;
 | 
			
		||||
  }, 100);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function done (button) {
 | 
			
		||||
  let el = document.querySelector(`#${button}-button > i`)
 | 
			
		||||
function done(button) {
 | 
			
		||||
  let el = document.querySelector(`#${button}-button > i`);
 | 
			
		||||
 | 
			
		||||
  if (el === undefined || el === null) {
 | 
			
		||||
    console.log('Error getting button ' + button) // eslint-disable-line
 | 
			
		||||
    return
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  el.style.opacity = 0
 | 
			
		||||
  el.style.opacity = 0;
 | 
			
		||||
 | 
			
		||||
  setTimeout(() => {
 | 
			
		||||
    el.classList.remove('spin')
 | 
			
		||||
    el.innerHTML = el.dataset.icon
 | 
			
		||||
    el.style.opacity = 1
 | 
			
		||||
  }, 100)
 | 
			
		||||
    el.classList.remove("spin");
 | 
			
		||||
    el.innerHTML = el.dataset.icon;
 | 
			
		||||
    el.style.opacity = 1;
 | 
			
		||||
  }, 100);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function success (button) {
 | 
			
		||||
  let el = document.querySelector(`#${button}-button > i`)
 | 
			
		||||
function success(button) {
 | 
			
		||||
  let el = document.querySelector(`#${button}-button > i`);
 | 
			
		||||
 | 
			
		||||
  if (el === undefined || el === null) {
 | 
			
		||||
    console.log('Error getting button ' + button) // eslint-disable-line
 | 
			
		||||
    return
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  el.style.opacity = 0
 | 
			
		||||
  el.style.opacity = 0;
 | 
			
		||||
 | 
			
		||||
  setTimeout(() => {
 | 
			
		||||
    el.classList.remove('spin')
 | 
			
		||||
    el.innerHTML = 'done'
 | 
			
		||||
    el.style.opacity = 1
 | 
			
		||||
    el.classList.remove("spin");
 | 
			
		||||
    el.innerHTML = "done";
 | 
			
		||||
    el.style.opacity = 1;
 | 
			
		||||
 | 
			
		||||
    setTimeout(() => {
 | 
			
		||||
      el.style.opacity = 0
 | 
			
		||||
      el.style.opacity = 0;
 | 
			
		||||
 | 
			
		||||
      setTimeout(() => {
 | 
			
		||||
        el.innerHTML = el.dataset.icon
 | 
			
		||||
        el.style.opacity = 1
 | 
			
		||||
      }, 100)
 | 
			
		||||
    }, 500)
 | 
			
		||||
  }, 100)
 | 
			
		||||
        el.innerHTML = el.dataset.icon;
 | 
			
		||||
        el.style.opacity = 1;
 | 
			
		||||
      }, 100);
 | 
			
		||||
    }, 500);
 | 
			
		||||
  }, 100);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  loading,
 | 
			
		||||
  done,
 | 
			
		||||
  success
 | 
			
		||||
}
 | 
			
		||||
  success,
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,19 +1,19 @@
 | 
			
		|||
const name = window.FileBrowser.Name || 'File Browser'
 | 
			
		||||
const disableExternal = window.FileBrowser.DisableExternal
 | 
			
		||||
const baseURL = window.FileBrowser.BaseURL
 | 
			
		||||
const staticURL = window.FileBrowser.StaticURL
 | 
			
		||||
const recaptcha = window.FileBrowser.ReCaptcha
 | 
			
		||||
const recaptchaKey = window.FileBrowser.ReCaptchaKey
 | 
			
		||||
const signup = window.FileBrowser.Signup
 | 
			
		||||
const version = window.FileBrowser.Version
 | 
			
		||||
const logoURL = `${staticURL}/img/logo.svg`
 | 
			
		||||
const noAuth = window.FileBrowser.NoAuth
 | 
			
		||||
const authMethod = window.FileBrowser.AuthMethod
 | 
			
		||||
const loginPage = window.FileBrowser.LoginPage
 | 
			
		||||
const theme = window.FileBrowser.Theme
 | 
			
		||||
const enableThumbs = window.FileBrowser.EnableThumbs
 | 
			
		||||
const resizePreview = window.FileBrowser.ResizePreview
 | 
			
		||||
const enableExec = window.FileBrowser.EnableExec
 | 
			
		||||
const name = window.FileBrowser.Name || "File Browser";
 | 
			
		||||
const disableExternal = window.FileBrowser.DisableExternal;
 | 
			
		||||
const baseURL = window.FileBrowser.BaseURL;
 | 
			
		||||
const staticURL = window.FileBrowser.StaticURL;
 | 
			
		||||
const recaptcha = window.FileBrowser.ReCaptcha;
 | 
			
		||||
const recaptchaKey = window.FileBrowser.ReCaptchaKey;
 | 
			
		||||
const signup = window.FileBrowser.Signup;
 | 
			
		||||
const version = window.FileBrowser.Version;
 | 
			
		||||
const logoURL = `${staticURL}/img/logo.svg`;
 | 
			
		||||
const noAuth = window.FileBrowser.NoAuth;
 | 
			
		||||
const authMethod = window.FileBrowser.AuthMethod;
 | 
			
		||||
const loginPage = window.FileBrowser.LoginPage;
 | 
			
		||||
const theme = window.FileBrowser.Theme;
 | 
			
		||||
const enableThumbs = window.FileBrowser.EnableThumbs;
 | 
			
		||||
const resizePreview = window.FileBrowser.ResizePreview;
 | 
			
		||||
const enableExec = window.FileBrowser.EnableExec;
 | 
			
		||||
 | 
			
		||||
export {
 | 
			
		||||
  name,
 | 
			
		||||
| 
						 | 
				
			
			@ -30,5 +30,5 @@ export {
 | 
			
		|||
  theme,
 | 
			
		||||
  enableThumbs,
 | 
			
		||||
  resizePreview,
 | 
			
		||||
  enableExec
 | 
			
		||||
}
 | 
			
		||||
  enableExec,
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,6 @@
 | 
			
		|||
export default function (name) {
 | 
			
		||||
  let re = new RegExp('(?:(?:^|.*;\\s*)' + name + '\\s*\\=\\s*([^;]*).*$)|^.*$')
 | 
			
		||||
  return document.cookie.replace(re, '$1')
 | 
			
		||||
  let re = new RegExp(
 | 
			
		||||
    "(?:(?:^|.*;\\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++) {
 | 
			
		||||
    rules[i] = rules[i].toLowerCase()
 | 
			
		||||
    rules[i] = rules[i].toLowerCase();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  let result = null
 | 
			
		||||
  let find = Array.prototype.find
 | 
			
		||||
  let result = null;
 | 
			
		||||
  let find = Array.prototype.find;
 | 
			
		||||
 | 
			
		||||
  find.call(document.styleSheets, styleSheet => {
 | 
			
		||||
    result = find.call(styleSheet.cssRules, cssRule => {
 | 
			
		||||
      let found = false
 | 
			
		||||
  find.call(document.styleSheets, (styleSheet) => {
 | 
			
		||||
    result = find.call(styleSheet.cssRules, (cssRule) => {
 | 
			
		||||
      let found = false;
 | 
			
		||||
 | 
			
		||||
      if (cssRule instanceof window.CSSStyleRule) {
 | 
			
		||||
        for (let i = 0; i < rules.length; i++) {
 | 
			
		||||
          if (cssRule.selectorText.toLowerCase() === rules[i]) {
 | 
			
		||||
            found = true
 | 
			
		||||
            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 url from '@/utils/url'
 | 
			
		||||
import store from "@/store";
 | 
			
		||||
import url from "@/utils/url";
 | 
			
		||||
 | 
			
		||||
export function checkConflict(files, items) {
 | 
			
		||||
  if (typeof items === 'undefined' || items === null) {
 | 
			
		||||
    items = []
 | 
			
		||||
  if (typeof items === "undefined" || items === null) {
 | 
			
		||||
    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++) {
 | 
			
		||||
    let file = files[i]
 | 
			
		||||
    let name = file.name
 | 
			
		||||
    let file = files[i];
 | 
			
		||||
    let name = file.name;
 | 
			
		||||
 | 
			
		||||
    if (folder_upload) {
 | 
			
		||||
      let dirs = file.fullPath.split("/")
 | 
			
		||||
      let dirs = file.fullPath.split("/");
 | 
			
		||||
      if (dirs.length > 1) {
 | 
			
		||||
        name = dirs[0]
 | 
			
		||||
        name = dirs[0];
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let res = items.findIndex(function hasConflict(element) {
 | 
			
		||||
      return (element.name === this)
 | 
			
		||||
    }, name)
 | 
			
		||||
      return element.name === this;
 | 
			
		||||
    }, name);
 | 
			
		||||
 | 
			
		||||
    if (res >= 0) {
 | 
			
		||||
      conflict = true
 | 
			
		||||
      break
 | 
			
		||||
      conflict = true;
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return conflict
 | 
			
		||||
  return conflict;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function scanFiles(dt) {
 | 
			
		||||
  return new Promise((resolve) => {
 | 
			
		||||
    let reading = 0
 | 
			
		||||
    const contents = []
 | 
			
		||||
    let reading = 0;
 | 
			
		||||
    const contents = [];
 | 
			
		||||
 | 
			
		||||
    if (dt.items !== undefined) {
 | 
			
		||||
      for (let item of dt.items) {
 | 
			
		||||
        if (item.kind === "file" && typeof item.webkitGetAsEntry === "function") {
 | 
			
		||||
          const entry = item.webkitGetAsEntry()
 | 
			
		||||
          readEntry(entry)
 | 
			
		||||
        if (
 | 
			
		||||
          item.kind === "file" &&
 | 
			
		||||
          typeof item.webkitGetAsEntry === "function"
 | 
			
		||||
        ) {
 | 
			
		||||
          const entry = item.webkitGetAsEntry();
 | 
			
		||||
          readEntry(entry);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      resolve(dt.files)
 | 
			
		||||
      resolve(dt.files);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function readEntry(entry, directory = "") {
 | 
			
		||||
      if (entry.isFile) {
 | 
			
		||||
        reading++
 | 
			
		||||
        entry.file(file => {
 | 
			
		||||
          reading--
 | 
			
		||||
        reading++;
 | 
			
		||||
        entry.file((file) => {
 | 
			
		||||
          reading--;
 | 
			
		||||
 | 
			
		||||
          file.fullPath = `${directory}${file.name}`
 | 
			
		||||
          contents.push(file)
 | 
			
		||||
          file.fullPath = `${directory}${file.name}`;
 | 
			
		||||
          contents.push(file);
 | 
			
		||||
 | 
			
		||||
          if (reading === 0) {
 | 
			
		||||
            resolve(contents)
 | 
			
		||||
            resolve(contents);
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
        });
 | 
			
		||||
      } else if (entry.isDirectory) {
 | 
			
		||||
        const dir = {
 | 
			
		||||
          isDir: true,
 | 
			
		||||
          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) {
 | 
			
		||||
      reading++
 | 
			
		||||
      reading++;
 | 
			
		||||
 | 
			
		||||
      reader.readEntries(function (entries) {
 | 
			
		||||
        reading--
 | 
			
		||||
        reading--;
 | 
			
		||||
        if (entries.length > 0) {
 | 
			
		||||
          for (const entry of entries) {
 | 
			
		||||
            readEntry(entry, `${directory}/`)
 | 
			
		||||
            readEntry(entry, `${directory}/`);
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          readReaderContent(reader, `${directory}/`)
 | 
			
		||||
          readReaderContent(reader, `${directory}/`);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (reading === 0) {
 | 
			
		||||
          resolve(contents)
 | 
			
		||||
          resolve(contents);
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function handleFiles(files, base, overwrite = false) {
 | 
			
		||||
  for (let i = 0; i < files.length; i++) {
 | 
			
		||||
    let id = store.state.upload.id
 | 
			
		||||
    let path = base
 | 
			
		||||
    let file = files[i]
 | 
			
		||||
    let id = store.state.upload.id;
 | 
			
		||||
    let path = base;
 | 
			
		||||
    let file = files[i];
 | 
			
		||||
 | 
			
		||||
    if (file.fullPath !== undefined) {
 | 
			
		||||
      path += url.encodePath(file.fullPath)
 | 
			
		||||
      path += url.encodePath(file.fullPath);
 | 
			
		||||
    } else {
 | 
			
		||||
      path += url.encodeRFC5987ValueChars(file.name)
 | 
			
		||||
      path += url.encodeRFC5987ValueChars(file.name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (file.isDir) {
 | 
			
		||||
      path += '/'
 | 
			
		||||
      path += "/";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const item = {
 | 
			
		||||
      id,
 | 
			
		||||
      path,
 | 
			
		||||
      file,
 | 
			
		||||
      overwrite
 | 
			
		||||
    }
 | 
			
		||||
      overwrite,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    store.dispatch('upload/upload', item);
 | 
			
		||||
    store.dispatch("upload/upload", item);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,31 +1,36 @@
 | 
			
		|||
function removeLastDir (url) {
 | 
			
		||||
  var arr = url.split('/')
 | 
			
		||||
  if (arr.pop() === '') {
 | 
			
		||||
    arr.pop()
 | 
			
		||||
function removeLastDir(url) {
 | 
			
		||||
  var arr = url.split("/");
 | 
			
		||||
  if (arr.pop() === "") {
 | 
			
		||||
    arr.pop();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return arr.join('/')
 | 
			
		||||
  return arr.join("/");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// this code borrow from mozilla
 | 
			
		||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent#Examples
 | 
			
		||||
function encodeRFC5987ValueChars(str) {
 | 
			
		||||
  return encodeURIComponent(str).
 | 
			
		||||
  return (
 | 
			
		||||
    encodeURIComponent(str)
 | 
			
		||||
      // Note that although RFC3986 reserves "!", RFC5987 does not,
 | 
			
		||||
      // so we do not need to escape it
 | 
			
		||||
      replace(/['()]/g, escape). // i.e., %27 %28 %29
 | 
			
		||||
      replace(/\*/g, '%2A').
 | 
			
		||||
          // The following are not required for percent-encoding per RFC5987, 
 | 
			
		||||
          // so we can allow for a little better readability over the wire: |`^
 | 
			
		||||
          replace(/%(?:7C|60|5E)/g, unescape);
 | 
			
		||||
      .replace(/['()]/g, escape) // i.e., %27 %28 %29
 | 
			
		||||
      .replace(/\*/g, "%2A")
 | 
			
		||||
      // The following are not required for percent-encoding per RFC5987,
 | 
			
		||||
      // so we can allow for a little better readability over the wire: |`^
 | 
			
		||||
      .replace(/%(?:7C|60|5E)/g, unescape)
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function encodePath(str) {
 | 
			
		||||
  return str.split('/').map(v => encodeURIComponent(v)).join('/')
 | 
			
		||||
  return str
 | 
			
		||||
    .split("/")
 | 
			
		||||
    .map((v) => encodeURIComponent(v))
 | 
			
		||||
    .join("/");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  encodeRFC5987ValueChars: encodeRFC5987ValueChars,
 | 
			
		||||
  removeLastDir: removeLastDir,
 | 
			
		||||
  encodePath: encodePath
 | 
			
		||||
}
 | 
			
		||||
  encodePath: encodePath,
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,58 +1,66 @@
 | 
			
		|||
import Vue from 'vue'
 | 
			
		||||
import Noty from 'noty'
 | 
			
		||||
import VueLazyload from 'vue-lazyload'
 | 
			
		||||
import i18n from '@/i18n'
 | 
			
		||||
import { disableExternal } from '@/utils/constants'
 | 
			
		||||
import Vue from "vue";
 | 
			
		||||
import Noty from "noty";
 | 
			
		||||
import VueLazyload from "vue-lazyload";
 | 
			
		||||
import i18n from "@/i18n";
 | 
			
		||||
import { disableExternal } from "@/utils/constants";
 | 
			
		||||
 | 
			
		||||
Vue.use(VueLazyload)
 | 
			
		||||
Vue.use(VueLazyload);
 | 
			
		||||
 | 
			
		||||
Vue.config.productionTip = true
 | 
			
		||||
Vue.config.productionTip = true;
 | 
			
		||||
 | 
			
		||||
const notyDefault = {
 | 
			
		||||
  type: 'info',
 | 
			
		||||
  layout: 'bottomRight',
 | 
			
		||||
  type: "info",
 | 
			
		||||
  layout: "bottomRight",
 | 
			
		||||
  timeout: 1000,
 | 
			
		||||
  progressBar: true
 | 
			
		||||
}
 | 
			
		||||
  progressBar: true,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Vue.prototype.$noty = (opts) => {
 | 
			
		||||
  new Noty(Object.assign({}, notyDefault, opts)).show()
 | 
			
		||||
}
 | 
			
		||||
  new Noty(Object.assign({}, notyDefault, opts)).show();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Vue.prototype.$showSuccess = (message) => {
 | 
			
		||||
  new Noty(Object.assign({}, notyDefault, {
 | 
			
		||||
    text: message,
 | 
			
		||||
    type: 'success'
 | 
			
		||||
  })).show()
 | 
			
		||||
}
 | 
			
		||||
  new Noty(
 | 
			
		||||
    Object.assign({}, notyDefault, {
 | 
			
		||||
      text: message,
 | 
			
		||||
      type: "success",
 | 
			
		||||
    })
 | 
			
		||||
  ).show();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Vue.prototype.$showError = (error, displayReport = true) => {
 | 
			
		||||
  let btns = [
 | 
			
		||||
    Noty.button(i18n.t('buttons.close'), '', function () {
 | 
			
		||||
      n.close()
 | 
			
		||||
    })
 | 
			
		||||
  ]
 | 
			
		||||
    Noty.button(i18n.t("buttons.close"), "", function () {
 | 
			
		||||
      n.close();
 | 
			
		||||
    }),
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  if (!disableExternal && displayReport) {
 | 
			
		||||
    btns.unshift(Noty.button(i18n.t('buttons.reportIssue'), '', function () {
 | 
			
		||||
      window.open('https://github.com/filebrowser/filebrowser/issues/new/choose')
 | 
			
		||||
    }))
 | 
			
		||||
    btns.unshift(
 | 
			
		||||
      Noty.button(i18n.t("buttons.reportIssue"), "", function () {
 | 
			
		||||
        window.open(
 | 
			
		||||
          "https://github.com/filebrowser/filebrowser/issues/new/choose"
 | 
			
		||||
        );
 | 
			
		||||
      })
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  let n = new Noty(Object.assign({}, notyDefault, {
 | 
			
		||||
    text: error.message || error,
 | 
			
		||||
    type: 'error',
 | 
			
		||||
    timeout: null,
 | 
			
		||||
    buttons: btns
 | 
			
		||||
  }))
 | 
			
		||||
  let n = new Noty(
 | 
			
		||||
    Object.assign({}, notyDefault, {
 | 
			
		||||
      text: error.message || error,
 | 
			
		||||
      type: "error",
 | 
			
		||||
      timeout: null,
 | 
			
		||||
      buttons: btns,
 | 
			
		||||
    })
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  n.show()
 | 
			
		||||
}
 | 
			
		||||
  n.show();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Vue.directive('focus', {
 | 
			
		||||
Vue.directive("focus", {
 | 
			
		||||
  inserted: function (el) {
 | 
			
		||||
    el.focus()
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
    el.focus();
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export default Vue
 | 
			
		||||
export default Vue;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,37 +10,34 @@
 | 
			
		|||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
 | 
			
		||||
import HeaderBar from '@/components/header/HeaderBar'
 | 
			
		||||
import HeaderBar from "@/components/header/HeaderBar";
 | 
			
		||||
 | 
			
		||||
const errors = {
 | 
			
		||||
  403: {
 | 
			
		||||
    icon: 'error',
 | 
			
		||||
    message: 'errors.forbidden'
 | 
			
		||||
    icon: "error",
 | 
			
		||||
    message: "errors.forbidden",
 | 
			
		||||
  },
 | 
			
		||||
  404: {
 | 
			
		||||
    icon: 'gps_off',
 | 
			
		||||
    message: 'errors.notFound'
 | 
			
		||||
    icon: "gps_off",
 | 
			
		||||
    message: "errors.notFound",
 | 
			
		||||
  },
 | 
			
		||||
  500: {
 | 
			
		||||
    icon: 'error_outline',
 | 
			
		||||
    message: 'errors.internal'
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
    icon: "error_outline",
 | 
			
		||||
    message: "errors.internal",
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'errors',
 | 
			
		||||
  name: "errors",
 | 
			
		||||
  components: {
 | 
			
		||||
    HeaderBar
 | 
			
		||||
    HeaderBar,
 | 
			
		||||
  },
 | 
			
		||||
  props: [
 | 
			
		||||
    'errorCode', 'showHeader'
 | 
			
		||||
  ],
 | 
			
		||||
  props: ["errorCode", "showHeader"],
 | 
			
		||||
  data: function () {
 | 
			
		||||
    return {
 | 
			
		||||
      icon: errors[this.errorCode].icon,
 | 
			
		||||
      message: this.$t(errors[this.errorCode].message)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
      message: this.$t(errors[this.errorCode].message),
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,137 +8,137 @@
 | 
			
		|||
    <component v-else-if="currentView" :is="currentView"></component>
 | 
			
		||||
    <div v-else>
 | 
			
		||||
      <h2 class="message">
 | 
			
		||||
        <span>{{ $t('files.loading') }}</span>
 | 
			
		||||
        <span>{{ $t("files.loading") }}</span>
 | 
			
		||||
      </h2>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { files as api } from '@/api'
 | 
			
		||||
import { mapState, mapMutations } from 'vuex'
 | 
			
		||||
import { files as api } from "@/api";
 | 
			
		||||
import { mapState, mapMutations } from "vuex";
 | 
			
		||||
 | 
			
		||||
import HeaderBar from '@/components/header/HeaderBar'
 | 
			
		||||
import Breadcrumbs from '@/components/Breadcrumbs'
 | 
			
		||||
import Errors from '@/views/Errors'
 | 
			
		||||
import Preview from '@/views/files/Preview'
 | 
			
		||||
import Listing from '@/views/files/Listing'
 | 
			
		||||
import HeaderBar from "@/components/header/HeaderBar";
 | 
			
		||||
import Breadcrumbs from "@/components/Breadcrumbs";
 | 
			
		||||
import Errors from "@/views/Errors";
 | 
			
		||||
import Preview from "@/views/files/Preview";
 | 
			
		||||
import Listing from "@/views/files/Listing";
 | 
			
		||||
 | 
			
		||||
function clean (path) {
 | 
			
		||||
  return path.endsWith('/') ? path.slice(0, -1) : path
 | 
			
		||||
function clean(path) {
 | 
			
		||||
  return path.endsWith("/") ? path.slice(0, -1) : path;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'files',
 | 
			
		||||
  name: "files",
 | 
			
		||||
  components: {
 | 
			
		||||
    HeaderBar,
 | 
			
		||||
    Breadcrumbs,
 | 
			
		||||
    Errors,
 | 
			
		||||
    Preview,
 | 
			
		||||
    Listing,
 | 
			
		||||
    Editor: () => import('@/views/files/Editor'),
 | 
			
		||||
    Editor: () => import("@/views/files/Editor"),
 | 
			
		||||
  },
 | 
			
		||||
  data: function () {
 | 
			
		||||
    return {
 | 
			
		||||
      error: null,
 | 
			
		||||
      width: window.innerWidth
 | 
			
		||||
    }
 | 
			
		||||
      width: window.innerWidth,
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapState([
 | 
			
		||||
      'req',
 | 
			
		||||
      'reload',
 | 
			
		||||
      'loading',
 | 
			
		||||
      'show'
 | 
			
		||||
    ]),
 | 
			
		||||
    currentView () {
 | 
			
		||||
    ...mapState(["req", "reload", "loading", "show"]),
 | 
			
		||||
    currentView() {
 | 
			
		||||
      if (this.req.type == undefined) {
 | 
			
		||||
        return null
 | 
			
		||||
        return null;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (this.req.isDir) {
 | 
			
		||||
        return 'listing'
 | 
			
		||||
      } else if(this.req.type === 'text' || this.req.type === 'textImmutable') {
 | 
			
		||||
        return 'editor'
 | 
			
		||||
        return "listing";
 | 
			
		||||
      } else if (
 | 
			
		||||
        this.req.type === "text" ||
 | 
			
		||||
        this.req.type === "textImmutable"
 | 
			
		||||
      ) {
 | 
			
		||||
        return "editor";
 | 
			
		||||
      } else {
 | 
			
		||||
        return 'preview'
 | 
			
		||||
        return "preview";
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    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 () {
 | 
			
		||||
    this.fetchData()
 | 
			
		||||
  created() {
 | 
			
		||||
    this.fetchData();
 | 
			
		||||
  },
 | 
			
		||||
  watch: {
 | 
			
		||||
    '$route': 'fetchData',
 | 
			
		||||
    'reload': function (value) {
 | 
			
		||||
       if (value === true) {
 | 
			
		||||
        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)
 | 
			
		||||
    $route: "fetchData",
 | 
			
		||||
    reload: function (value) {
 | 
			
		||||
      if (value === true) {
 | 
			
		||||
        this.fetchData();
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    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) {
 | 
			
		||||
        // Esc!
 | 
			
		||||
        if (event.keyCode === 27) {
 | 
			
		||||
          this.$store.commit('closeHovers')
 | 
			
		||||
          this.$store.commit("closeHovers");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // F1!
 | 
			
		||||
      if (event.keyCode === 112) {
 | 
			
		||||
        event.preventDefault()
 | 
			
		||||
        this.$store.commit('showHover', 'help')
 | 
			
		||||
        event.preventDefault();
 | 
			
		||||
        this.$store.commit("showHover", "help");
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,30 +13,31 @@
 | 
			
		|||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { mapState, mapGetters } from 'vuex'
 | 
			
		||||
import Sidebar from '@/components/Sidebar'
 | 
			
		||||
import Prompts from '@/components/prompts/Prompts'
 | 
			
		||||
import Shell from '@/components/Shell'
 | 
			
		||||
import { enableExec } from '@/utils/constants'
 | 
			
		||||
import { mapState, mapGetters } from "vuex";
 | 
			
		||||
import Sidebar from "@/components/Sidebar";
 | 
			
		||||
import Prompts from "@/components/prompts/Prompts";
 | 
			
		||||
import Shell from "@/components/Shell";
 | 
			
		||||
import { enableExec } from "@/utils/constants";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'layout',
 | 
			
		||||
  name: "layout",
 | 
			
		||||
  components: {
 | 
			
		||||
    Sidebar,
 | 
			
		||||
    Prompts,
 | 
			
		||||
    Shell
 | 
			
		||||
    Shell,
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapGetters([ 'isLogged', 'progress' ]),
 | 
			
		||||
    ...mapState([ 'user' ]),
 | 
			
		||||
    isExecEnabled: () => enableExec
 | 
			
		||||
    ...mapGetters(["isLogged", "progress"]),
 | 
			
		||||
    ...mapState(["user"]),
 | 
			
		||||
    isExecEnabled: () => enableExec,
 | 
			
		||||
  },
 | 
			
		||||
  watch: {
 | 
			
		||||
    '$route': function () {
 | 
			
		||||
      this.$store.commit('resetSelected')
 | 
			
		||||
      this.$store.commit('multiple', false)
 | 
			
		||||
      if (this.$store.state.show !== 'success') this.$store.commit('closeHovers')
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
    $route: function () {
 | 
			
		||||
      this.$store.commit("resetSelected");
 | 
			
		||||
      this.$store.commit("multiple", false);
 | 
			
		||||
      if (this.$store.state.show !== "success")
 | 
			
		||||
        this.$store.commit("closeHovers");
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,97 +1,127 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div id="login" :class="{ recaptcha: recaptcha }">
 | 
			
		||||
    <form @submit="submit">
 | 
			
		||||
      <img :src="logoURL" alt="File Browser">
 | 
			
		||||
      <img :src="logoURL" alt="File Browser" />
 | 
			
		||||
      <h1>{{ name }}</h1>
 | 
			
		||||
      <div v-if="error !== ''" class="wrong">{{ error }}</div>
 | 
			
		||||
 | 
			
		||||
      <input class="input input--block" 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')" />
 | 
			
		||||
      <input
 | 
			
		||||
        class="input input--block"
 | 
			
		||||
        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>
 | 
			
		||||
      <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>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import * as auth from '@/utils/auth'
 | 
			
		||||
import { name, logoURL, recaptcha, recaptchaKey, signup } from '@/utils/constants'
 | 
			
		||||
import * as auth from "@/utils/auth";
 | 
			
		||||
import {
 | 
			
		||||
  name,
 | 
			
		||||
  logoURL,
 | 
			
		||||
  recaptcha,
 | 
			
		||||
  recaptchaKey,
 | 
			
		||||
  signup,
 | 
			
		||||
} from "@/utils/constants";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'login',
 | 
			
		||||
  name: "login",
 | 
			
		||||
  computed: {
 | 
			
		||||
    signup: () => signup,
 | 
			
		||||
    name: () => name,
 | 
			
		||||
    logoURL: () => logoURL
 | 
			
		||||
    logoURL: () => logoURL,
 | 
			
		||||
  },
 | 
			
		||||
  data: function () {
 | 
			
		||||
    return {
 | 
			
		||||
      createMode: false,
 | 
			
		||||
      error: '',
 | 
			
		||||
      username: '',
 | 
			
		||||
      password: '',
 | 
			
		||||
      error: "",
 | 
			
		||||
      username: "",
 | 
			
		||||
      password: "",
 | 
			
		||||
      recaptcha: recaptcha,
 | 
			
		||||
      passwordConfirm: ''
 | 
			
		||||
    }
 | 
			
		||||
      passwordConfirm: "",
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  mounted () {
 | 
			
		||||
    if (!recaptcha) return
 | 
			
		||||
  mounted() {
 | 
			
		||||
    if (!recaptcha) return;
 | 
			
		||||
 | 
			
		||||
    window.grecaptcha.ready(function () {
 | 
			
		||||
      window.grecaptcha.render('recaptcha', {
 | 
			
		||||
        sitekey: recaptchaKey
 | 
			
		||||
      })
 | 
			
		||||
    })
 | 
			
		||||
      window.grecaptcha.render("recaptcha", {
 | 
			
		||||
        sitekey: recaptchaKey,
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    toggleMode () {
 | 
			
		||||
      this.createMode = !this.createMode
 | 
			
		||||
    toggleMode() {
 | 
			
		||||
      this.createMode = !this.createMode;
 | 
			
		||||
    },
 | 
			
		||||
    async submit (event) {
 | 
			
		||||
      event.preventDefault()
 | 
			
		||||
      event.stopPropagation()
 | 
			
		||||
    async submit(event) {
 | 
			
		||||
      event.preventDefault();
 | 
			
		||||
      event.stopPropagation();
 | 
			
		||||
 | 
			
		||||
      let redirect = this.$route.query.redirect
 | 
			
		||||
      if (redirect === '' || redirect === undefined || redirect === null) {
 | 
			
		||||
        redirect = '/files/'
 | 
			
		||||
      let redirect = this.$route.query.redirect;
 | 
			
		||||
      if (redirect === "" || redirect === undefined || redirect === null) {
 | 
			
		||||
        redirect = "/files/";
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      let captcha = ''
 | 
			
		||||
      let captcha = "";
 | 
			
		||||
      if (recaptcha) {
 | 
			
		||||
        captcha = window.grecaptcha.getResponse()
 | 
			
		||||
        captcha = window.grecaptcha.getResponse();
 | 
			
		||||
 | 
			
		||||
        if (captcha === '') {
 | 
			
		||||
          this.error = this.$t('login.wrongCredentials')
 | 
			
		||||
          return
 | 
			
		||||
        if (captcha === "") {
 | 
			
		||||
          this.error = this.$t("login.wrongCredentials");
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (this.createMode) {
 | 
			
		||||
        if (this.password !== this.passwordConfirm) {
 | 
			
		||||
          this.error = this.$t('login.passwordsDontMatch')
 | 
			
		||||
          return
 | 
			
		||||
          this.error = this.$t("login.passwordsDontMatch");
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      try {
 | 
			
		||||
        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)
 | 
			
		||||
        this.$router.push({ path: redirect })
 | 
			
		||||
        await auth.login(this.username, this.password, captcha);
 | 
			
		||||
        this.$router.push({ path: redirect });
 | 
			
		||||
      } catch (e) {
 | 
			
		||||
        if (e.message == 409) {
 | 
			
		||||
          this.error = this.$t('login.usernameTaken')
 | 
			
		||||
          this.error = this.$t("login.usernameTaken");
 | 
			
		||||
        } else {
 | 
			
		||||
          this.error = this.$t('login.wrongCredentials')
 | 
			
		||||
          this.error = this.$t("login.wrongCredentials");
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,10 +5,35 @@
 | 
			
		|||
    <div id="nav">
 | 
			
		||||
      <div class="wrapper">
 | 
			
		||||
        <ul>
 | 
			
		||||
          <router-link to="/settings/profile"><li :class="{ active: $route.path === '/settings/profile' }">{{ $t('settings.profileSettings') }}</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>
 | 
			
		||||
          <router-link to="/settings/profile"
 | 
			
		||||
            ><li :class="{ active: $route.path === '/settings/profile' }">
 | 
			
		||||
              {{ $t("settings.profileSettings") }}
 | 
			
		||||
            </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>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -18,17 +43,17 @@
 | 
			
		|||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { mapState } from 'vuex'
 | 
			
		||||
import { mapState } from "vuex";
 | 
			
		||||
 | 
			
		||||
import HeaderBar from '@/components/header/HeaderBar'
 | 
			
		||||
import HeaderBar from "@/components/header/HeaderBar";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'settings',
 | 
			
		||||
  name: "settings",
 | 
			
		||||
  components: {
 | 
			
		||||
    HeaderBar
 | 
			
		||||
    HeaderBar,
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapState([ 'user' ])
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
    ...mapState(["user"]),
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,8 +3,18 @@
 | 
			
		|||
    <header-bar showMenu showLogo>
 | 
			
		||||
      <title />
 | 
			
		||||
 | 
			
		||||
      <action v-if="selectedCount" icon="file_download" :label="$t('buttons.download')" @action="download" :counter="selectedCount" />
 | 
			
		||||
      <action icon="check_circle" :label="$t('buttons.selectMultiple')" @action="toggleMultipleSelection" />
 | 
			
		||||
      <action
 | 
			
		||||
        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>
 | 
			
		||||
 | 
			
		||||
    <breadcrumbs :base="'/share/' + hash" />
 | 
			
		||||
| 
						 | 
				
			
			@ -12,34 +22,44 @@
 | 
			
		|||
    <div v-if="!loading">
 | 
			
		||||
      <div class="share">
 | 
			
		||||
        <div class="share__box share__box__info">
 | 
			
		||||
            <div class="share__box__header">
 | 
			
		||||
              {{ req.isDir ? $t('download.downloadFolder') : $t('download.downloadFile') }}
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="share__box__element share__box__center share__box__icon">
 | 
			
		||||
              <i class="material-icons">{{ icon }}</i>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="share__box__element">
 | 
			
		||||
              <strong>{{ $t('prompts.displayName') }}</strong> {{ req.name }}
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="share__box__element">
 | 
			
		||||
              <strong>{{ $t('prompts.lastModified') }}:</strong> {{ humanTime }}
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="share__box__element">
 | 
			
		||||
              <strong>{{ $t('prompts.size') }}:</strong> {{ humanSize }}
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="share__box__element share__box__center">
 | 
			
		||||
              <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 class="share__box__header">
 | 
			
		||||
            {{
 | 
			
		||||
              req.isDir
 | 
			
		||||
                ? $t("download.downloadFolder")
 | 
			
		||||
                : $t("download.downloadFile")
 | 
			
		||||
            }}
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="share__box__element share__box__center share__box__icon">
 | 
			
		||||
            <i class="material-icons">{{ icon }}</i>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="share__box__element">
 | 
			
		||||
            <strong>{{ $t("prompts.displayName") }}</strong> {{ req.name }}
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="share__box__element">
 | 
			
		||||
            <strong>{{ $t("prompts.lastModified") }}:</strong> {{ humanTime }}
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="share__box__element">
 | 
			
		||||
            <strong>{{ $t("prompts.size") }}:</strong> {{ humanSize }}
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="share__box__element share__box__center">
 | 
			
		||||
            <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 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">
 | 
			
		||||
            {{ $t('files.files') }}
 | 
			
		||||
            {{ $t("files.files") }}
 | 
			
		||||
          </div>
 | 
			
		||||
          <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)"
 | 
			
		||||
              v-bind:index="item.index"
 | 
			
		||||
              v-bind:name="item.name"
 | 
			
		||||
| 
						 | 
				
			
			@ -48,26 +68,40 @@
 | 
			
		|||
              v-bind:modified="item.modified"
 | 
			
		||||
              v-bind:type="item.type"
 | 
			
		||||
              v-bind:size="item.size"
 | 
			
		||||
              readOnly>
 | 
			
		||||
              readOnly
 | 
			
		||||
            >
 | 
			
		||||
            </item>
 | 
			
		||||
            <div v-if="req.items.length > showLimit" class="item">
 | 
			
		||||
              <div>
 | 
			
		||||
                <p class="name"> + {{ req.items.length - showLimit }} </p>
 | 
			
		||||
                <p class="name">+ {{ req.items.length - showLimit }}</p>
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <div :class="{ active: $store.state.multiple }" 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">
 | 
			
		||||
            <div
 | 
			
		||||
              :class="{ active: $store.state.multiple }"
 | 
			
		||||
              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>
 | 
			
		||||
              </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">
 | 
			
		||||
            <i class="material-icons">sentiment_dissatisfied</i>
 | 
			
		||||
            <span>{{ $t('files.lonely') }}</span>
 | 
			
		||||
            <span>{{ $t("files.lonely") }}</span>
 | 
			
		||||
          </h2>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -75,19 +109,31 @@
 | 
			
		|||
    <div v-if="error">
 | 
			
		||||
      <div v-if="error.message === '401'">
 | 
			
		||||
        <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">
 | 
			
		||||
            <h2>{{ $t('login.password') }}</h2>
 | 
			
		||||
            <h2>{{ $t("login.password") }}</h2>
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          <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 class="card-action">
 | 
			
		||||
            <button class="button button--flat"
 | 
			
		||||
            <button
 | 
			
		||||
              class="button button--flat"
 | 
			
		||||
              @click="fetchData"
 | 
			
		||||
              :aria-label="$t('buttons.submit')"
 | 
			
		||||
              :title="$t('buttons.submit')">{{ $t('buttons.submit') }}</button>
 | 
			
		||||
              :title="$t('buttons.submit')"
 | 
			
		||||
            >
 | 
			
		||||
              {{ $t("buttons.submit") }}
 | 
			
		||||
            </button>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -97,156 +143,163 @@
 | 
			
		|||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import {mapState, mapMutations, mapGetters} from 'vuex';
 | 
			
		||||
import { pub as api } from '@/api'
 | 
			
		||||
import { baseURL } from '@/utils/constants'
 | 
			
		||||
import filesize from 'filesize'
 | 
			
		||||
import moment from 'moment'
 | 
			
		||||
import { mapState, mapMutations, mapGetters } from "vuex";
 | 
			
		||||
import { pub as api } from "@/api";
 | 
			
		||||
import { baseURL } from "@/utils/constants";
 | 
			
		||||
import filesize from "filesize";
 | 
			
		||||
import moment from "moment";
 | 
			
		||||
 | 
			
		||||
import HeaderBar from '@/components/header/HeaderBar'
 | 
			
		||||
import Action from '@/components/header/Action'
 | 
			
		||||
import Breadcrumbs from '@/components/Breadcrumbs'
 | 
			
		||||
import Errors from '@/views/Errors'
 | 
			
		||||
import QrcodeVue from 'qrcode.vue'
 | 
			
		||||
import Item from "@/components/files/ListingItem"
 | 
			
		||||
import HeaderBar from "@/components/header/HeaderBar";
 | 
			
		||||
import Action from "@/components/header/Action";
 | 
			
		||||
import Breadcrumbs from "@/components/Breadcrumbs";
 | 
			
		||||
import Errors from "@/views/Errors";
 | 
			
		||||
import QrcodeVue from "qrcode.vue";
 | 
			
		||||
import Item from "@/components/files/ListingItem";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'share',
 | 
			
		||||
  name: "share",
 | 
			
		||||
  components: {
 | 
			
		||||
    HeaderBar,
 | 
			
		||||
    Action,
 | 
			
		||||
    Breadcrumbs,
 | 
			
		||||
    Item,
 | 
			
		||||
    QrcodeVue,
 | 
			
		||||
    Errors
 | 
			
		||||
    Errors,
 | 
			
		||||
  },
 | 
			
		||||
  data: () => ({
 | 
			
		||||
    error: null,
 | 
			
		||||
    showLimit: 500,
 | 
			
		||||
    password: '',
 | 
			
		||||
    password: "",
 | 
			
		||||
    attemptedPasswordLogin: false,
 | 
			
		||||
    hash: null,
 | 
			
		||||
    token: null
 | 
			
		||||
    token: null,
 | 
			
		||||
  }),
 | 
			
		||||
  watch: {
 | 
			
		||||
    '$route': 'fetchData'
 | 
			
		||||
    $route: "fetchData",
 | 
			
		||||
  },
 | 
			
		||||
  created: async function () {
 | 
			
		||||
    const hash = this.$route.params.pathMatch.split('/')[0]
 | 
			
		||||
    this.hash = hash
 | 
			
		||||
    await this.fetchData()
 | 
			
		||||
    const hash = this.$route.params.pathMatch.split("/")[0];
 | 
			
		||||
    this.hash = hash;
 | 
			
		||||
    await this.fetchData();
 | 
			
		||||
  },
 | 
			
		||||
  mounted () {
 | 
			
		||||
    window.addEventListener('keydown', this.keyEvent)
 | 
			
		||||
  mounted() {
 | 
			
		||||
    window.addEventListener("keydown", this.keyEvent);
 | 
			
		||||
  },
 | 
			
		||||
  beforeDestroy () {
 | 
			
		||||
    window.removeEventListener('keydown', this.keyEvent)
 | 
			
		||||
  beforeDestroy() {
 | 
			
		||||
    window.removeEventListener("keydown", this.keyEvent);
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapState(['req', 'loading', 'multiple', 'selected']),
 | 
			
		||||
    ...mapGetters(['selectedCount', 'selectedCount']),
 | 
			
		||||
    ...mapState(["req", "loading", "multiple", "selected"]),
 | 
			
		||||
    ...mapGetters(["selectedCount", "selectedCount"]),
 | 
			
		||||
    icon: function () {
 | 
			
		||||
      if (this.req.isDir) return 'folder'
 | 
			
		||||
      if (this.req.type === 'image') return 'insert_photo'
 | 
			
		||||
      if (this.req.type === 'audio') return 'volume_up'
 | 
			
		||||
      if (this.req.type === 'video') return 'movie'
 | 
			
		||||
      return 'insert_drive_file'
 | 
			
		||||
      if (this.req.isDir) return "folder";
 | 
			
		||||
      if (this.req.type === "image") return "insert_photo";
 | 
			
		||||
      if (this.req.type === "audio") return "volume_up";
 | 
			
		||||
      if (this.req.type === "video") return "movie";
 | 
			
		||||
      return "insert_drive_file";
 | 
			
		||||
    },
 | 
			
		||||
    link: function () {
 | 
			
		||||
      let queryArg = '';
 | 
			
		||||
      if (this.token !== ''){
 | 
			
		||||
        queryArg = `?token=${this.token}`
 | 
			
		||||
      let queryArg = "";
 | 
			
		||||
      if (this.token !== "") {
 | 
			
		||||
        queryArg = `?token=${this.token}`;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const path = this.$route.path.split('/').splice(2).join('/')
 | 
			
		||||
      return `${baseURL}/api/public/dl/${path}${queryArg}`
 | 
			
		||||
      const path = this.$route.path.split("/").splice(2).join("/");
 | 
			
		||||
      return `${baseURL}/api/public/dl/${path}${queryArg}`;
 | 
			
		||||
    },
 | 
			
		||||
    fullLink: function () {
 | 
			
		||||
      return window.location.origin + this.link
 | 
			
		||||
      return window.location.origin + this.link;
 | 
			
		||||
    },
 | 
			
		||||
    humanSize: function () {
 | 
			
		||||
      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 () {
 | 
			
		||||
      return moment(this.req.modified).fromNow()
 | 
			
		||||
      return moment(this.req.modified).fromNow();
 | 
			
		||||
    },
 | 
			
		||||
    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: {
 | 
			
		||||
    ...mapMutations([ 'resetSelected', 'updateRequest', 'setLoading' ]),
 | 
			
		||||
    ...mapMutations(["resetSelected", "updateRequest", "setLoading"]),
 | 
			
		||||
    base64: function (name) {
 | 
			
		||||
      return window.btoa(unescape(encodeURIComponent(name)))
 | 
			
		||||
      return window.btoa(unescape(encodeURIComponent(name)));
 | 
			
		||||
    },
 | 
			
		||||
    fetchData: async function () {
 | 
			
		||||
      // Reset view information.
 | 
			
		||||
      this.$store.commit('setReload', false)
 | 
			
		||||
      this.$store.commit('resetSelected')
 | 
			
		||||
      this.$store.commit('multiple', false)
 | 
			
		||||
      this.$store.commit('closeHovers')
 | 
			
		||||
      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
 | 
			
		||||
      this.setLoading(true);
 | 
			
		||||
      this.error = null;
 | 
			
		||||
 | 
			
		||||
      if (this.password !== ''){
 | 
			
		||||
        this.attemptedPasswordLogin = true
 | 
			
		||||
      if (this.password !== "") {
 | 
			
		||||
        this.attemptedPasswordLogin = true;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      let url = this.$route.path
 | 
			
		||||
      if (url === '') url = '/'
 | 
			
		||||
      if (url[0] !== '/') url = '/' + url
 | 
			
		||||
      let url = this.$route.path;
 | 
			
		||||
      if (url === "") url = "/";
 | 
			
		||||
      if (url[0] !== "/") url = "/" + url;
 | 
			
		||||
 | 
			
		||||
      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.setLoading(false)
 | 
			
		||||
        this.updateRequest(file);
 | 
			
		||||
        this.setLoading(false);
 | 
			
		||||
      } catch (e) {
 | 
			
		||||
        this.error = e
 | 
			
		||||
        this.error = e;
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    keyEvent (event) {
 | 
			
		||||
    keyEvent(event) {
 | 
			
		||||
      // Esc!
 | 
			
		||||
      if (event.keyCode === 27) {
 | 
			
		||||
        // If we're on a listing, unselect all
 | 
			
		||||
        // files and folders.
 | 
			
		||||
        if (this.selectedCount > 0) {
 | 
			
		||||
          this.resetSelected()
 | 
			
		||||
          this.resetSelected();
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    toggleMultipleSelection () {
 | 
			
		||||
      this.$store.commit('multiple', !this.multiple)
 | 
			
		||||
    toggleMultipleSelection() {
 | 
			
		||||
      this.$store.commit("multiple", !this.multiple);
 | 
			
		||||
    },
 | 
			
		||||
    download () {
 | 
			
		||||
    download() {
 | 
			
		||||
      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)
 | 
			
		||||
        return
 | 
			
		||||
        api.download(
 | 
			
		||||
          null,
 | 
			
		||||
          this.hash,
 | 
			
		||||
          this.token,
 | 
			
		||||
          this.req.items[this.selected[0]].path
 | 
			
		||||
        );
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this.$store.commit('showHover', {
 | 
			
		||||
        prompt: 'download',
 | 
			
		||||
      this.$store.commit("showHover", {
 | 
			
		||||
        prompt: "download",
 | 
			
		||||
        confirm: (format) => {
 | 
			
		||||
          this.$store.commit('closeHovers')
 | 
			
		||||
          this.$store.commit("closeHovers");
 | 
			
		||||
 | 
			
		||||
          let files = []
 | 
			
		||||
          let files = [];
 | 
			
		||||
 | 
			
		||||
          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>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,7 +5,12 @@
 | 
			
		|||
      <title>{{ req.name }}</title>
 | 
			
		||||
 | 
			
		||||
      <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>
 | 
			
		||||
    </header-bar>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -16,120 +21,120 @@
 | 
			
		|||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { mapState } from 'vuex'
 | 
			
		||||
import { files as api } from '@/api'
 | 
			
		||||
import { theme } from '@/utils/constants'
 | 
			
		||||
import buttons from '@/utils/buttons'
 | 
			
		||||
import url from '@/utils/url'
 | 
			
		||||
import { mapState } from "vuex";
 | 
			
		||||
import { files as api } from "@/api";
 | 
			
		||||
import { theme } from "@/utils/constants";
 | 
			
		||||
import buttons from "@/utils/buttons";
 | 
			
		||||
import url from "@/utils/url";
 | 
			
		||||
 | 
			
		||||
import ace from 'ace-builds/src-min-noconflict/ace.js'
 | 
			
		||||
import modelist from 'ace-builds/src-min-noconflict/ext-modelist.js'
 | 
			
		||||
import 'ace-builds/webpack-resolver'
 | 
			
		||||
import ace from "ace-builds/src-min-noconflict/ace.js";
 | 
			
		||||
import modelist from "ace-builds/src-min-noconflict/ext-modelist.js";
 | 
			
		||||
import "ace-builds/webpack-resolver";
 | 
			
		||||
 | 
			
		||||
import HeaderBar from '@/components/header/HeaderBar'
 | 
			
		||||
import Action from '@/components/header/Action'
 | 
			
		||||
import Breadcrumbs from '@/components/Breadcrumbs'
 | 
			
		||||
import HeaderBar from "@/components/header/HeaderBar";
 | 
			
		||||
import Action from "@/components/header/Action";
 | 
			
		||||
import Breadcrumbs from "@/components/Breadcrumbs";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'editor',
 | 
			
		||||
  name: "editor",
 | 
			
		||||
  components: {
 | 
			
		||||
    HeaderBar,
 | 
			
		||||
    Action,
 | 
			
		||||
    Breadcrumbs
 | 
			
		||||
    Breadcrumbs,
 | 
			
		||||
  },
 | 
			
		||||
  data: function () {
 | 
			
		||||
    return {}
 | 
			
		||||
    return {};
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapState(['req', 'user']),
 | 
			
		||||
    breadcrumbs () {
 | 
			
		||||
      let parts = this.$route.path.split('/')
 | 
			
		||||
    ...mapState(["req", "user"]),
 | 
			
		||||
    breadcrumbs() {
 | 
			
		||||
      let parts = this.$route.path.split("/");
 | 
			
		||||
 | 
			
		||||
      if (parts[0] === '') {
 | 
			
		||||
        parts.shift()
 | 
			
		||||
      if (parts[0] === "") {
 | 
			
		||||
        parts.shift();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (parts[parts.length - 1] === '') {
 | 
			
		||||
        parts.pop()
 | 
			
		||||
      if (parts[parts.length - 1] === "") {
 | 
			
		||||
        parts.pop();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      let breadcrumbs = []
 | 
			
		||||
      let breadcrumbs = [];
 | 
			
		||||
 | 
			
		||||
      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) {
 | 
			
		||||
        while (breadcrumbs.length !== 4) {
 | 
			
		||||
          breadcrumbs.shift()
 | 
			
		||||
          breadcrumbs.shift();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        breadcrumbs[0].name = '...'
 | 
			
		||||
        breadcrumbs[0].name = "...";
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return breadcrumbs
 | 
			
		||||
    }
 | 
			
		||||
      return breadcrumbs;
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  created () {
 | 
			
		||||
    window.addEventListener('keydown', this.keyEvent)
 | 
			
		||||
  created() {
 | 
			
		||||
    window.addEventListener("keydown", this.keyEvent);
 | 
			
		||||
  },
 | 
			
		||||
  beforeDestroy () {
 | 
			
		||||
    window.removeEventListener('keydown', this.keyEvent)
 | 
			
		||||
  beforeDestroy() {
 | 
			
		||||
    window.removeEventListener("keydown", this.keyEvent);
 | 
			
		||||
    this.editor.destroy();
 | 
			
		||||
  },
 | 
			
		||||
  mounted: function () {
 | 
			
		||||
    const fileContent = this.req.content || '';
 | 
			
		||||
    const fileContent = this.req.content || "";
 | 
			
		||||
 | 
			
		||||
    this.editor = ace.edit('editor', {
 | 
			
		||||
    this.editor = ace.edit("editor", {
 | 
			
		||||
      value: fileContent,
 | 
			
		||||
      showPrintMargin: false,
 | 
			
		||||
      readOnly: this.req.type === 'textImmutable',
 | 
			
		||||
      theme: 'ace/theme/chrome',
 | 
			
		||||
      readOnly: this.req.type === "textImmutable",
 | 
			
		||||
      theme: "ace/theme/chrome",
 | 
			
		||||
      mode: modelist.getModeForPath(this.req.name).mode,
 | 
			
		||||
      wrap: true
 | 
			
		||||
    })
 | 
			
		||||
      wrap: true,
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if (theme == 'dark') {
 | 
			
		||||
    if (theme == "dark") {
 | 
			
		||||
      this.editor.setTheme("ace/theme/twilight");
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    back () {
 | 
			
		||||
      let uri = url.removeLastDir(this.$route.path) + '/'
 | 
			
		||||
      this.$router.push({ path: uri })
 | 
			
		||||
    back() {
 | 
			
		||||
      let uri = url.removeLastDir(this.$route.path) + "/";
 | 
			
		||||
      this.$router.push({ path: uri });
 | 
			
		||||
    },
 | 
			
		||||
    keyEvent (event) {
 | 
			
		||||
    keyEvent(event) {
 | 
			
		||||
      if (!event.ctrlKey && !event.metaKey) {
 | 
			
		||||
        return
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (String.fromCharCode(event.which).toLowerCase() !== 's') {
 | 
			
		||||
        return
 | 
			
		||||
      if (String.fromCharCode(event.which).toLowerCase() !== "s") {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      event.preventDefault()
 | 
			
		||||
      this.save()
 | 
			
		||||
      event.preventDefault();
 | 
			
		||||
      this.save();
 | 
			
		||||
    },
 | 
			
		||||
    async save () {
 | 
			
		||||
      const button = 'save'
 | 
			
		||||
      buttons.loading('save')
 | 
			
		||||
    async save() {
 | 
			
		||||
      const button = "save";
 | 
			
		||||
      buttons.loading("save");
 | 
			
		||||
 | 
			
		||||
      try {
 | 
			
		||||
        await api.put(this.$route.path, this.editor.getValue())
 | 
			
		||||
        buttons.success(button)
 | 
			
		||||
        await api.put(this.$route.path, this.editor.getValue());
 | 
			
		||||
        buttons.success(button);
 | 
			
		||||
      } catch (e) {
 | 
			
		||||
        buttons.done(button)
 | 
			
		||||
        this.$showError(e)
 | 
			
		||||
        buttons.done(button);
 | 
			
		||||
        this.$showError(e);
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    close () {
 | 
			
		||||
      this.$store.commit('updateRequest', {})
 | 
			
		||||
    close() {
 | 
			
		||||
      this.$store.commit("updateRequest", {});
 | 
			
		||||
 | 
			
		||||
      let uri = url.removeLastDir(this.$route.path) + '/'
 | 
			
		||||
      this.$router.push({ path: uri })
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
      let uri = url.removeLastDir(this.$route.path) + "/";
 | 
			
		||||
      this.$router.push({ path: uri });
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
				
			
			@ -1,15 +1,45 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div id="previewer" @mousemove="toggleNavigation" @touchstart="toggleNavigation">
 | 
			
		||||
  <div
 | 
			
		||||
    id="previewer"
 | 
			
		||||
    @mousemove="toggleNavigation"
 | 
			
		||||
    @touchstart="toggleNavigation"
 | 
			
		||||
  >
 | 
			
		||||
    <header-bar>
 | 
			
		||||
      <action icon="close" :label="$t('buttons.close')" @action="close()" />
 | 
			
		||||
      <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>
 | 
			
		||||
        <action :disabled="loading" icon="mode_edit" :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" />
 | 
			
		||||
        <action
 | 
			
		||||
          :disabled="loading"
 | 
			
		||||
          icon="mode_edit"
 | 
			
		||||
          :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>
 | 
			
		||||
    </header-bar>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -31,221 +61,249 @@
 | 
			
		|||
            v-for="(sub, index) in subtitles"
 | 
			
		||||
            :key="index"
 | 
			
		||||
            :src="sub"
 | 
			
		||||
            :label="'Subtitle ' + index" :default="index === 0">
 | 
			
		||||
          Sorry, your browser doesn't support embedded videos,
 | 
			
		||||
          but don't worry, you can <a :href="downloadUrl">download it</a>
 | 
			
		||||
            :label="'Subtitle ' + index"
 | 
			
		||||
            :default="index === 0"
 | 
			
		||||
          />
 | 
			
		||||
          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!
 | 
			
		||||
        </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">
 | 
			
		||||
          <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>
 | 
			
		||||
      </div>
 | 
			
		||||
    </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>
 | 
			
		||||
    </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>
 | 
			
		||||
    </button>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { mapState } from 'vuex'
 | 
			
		||||
import { files as api } from '@/api'
 | 
			
		||||
import { baseURL, resizePreview } from '@/utils/constants'
 | 
			
		||||
import url from '@/utils/url'
 | 
			
		||||
import throttle from 'lodash.throttle'
 | 
			
		||||
import { mapState } from "vuex";
 | 
			
		||||
import { files as api } from "@/api";
 | 
			
		||||
import { baseURL, resizePreview } from "@/utils/constants";
 | 
			
		||||
import url from "@/utils/url";
 | 
			
		||||
import throttle from "lodash.throttle";
 | 
			
		||||
 | 
			
		||||
import HeaderBar from '@/components/header/HeaderBar'
 | 
			
		||||
import Action from '@/components/header/Action'
 | 
			
		||||
import ExtendedImage from '@/components/files/ExtendedImage'
 | 
			
		||||
import HeaderBar from "@/components/header/HeaderBar";
 | 
			
		||||
import Action from "@/components/header/Action";
 | 
			
		||||
import ExtendedImage from "@/components/files/ExtendedImage";
 | 
			
		||||
 | 
			
		||||
const mediaTypes = [
 | 
			
		||||
  "image",
 | 
			
		||||
  "video",
 | 
			
		||||
  "audio",
 | 
			
		||||
  "blob"
 | 
			
		||||
]
 | 
			
		||||
const mediaTypes = ["image", "video", "audio", "blob"];
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'preview',
 | 
			
		||||
  name: "preview",
 | 
			
		||||
  components: {
 | 
			
		||||
    HeaderBar,
 | 
			
		||||
    Action,
 | 
			
		||||
    ExtendedImage
 | 
			
		||||
    ExtendedImage,
 | 
			
		||||
  },
 | 
			
		||||
  data: function () {
 | 
			
		||||
    return {
 | 
			
		||||
      previousLink: '',
 | 
			
		||||
      nextLink: '',
 | 
			
		||||
      previousLink: "",
 | 
			
		||||
      nextLink: "",
 | 
			
		||||
      listing: null,
 | 
			
		||||
      name: '',
 | 
			
		||||
      name: "",
 | 
			
		||||
      subtitles: [],
 | 
			
		||||
      fullSize: false,
 | 
			
		||||
      showNav: true,
 | 
			
		||||
      navTimeout: null,
 | 
			
		||||
      hoverNav: false
 | 
			
		||||
    }
 | 
			
		||||
      hoverNav: false,
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapState(['req', 'user', 'oldReq', 'jwt', 'loading', 'show']),
 | 
			
		||||
    hasPrevious () {
 | 
			
		||||
      return (this.previousLink !== '')
 | 
			
		||||
    ...mapState(["req", "user", "oldReq", "jwt", "loading", "show"]),
 | 
			
		||||
    hasPrevious() {
 | 
			
		||||
      return this.previousLink !== "";
 | 
			
		||||
    },
 | 
			
		||||
    hasNext () {
 | 
			
		||||
      return (this.nextLink !== '')
 | 
			
		||||
    hasNext() {
 | 
			
		||||
      return this.nextLink !== "";
 | 
			
		||||
    },
 | 
			
		||||
    downloadUrl () {
 | 
			
		||||
      return `${baseURL}/api/raw${url.encodePath(this.req.path)}?auth=${this.jwt}`
 | 
			
		||||
    downloadUrl() {
 | 
			
		||||
      return `${baseURL}/api/raw${url.encodePath(this.req.path)}?auth=${
 | 
			
		||||
        this.jwt
 | 
			
		||||
      }`;
 | 
			
		||||
    },
 | 
			
		||||
    previewUrl () {
 | 
			
		||||
    previewUrl() {
 | 
			
		||||
      // 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) {
 | 
			
		||||
        return `${baseURL}/api/preview/big${url.encodePath(this.req.path)}?auth=${this.jwt}&k=${key}`
 | 
			
		||||
      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/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 () {
 | 
			
		||||
      return `${this.previewUrl}&inline=true`
 | 
			
		||||
    raw() {
 | 
			
		||||
      return `${this.previewUrl}&inline=true`;
 | 
			
		||||
    },
 | 
			
		||||
    showMore () {
 | 
			
		||||
      return this.$store.state.show === 'more'
 | 
			
		||||
    showMore() {
 | 
			
		||||
      return this.$store.state.show === "more";
 | 
			
		||||
    },
 | 
			
		||||
    isResizeEnabled() {
 | 
			
		||||
      return resizePreview;
 | 
			
		||||
    },
 | 
			
		||||
    isResizeEnabled () {
 | 
			
		||||
      return resizePreview
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  watch: {
 | 
			
		||||
    $route: function () {
 | 
			
		||||
      this.updatePreview()
 | 
			
		||||
      this.toggleNavigation()
 | 
			
		||||
    }
 | 
			
		||||
      this.updatePreview();
 | 
			
		||||
      this.toggleNavigation();
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  async mounted () {
 | 
			
		||||
    window.addEventListener('keydown', this.key)
 | 
			
		||||
    this.listing = this.oldReq.items
 | 
			
		||||
    this.updatePreview()
 | 
			
		||||
  async mounted() {
 | 
			
		||||
    window.addEventListener("keydown", this.key);
 | 
			
		||||
    this.listing = this.oldReq.items;
 | 
			
		||||
    this.updatePreview();
 | 
			
		||||
  },
 | 
			
		||||
  beforeDestroy () {
 | 
			
		||||
    window.removeEventListener('keydown', this.key)
 | 
			
		||||
  beforeDestroy() {
 | 
			
		||||
    window.removeEventListener("keydown", this.key);
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    deleteFile () {
 | 
			
		||||
      this.$store.commit('showHover', {
 | 
			
		||||
        prompt: 'delete',
 | 
			
		||||
    deleteFile() {
 | 
			
		||||
      this.$store.commit("showHover", {
 | 
			
		||||
        prompt: "delete",
 | 
			
		||||
        confirm: () => {
 | 
			
		||||
          this.listing = this.listing.filter(item => item.name !== this.name)
 | 
			
		||||
          this.listing = this.listing.filter((item) => item.name !== this.name);
 | 
			
		||||
 | 
			
		||||
          if (this.hasNext) {
 | 
			
		||||
            this.next()
 | 
			
		||||
            this.next();
 | 
			
		||||
          } else if (!this.hasPrevious && !this.hasNext) {
 | 
			
		||||
            this.close()
 | 
			
		||||
            this.close();
 | 
			
		||||
          } else {
 | 
			
		||||
            this.prev()
 | 
			
		||||
            this.prev();
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
    prev () {
 | 
			
		||||
      this.hoverNav = false
 | 
			
		||||
      this.$router.push({ path: this.previousLink })
 | 
			
		||||
    prev() {
 | 
			
		||||
      this.hoverNav = false;
 | 
			
		||||
      this.$router.push({ path: this.previousLink });
 | 
			
		||||
    },
 | 
			
		||||
    next () {
 | 
			
		||||
      this.hoverNav = false
 | 
			
		||||
      this.$router.push({ path: this.nextLink })
 | 
			
		||||
    next() {
 | 
			
		||||
      this.hoverNav = false;
 | 
			
		||||
      this.$router.push({ path: this.nextLink });
 | 
			
		||||
    },
 | 
			
		||||
    key (event) {
 | 
			
		||||
 | 
			
		||||
    key(event) {
 | 
			
		||||
      if (this.show !== null) {
 | 
			
		||||
        return
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (event.which === 13 || event.which === 39) { // right arrow
 | 
			
		||||
        if (this.hasNext) this.next()
 | 
			
		||||
      } else if (event.which === 37) { // left arrow
 | 
			
		||||
        if (this.hasPrevious) this.prev()
 | 
			
		||||
      } else if (event.which === 27) { // esc
 | 
			
		||||
        this.close()
 | 
			
		||||
      if (event.which === 13 || event.which === 39) {
 | 
			
		||||
        // right arrow
 | 
			
		||||
        if (this.hasNext) this.next();
 | 
			
		||||
      } else if (event.which === 37) {
 | 
			
		||||
        // left arrow
 | 
			
		||||
        if (this.hasPrevious) this.prev();
 | 
			
		||||
      } else if (event.which === 27) {
 | 
			
		||||
        // esc
 | 
			
		||||
        this.close();
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    async updatePreview () {
 | 
			
		||||
    async updatePreview() {
 | 
			
		||||
      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("/")
 | 
			
		||||
      this.name = decodeURIComponent(dirs[dirs.length - 1])
 | 
			
		||||
      let dirs = this.$route.fullPath.split("/");
 | 
			
		||||
      this.name = decodeURIComponent(dirs[dirs.length - 1]);
 | 
			
		||||
 | 
			
		||||
      if (!this.listing) {
 | 
			
		||||
        try {
 | 
			
		||||
          const path = url.removeLastDir(this.$route.path)
 | 
			
		||||
          const res = await api.fetch(path)
 | 
			
		||||
          this.listing = res.items
 | 
			
		||||
          const path = url.removeLastDir(this.$route.path);
 | 
			
		||||
          const res = await api.fetch(path);
 | 
			
		||||
          this.listing = res.items;
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
          this.$showError(e)
 | 
			
		||||
          this.$showError(e);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this.previousLink = ''
 | 
			
		||||
      this.nextLink = ''
 | 
			
		||||
      this.previousLink = "";
 | 
			
		||||
      this.nextLink = "";
 | 
			
		||||
 | 
			
		||||
      for (let i = 0; i < this.listing.length; i++) {
 | 
			
		||||
        if (this.listing[i].name !== this.name) {
 | 
			
		||||
          continue
 | 
			
		||||
          continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (let j = i - 1; j >= 0; j--) {
 | 
			
		||||
          if (mediaTypes.includes(this.listing[j].type)) {
 | 
			
		||||
            this.previousLink = this.listing[j].url
 | 
			
		||||
            break
 | 
			
		||||
            this.previousLink = this.listing[j].url;
 | 
			
		||||
            break;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (let j = i + 1; j < this.listing.length; j++) {
 | 
			
		||||
          if (mediaTypes.includes(this.listing[j].type)) {
 | 
			
		||||
            this.nextLink = this.listing[j].url
 | 
			
		||||
            break
 | 
			
		||||
            this.nextLink = this.listing[j].url;
 | 
			
		||||
            break;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    openMore () {
 | 
			
		||||
      this.$store.commit('showHover', 'more')
 | 
			
		||||
    openMore() {
 | 
			
		||||
      this.$store.commit("showHover", "more");
 | 
			
		||||
    },
 | 
			
		||||
    resetPrompts () {
 | 
			
		||||
      this.$store.commit('closeHovers')
 | 
			
		||||
    resetPrompts() {
 | 
			
		||||
      this.$store.commit("closeHovers");
 | 
			
		||||
    },
 | 
			
		||||
    toggleSize () {
 | 
			
		||||
      this.fullSize = !this.fullSize
 | 
			
		||||
    toggleSize() {
 | 
			
		||||
      this.fullSize = !this.fullSize;
 | 
			
		||||
    },
 | 
			
		||||
    toggleNavigation: throttle(function() {
 | 
			
		||||
      this.showNav = true
 | 
			
		||||
    toggleNavigation: throttle(function () {
 | 
			
		||||
      this.showNav = true;
 | 
			
		||||
 | 
			
		||||
      if (this.navTimeout) {
 | 
			
		||||
        clearTimeout(this.navTimeout)
 | 
			
		||||
        clearTimeout(this.navTimeout);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this.navTimeout = setTimeout(() => {
 | 
			
		||||
        this.showNav = false || this.hoverNav
 | 
			
		||||
        this.navTimeout = null
 | 
			
		||||
        this.showNav = false || this.hoverNav;
 | 
			
		||||
        this.navTimeout = null;
 | 
			
		||||
      }, 1500);
 | 
			
		||||
    }, 500),
 | 
			
		||||
    close () {
 | 
			
		||||
      this.$store.commit('updateRequest', {})
 | 
			
		||||
    close() {
 | 
			
		||||
      this.$store.commit("updateRequest", {});
 | 
			
		||||
 | 
			
		||||
      let uri = url.removeLastDir(this.$route.path) + '/'
 | 
			
		||||
      this.$router.push({ path: uri })
 | 
			
		||||
      let uri = url.removeLastDir(this.$route.path) + "/";
 | 
			
		||||
      this.$router.push({ path: uri });
 | 
			
		||||
    },
 | 
			
		||||
    download() {
 | 
			
		||||
      api.download(null, this.$route.path)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
      api.download(null, this.$route.path);
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,54 +3,93 @@
 | 
			
		|||
    <div class="column">
 | 
			
		||||
      <form class="card" @submit.prevent="save">
 | 
			
		||||
        <div class="card-title">
 | 
			
		||||
          <h2>{{ $t('settings.globalSettings') }}</h2>
 | 
			
		||||
          <h2>{{ $t("settings.globalSettings") }}</h2>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <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>
 | 
			
		||||
          <p class="small">{{ $t('settings.globalRules') }}</p>
 | 
			
		||||
          <h3>{{ $t("settings.rules") }}</h3>
 | 
			
		||||
          <p class="small">{{ $t("settings.globalRules") }}</p>
 | 
			
		||||
          <rules :rules.sync="settings.rules" />
 | 
			
		||||
 | 
			
		||||
          <div v-if="isExecEnabled">
 | 
			
		||||
            <h3>{{ $t('settings.executeOnShell') }}</h3>
 | 
			
		||||
            <p class="small">{{ $t('settings.executeOnShellDescription') }}</p>
 | 
			
		||||
            <input class="input input--block" type="text" placeholder="bash -c, cmd /c, ..." v-model="settings.shell" />
 | 
			
		||||
            <h3>{{ $t("settings.executeOnShell") }}</h3>
 | 
			
		||||
            <p class="small">{{ $t("settings.executeOnShellDescription") }}</p>
 | 
			
		||||
            <input
 | 
			
		||||
              class="input input--block"
 | 
			
		||||
              type="text"
 | 
			
		||||
              placeholder="bash -c, cmd /c, ..."
 | 
			
		||||
              v-model="settings.shell"
 | 
			
		||||
            />
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          <h3>{{ $t('settings.branding') }}</h3>
 | 
			
		||||
          <h3>{{ $t("settings.branding") }}</h3>
 | 
			
		||||
 | 
			
		||||
          <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>
 | 
			
		||||
 | 
			
		||||
          <p>
 | 
			
		||||
            <input type="checkbox" v-model="settings.branding.disableExternal" id="branding-links" />
 | 
			
		||||
            {{ $t('settings.disableExternalLinks') }}
 | 
			
		||||
            <input
 | 
			
		||||
              type="checkbox"
 | 
			
		||||
              v-model="settings.branding.disableExternal"
 | 
			
		||||
              id="branding-links"
 | 
			
		||||
            />
 | 
			
		||||
            {{ $t("settings.disableExternalLinks") }}
 | 
			
		||||
          </p>
 | 
			
		||||
 | 
			
		||||
          <p>
 | 
			
		||||
            <label for="theme">{{ $t('settings.themes.title') }}</label>
 | 
			
		||||
            <themes class="input input--block" :theme.sync="settings.branding.theme" id="theme"></themes>
 | 
			
		||||
            <label for="theme">{{ $t("settings.themes.title") }}</label>
 | 
			
		||||
            <themes
 | 
			
		||||
              class="input input--block"
 | 
			
		||||
              :theme.sync="settings.branding.theme"
 | 
			
		||||
              id="theme"
 | 
			
		||||
            ></themes>
 | 
			
		||||
          </p>
 | 
			
		||||
 | 
			
		||||
          <p>
 | 
			
		||||
            <label for="branding-name">{{ $t('settings.instanceName') }}</label>
 | 
			
		||||
            <input class="input input--block" type="text" v-model="settings.branding.name" id="branding-name" />
 | 
			
		||||
            <label for="branding-name">{{ $t("settings.instanceName") }}</label>
 | 
			
		||||
            <input
 | 
			
		||||
              class="input input--block"
 | 
			
		||||
              type="text"
 | 
			
		||||
              v-model="settings.branding.name"
 | 
			
		||||
              id="branding-name"
 | 
			
		||||
            />
 | 
			
		||||
          </p>
 | 
			
		||||
 | 
			
		||||
          <p>
 | 
			
		||||
            <label for="branding-files">{{ $t('settings.brandingDirectoryPath') }}</label>
 | 
			
		||||
            <input class="input input--block" type="text" v-model="settings.branding.files" id="branding-files" />
 | 
			
		||||
            <label for="branding-files">{{
 | 
			
		||||
              $t("settings.brandingDirectoryPath")
 | 
			
		||||
            }}</label>
 | 
			
		||||
            <input
 | 
			
		||||
              class="input input--block"
 | 
			
		||||
              type="text"
 | 
			
		||||
              v-model="settings.branding.files"
 | 
			
		||||
              id="branding-files"
 | 
			
		||||
            />
 | 
			
		||||
          </p>
 | 
			
		||||
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <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>
 | 
			
		||||
      </form>
 | 
			
		||||
    </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -58,17 +97,25 @@
 | 
			
		|||
    <div class="column">
 | 
			
		||||
      <form class="card" @submit.prevent="save">
 | 
			
		||||
        <div class="card-title">
 | 
			
		||||
          <h2>{{ $t('settings.userDefaults') }}</h2>
 | 
			
		||||
          <h2>{{ $t("settings.userDefaults") }}</h2>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <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 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>
 | 
			
		||||
      </form>
 | 
			
		||||
    </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -76,30 +123,46 @@
 | 
			
		|||
    <div class="column">
 | 
			
		||||
      <form v-if="isExecEnabled" class="card" @submit.prevent="save">
 | 
			
		||||
        <div class="card-title">
 | 
			
		||||
          <h2>{{ $t('settings.commandRunner') }}</h2>
 | 
			
		||||
          <h2>{{ $t("settings.commandRunner") }}</h2>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="card-content">
 | 
			
		||||
          <i18n path="settings.commandRunnerHelp" tag="p" class="small">
 | 
			
		||||
            <code>FILE</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>
 | 
			
		||||
 | 
			
		||||
          <div v-for="command in settings.commands" :key="command.name" class="collapsible">
 | 
			
		||||
            <input :id="command.name" type="checkbox">
 | 
			
		||||
          <div
 | 
			
		||||
            v-for="command in settings.commands"
 | 
			
		||||
            :key="command.name"
 | 
			
		||||
            class="collapsible"
 | 
			
		||||
          >
 | 
			
		||||
            <input :id="command.name" type="checkbox" />
 | 
			
		||||
            <label :for="command.name">
 | 
			
		||||
              <p>{{ capitalize(command.name) }}</p>
 | 
			
		||||
              <i class="material-icons">arrow_drop_down</i>
 | 
			
		||||
            </label>
 | 
			
		||||
            <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 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>
 | 
			
		||||
      </form>
 | 
			
		||||
    </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -107,80 +170,84 @@
 | 
			
		|||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { mapState } from 'vuex'
 | 
			
		||||
import { settings as api } from '@/api'
 | 
			
		||||
import UserForm from '@/components/settings/UserForm'
 | 
			
		||||
import Rules from '@/components/settings/Rules'
 | 
			
		||||
import Themes from '@/components/settings/Themes'
 | 
			
		||||
import { enableExec } from '@/utils/constants'
 | 
			
		||||
import { mapState } from "vuex";
 | 
			
		||||
import { settings as api } from "@/api";
 | 
			
		||||
import UserForm from "@/components/settings/UserForm";
 | 
			
		||||
import Rules from "@/components/settings/Rules";
 | 
			
		||||
import Themes from "@/components/settings/Themes";
 | 
			
		||||
import { enableExec } from "@/utils/constants";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'settings',
 | 
			
		||||
  name: "settings",
 | 
			
		||||
  components: {
 | 
			
		||||
    Themes,
 | 
			
		||||
    UserForm,
 | 
			
		||||
    Rules
 | 
			
		||||
    Rules,
 | 
			
		||||
  },
 | 
			
		||||
  data: function () {
 | 
			
		||||
    return {
 | 
			
		||||
      originalSettings: null,
 | 
			
		||||
      settings: null
 | 
			
		||||
    }
 | 
			
		||||
      settings: null,
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapState([ 'user' ]),
 | 
			
		||||
    isExecEnabled: () => enableExec
 | 
			
		||||
    ...mapState(["user"]),
 | 
			
		||||
    isExecEnabled: () => enableExec,
 | 
			
		||||
  },
 | 
			
		||||
  async created () {
 | 
			
		||||
  async created() {
 | 
			
		||||
    try {
 | 
			
		||||
      const original = await api.get()
 | 
			
		||||
      let settings = { ...original, commands: [] }
 | 
			
		||||
      const original = await api.get();
 | 
			
		||||
      let settings = { ...original, commands: [] };
 | 
			
		||||
 | 
			
		||||
      for (const key in original.commands) {
 | 
			
		||||
        settings.commands.push({
 | 
			
		||||
          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.settings = settings
 | 
			
		||||
      this.originalSettings = original;
 | 
			
		||||
      this.settings = settings;
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      this.$showError(e)
 | 
			
		||||
      this.$showError(e);
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    capitalize (name, where = '_') {
 | 
			
		||||
      if (where === 'caps') where = /(?=[A-Z])/
 | 
			
		||||
      let splitted = name.split(where)
 | 
			
		||||
      name = ''
 | 
			
		||||
    capitalize(name, where = "_") {
 | 
			
		||||
      if (where === "caps") where = /(?=[A-Z])/;
 | 
			
		||||
      let splitted = name.split(where);
 | 
			
		||||
      name = "";
 | 
			
		||||
 | 
			
		||||
      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 = {
 | 
			
		||||
        ...this.settings,
 | 
			
		||||
        shell: this.settings.shell.trim().split(' ').filter(s => s !== ''),
 | 
			
		||||
        commands: {}
 | 
			
		||||
      }
 | 
			
		||||
        shell: this.settings.shell
 | 
			
		||||
          .trim()
 | 
			
		||||
          .split(" ")
 | 
			
		||||
          .filter((s) => s !== ""),
 | 
			
		||||
        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 {
 | 
			
		||||
        await api.update(settings)
 | 
			
		||||
        this.$showSuccess(this.$t('settings.settingsUpdated'))
 | 
			
		||||
        await api.update(settings);
 | 
			
		||||
        this.$showSuccess(this.$t("settings.settingsUpdated"));
 | 
			
		||||
      } catch (e) {
 | 
			
		||||
        this.$showError(e)
 | 
			
		||||
        this.$showError(e);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,18 +3,31 @@
 | 
			
		|||
    <div class="column">
 | 
			
		||||
      <form class="card" @submit="updateSettings">
 | 
			
		||||
        <div class="card-title">
 | 
			
		||||
          <h2>{{ $t('settings.profileSettings') }}</h2>
 | 
			
		||||
          <h2>{{ $t("settings.profileSettings") }}</h2>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="card-content">
 | 
			
		||||
          <p><input type="checkbox" v-model="hideDotfiles"> {{ $t('settings.hideDotfiles') }}</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>
 | 
			
		||||
          <p>
 | 
			
		||||
            <input type="checkbox" v-model="hideDotfiles" />
 | 
			
		||||
            {{ $t("settings.hideDotfiles") }}
 | 
			
		||||
          </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 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>
 | 
			
		||||
      </form>
 | 
			
		||||
    </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -22,16 +35,32 @@
 | 
			
		|||
    <div class="column">
 | 
			
		||||
      <form class="card" v-if="!user.lockPassword" @submit="updatePassword">
 | 
			
		||||
        <div class="card-title">
 | 
			
		||||
          <h2>{{ $t('settings.changePassword') }}</h2>
 | 
			
		||||
          <h2>{{ $t("settings.changePassword") }}</h2>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="card-content">
 | 
			
		||||
          <input :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">
 | 
			
		||||
          <input
 | 
			
		||||
            :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 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>
 | 
			
		||||
      </form>
 | 
			
		||||
    </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -39,75 +68,80 @@
 | 
			
		|||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { mapState, mapMutations } from 'vuex'
 | 
			
		||||
import { users as api } from '@/api'
 | 
			
		||||
import Languages from '@/components/settings/Languages'
 | 
			
		||||
import { mapState, mapMutations } from "vuex";
 | 
			
		||||
import { users as api } from "@/api";
 | 
			
		||||
import Languages from "@/components/settings/Languages";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'settings',
 | 
			
		||||
  name: "settings",
 | 
			
		||||
  components: {
 | 
			
		||||
    Languages
 | 
			
		||||
    Languages,
 | 
			
		||||
  },
 | 
			
		||||
  data: function () {
 | 
			
		||||
    return {
 | 
			
		||||
      password: '',
 | 
			
		||||
      passwordConf: '',
 | 
			
		||||
      password: "",
 | 
			
		||||
      passwordConf: "",
 | 
			
		||||
      hideDotfiles: false,
 | 
			
		||||
      singleClick: false,
 | 
			
		||||
      locale: ''
 | 
			
		||||
    }
 | 
			
		||||
      locale: "",
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapState([ 'user' ]),
 | 
			
		||||
    passwordClass () {
 | 
			
		||||
      const baseClass = 'input input--block'
 | 
			
		||||
    ...mapState(["user"]),
 | 
			
		||||
    passwordClass() {
 | 
			
		||||
      const baseClass = "input input--block";
 | 
			
		||||
 | 
			
		||||
      if (this.password === '' && this.passwordConf === '') {
 | 
			
		||||
        return baseClass
 | 
			
		||||
      if (this.password === "" && this.passwordConf === "") {
 | 
			
		||||
        return baseClass;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (this.password === this.passwordConf) {
 | 
			
		||||
        return `${baseClass} input--green`
 | 
			
		||||
        return `${baseClass} input--green`;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return `${baseClass} input--red`
 | 
			
		||||
    }
 | 
			
		||||
      return `${baseClass} input--red`;
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  created () {
 | 
			
		||||
    this.locale = this.user.locale
 | 
			
		||||
    this.hideDotfiles = this.user.hideDotfiles
 | 
			
		||||
    this.singleClick = this.user.singleClick
 | 
			
		||||
  created() {
 | 
			
		||||
    this.locale = this.user.locale;
 | 
			
		||||
    this.hideDotfiles = this.user.hideDotfiles;
 | 
			
		||||
    this.singleClick = this.user.singleClick;
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    ...mapMutations([ 'updateUser' ]),
 | 
			
		||||
    async updatePassword (event) {
 | 
			
		||||
      event.preventDefault()
 | 
			
		||||
    ...mapMutations(["updateUser"]),
 | 
			
		||||
    async updatePassword(event) {
 | 
			
		||||
      event.preventDefault();
 | 
			
		||||
 | 
			
		||||
      if (this.password !== this.passwordConf || this.password === '') {
 | 
			
		||||
        return
 | 
			
		||||
      if (this.password !== this.passwordConf || this.password === "") {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      try {
 | 
			
		||||
        const data = { id: this.user.id, password: this.password }
 | 
			
		||||
        await api.update(data, ['password'])
 | 
			
		||||
        this.updateUser(data)
 | 
			
		||||
        this.$showSuccess(this.$t('settings.passwordUpdated'))
 | 
			
		||||
        const data = { id: this.user.id, password: this.password };
 | 
			
		||||
        await api.update(data, ["password"]);
 | 
			
		||||
        this.updateUser(data);
 | 
			
		||||
        this.$showSuccess(this.$t("settings.passwordUpdated"));
 | 
			
		||||
      } catch (e) {
 | 
			
		||||
        this.$showError(e)
 | 
			
		||||
        this.$showError(e);
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    async updateSettings (event) {
 | 
			
		||||
      event.preventDefault()
 | 
			
		||||
    async updateSettings(event) {
 | 
			
		||||
      event.preventDefault();
 | 
			
		||||
 | 
			
		||||
      try {
 | 
			
		||||
        const data = { id: this.user.id, locale: this.locale, hideDotfiles: this.hideDotfiles, singleClick: this.singleClick }
 | 
			
		||||
        await api.update(data, ['locale', 'hideDotfiles', 'singleClick'])
 | 
			
		||||
        this.updateUser(data)
 | 
			
		||||
        this.$showSuccess(this.$t('settings.settingsUpdated'))
 | 
			
		||||
        const data = {
 | 
			
		||||
          id: this.user.id,
 | 
			
		||||
          locale: this.locale,
 | 
			
		||||
          hideDotfiles: this.hideDotfiles,
 | 
			
		||||
          singleClick: this.singleClick,
 | 
			
		||||
        };
 | 
			
		||||
        await api.update(data, ["locale", "hideDotfiles", "singleClick"]);
 | 
			
		||||
        this.updateUser(data);
 | 
			
		||||
        this.$showSuccess(this.$t("settings.settingsUpdated"));
 | 
			
		||||
      } catch (e) {
 | 
			
		||||
        this.$showError(e)
 | 
			
		||||
        this.$showError(e);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,37 +3,51 @@
 | 
			
		|||
    <div class="column">
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <div class="card-title">
 | 
			
		||||
          <h2>{{ $t('settings.shareManagement') }}</h2>
 | 
			
		||||
          <h2>{{ $t("settings.shareManagement") }}</h2>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="card-content full">
 | 
			
		||||
          <table>
 | 
			
		||||
            <tr>
 | 
			
		||||
              <th>{{ $t('settings.path') }}</th>
 | 
			
		||||
              <th>{{ $t('settings.shareDuration') }}</th>
 | 
			
		||||
              <th v-if="user.perm.admin">{{ $t('settings.username') }}</th>
 | 
			
		||||
              <th>{{ $t("settings.path") }}</th>
 | 
			
		||||
              <th>{{ $t("settings.shareDuration") }}</th>
 | 
			
		||||
              <th v-if="user.perm.admin">{{ $t("settings.username") }}</th>
 | 
			
		||||
              <th></th>
 | 
			
		||||
              <th></th>
 | 
			
		||||
            </tr>
 | 
			
		||||
 | 
			
		||||
            <tr v-for="link in links" :key="link.hash">
 | 
			
		||||
              <td><a :href="buildLink(link.hash)" target="_blank">{{ link.path }}</a></td>
 | 
			
		||||
              <td>
 | 
			
		||||
                <template v-if="link.expire !== 0">{{ humanTime(link.expire) }}</template>
 | 
			
		||||
                <template v-else>{{ $t('permanent') }}</template>
 | 
			
		||||
                <a :href="buildLink(link.hash)" target="_blank">{{
 | 
			
		||||
                  link.path
 | 
			
		||||
                }}</a>
 | 
			
		||||
              </td>
 | 
			
		||||
              <td>
 | 
			
		||||
                <template v-if="link.expire !== 0">{{
 | 
			
		||||
                  humanTime(link.expire)
 | 
			
		||||
                }}</template>
 | 
			
		||||
                <template v-else>{{ $t("permanent") }}</template>
 | 
			
		||||
              </td>
 | 
			
		||||
              <td v-if="user.perm.admin">{{ link.username }}</td>
 | 
			
		||||
              <td class="small">
 | 
			
		||||
                <button class="action"
 | 
			
		||||
                        @click="deleteLink($event, link)"
 | 
			
		||||
                        :aria-label="$t('buttons.delete')"
 | 
			
		||||
                        :title="$t('buttons.delete')"><i class="material-icons">delete</i></button>
 | 
			
		||||
                <button
 | 
			
		||||
                  class="action"
 | 
			
		||||
                  @click="deleteLink($event, link)"
 | 
			
		||||
                  :aria-label="$t('buttons.delete')"
 | 
			
		||||
                  :title="$t('buttons.delete')"
 | 
			
		||||
                >
 | 
			
		||||
                  <i class="material-icons">delete</i>
 | 
			
		||||
                </button>
 | 
			
		||||
              </td>
 | 
			
		||||
              <td class="small">
 | 
			
		||||
                <button class="action copy-clipboard"
 | 
			
		||||
                        :data-clipboard-text="buildLink(link.hash)"
 | 
			
		||||
                        :aria-label="$t('buttons.copyToClipboard')"
 | 
			
		||||
                        :title="$t('buttons.copyToClipboard')"><i class="material-icons">content_paste</i></button>
 | 
			
		||||
                <button
 | 
			
		||||
                  class="action copy-clipboard"
 | 
			
		||||
                  :data-clipboard-text="buildLink(link.hash)"
 | 
			
		||||
                  :aria-label="$t('buttons.copyToClipboard')"
 | 
			
		||||
                  :title="$t('buttons.copyToClipboard')"
 | 
			
		||||
                >
 | 
			
		||||
                  <i class="material-icons">content_paste</i>
 | 
			
		||||
                </button>
 | 
			
		||||
              </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
          </table>
 | 
			
		||||
| 
						 | 
				
			
			@ -44,63 +58,67 @@
 | 
			
		|||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { share as api, users } from '@/api'
 | 
			
		||||
import moment from 'moment'
 | 
			
		||||
import {baseURL} from "@/utils/constants"
 | 
			
		||||
import Clipboard from 'clipboard'
 | 
			
		||||
import {mapState} from "vuex";
 | 
			
		||||
import { share as api, users } from "@/api";
 | 
			
		||||
import moment from "moment";
 | 
			
		||||
import { baseURL } from "@/utils/constants";
 | 
			
		||||
import Clipboard from "clipboard";
 | 
			
		||||
import { mapState } from "vuex";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'shares',
 | 
			
		||||
  computed: mapState([ 'user' ]),
 | 
			
		||||
  name: "shares",
 | 
			
		||||
  computed: mapState(["user"]),
 | 
			
		||||
  data: function () {
 | 
			
		||||
    return {
 | 
			
		||||
      links: [],
 | 
			
		||||
      clip: null
 | 
			
		||||
    }
 | 
			
		||||
      clip: null,
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  async created () {
 | 
			
		||||
  async created() {
 | 
			
		||||
    try {
 | 
			
		||||
      let links = await api.list()
 | 
			
		||||
      let links = await api.list();
 | 
			
		||||
      if (this.user.perm.admin) {
 | 
			
		||||
        let userMap = new Map()
 | 
			
		||||
        for (let user of await users.getAll()) userMap.set(user.id, user.username)
 | 
			
		||||
        for (let link of links) link.username = userMap.has(link.userID) ? userMap.get(link.userID) : ''
 | 
			
		||||
        let userMap = new Map();
 | 
			
		||||
        for (let user of await users.getAll())
 | 
			
		||||
          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) {
 | 
			
		||||
      this.$showError(e)
 | 
			
		||||
      this.$showError(e);
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  mounted() {
 | 
			
		||||
    this.clip = new Clipboard('.copy-clipboard')
 | 
			
		||||
    this.clip.on('success', () => {
 | 
			
		||||
      this.$showSuccess(this.$t('success.linkCopied'))
 | 
			
		||||
    })
 | 
			
		||||
    this.clip = new Clipboard(".copy-clipboard");
 | 
			
		||||
    this.clip.on("success", () => {
 | 
			
		||||
      this.$showSuccess(this.$t("success.linkCopied"));
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
  beforeDestroy () {
 | 
			
		||||
    this.clip.destroy()
 | 
			
		||||
  beforeDestroy() {
 | 
			
		||||
    this.clip.destroy();
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    deleteLink: async function (event, link) {
 | 
			
		||||
      event.preventDefault()
 | 
			
		||||
      event.preventDefault();
 | 
			
		||||
 | 
			
		||||
      this.$store.commit('showHover', {
 | 
			
		||||
        prompt: 'share-delete',
 | 
			
		||||
      this.$store.commit("showHover", {
 | 
			
		||||
        prompt: "share-delete",
 | 
			
		||||
        confirm: () => {
 | 
			
		||||
          this.$store.commit('closeHovers')
 | 
			
		||||
          this.$store.commit("closeHovers");
 | 
			
		||||
 | 
			
		||||
          api.remove(link.hash)
 | 
			
		||||
          this.links = this.links.filter(item => item.hash !== link.hash)
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
          api.remove(link.hash);
 | 
			
		||||
          this.links = this.links.filter((item) => item.hash !== link.hash);
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
    humanTime (time) {
 | 
			
		||||
      return moment(time * 1000).fromNow()
 | 
			
		||||
    humanTime(time) {
 | 
			
		||||
      return moment(time * 1000).fromNow();
 | 
			
		||||
    },
 | 
			
		||||
    buildLink (hash) {
 | 
			
		||||
      return `${window.location.origin}${baseURL}/share/${hash}`
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
    buildLink(hash) {
 | 
			
		||||
      return `${window.location.origin}${baseURL}/share/${hash}`;
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,8 +3,8 @@
 | 
			
		|||
    <div class="column">
 | 
			
		||||
      <form v-if="loaded" @submit="save" class="card">
 | 
			
		||||
        <div class="card-title">
 | 
			
		||||
          <h2 v-if="user.id === 0">{{ $t('settings.newUser') }}</h2>
 | 
			
		||||
          <h2 v-else>{{ $t('settings.user') }} {{ user.username }}</h2>
 | 
			
		||||
          <h2 v-if="user.id === 0">{{ $t("settings.newUser") }}</h2>
 | 
			
		||||
          <h2 v-else>{{ $t("settings.user") }} {{ user.username }}</h2>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="card-content">
 | 
			
		||||
| 
						 | 
				
			
			@ -18,11 +18,15 @@
 | 
			
		|||
            type="button"
 | 
			
		||||
            class="button button--flat button--red"
 | 
			
		||||
            :aria-label="$t('buttons.delete')"
 | 
			
		||||
            :title="$t('buttons.delete')">{{ $t('buttons.delete') }}</button>
 | 
			
		||||
            :title="$t('buttons.delete')"
 | 
			
		||||
          >
 | 
			
		||||
            {{ $t("buttons.delete") }}
 | 
			
		||||
          </button>
 | 
			
		||||
          <input
 | 
			
		||||
            class="button button--flat"
 | 
			
		||||
            type="submit"
 | 
			
		||||
            :value="$t('buttons.save')">
 | 
			
		||||
            :value="$t('buttons.save')"
 | 
			
		||||
          />
 | 
			
		||||
        </div>
 | 
			
		||||
      </form>
 | 
			
		||||
    </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -33,16 +37,17 @@
 | 
			
		|||
      </div>
 | 
			
		||||
 | 
			
		||||
      <div class="card-action">
 | 
			
		||||
        <button class="button button--flat button--grey"
 | 
			
		||||
        <button
 | 
			
		||||
          class="button button--flat button--grey"
 | 
			
		||||
          @click="closeHovers"
 | 
			
		||||
          v-focus
 | 
			
		||||
          :aria-label="$t('buttons.cancel')"
 | 
			
		||||
          :title="$t('buttons.cancel')">
 | 
			
		||||
          {{ $t('buttons.cancel') }}
 | 
			
		||||
          :title="$t('buttons.cancel')"
 | 
			
		||||
        >
 | 
			
		||||
          {{ $t("buttons.cancel") }}
 | 
			
		||||
        </button>
 | 
			
		||||
        <button class="button button--flat"
 | 
			
		||||
          @click="deleteUser">
 | 
			
		||||
          {{ $t('buttons.delete') }}
 | 
			
		||||
        <button class="button button--flat" @click="deleteUser">
 | 
			
		||||
          {{ $t("buttons.delete") }}
 | 
			
		||||
        </button>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -50,101 +55,103 @@
 | 
			
		|||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { mapMutations } from 'vuex'
 | 
			
		||||
import { users as api, settings } from '@/api'
 | 
			
		||||
import UserForm from '@/components/settings/UserForm'
 | 
			
		||||
import deepClone from 'lodash.clonedeep'
 | 
			
		||||
import { mapMutations } from "vuex";
 | 
			
		||||
import { users as api, settings } from "@/api";
 | 
			
		||||
import UserForm from "@/components/settings/UserForm";
 | 
			
		||||
import deepClone from "lodash.clonedeep";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'user',
 | 
			
		||||
  name: "user",
 | 
			
		||||
  components: {
 | 
			
		||||
    UserForm
 | 
			
		||||
    UserForm,
 | 
			
		||||
  },
 | 
			
		||||
  data: () => {
 | 
			
		||||
    return {
 | 
			
		||||
      originalUser: null,
 | 
			
		||||
      user: {},
 | 
			
		||||
      loaded: false
 | 
			
		||||
    }
 | 
			
		||||
      loaded: false,
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  created () {
 | 
			
		||||
    this.fetchData()
 | 
			
		||||
  created() {
 | 
			
		||||
    this.fetchData();
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    isNew () {
 | 
			
		||||
      return this.$route.path === '/settings/users/new'
 | 
			
		||||
    }
 | 
			
		||||
    isNew() {
 | 
			
		||||
      return this.$route.path === "/settings/users/new";
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  watch: {
 | 
			
		||||
    '$route': 'fetchData',
 | 
			
		||||
    'user.perm.admin': function () {
 | 
			
		||||
      if (!this.user.perm.admin) return
 | 
			
		||||
      this.user.lockPassword = false
 | 
			
		||||
    }
 | 
			
		||||
    $route: "fetchData",
 | 
			
		||||
    "user.perm.admin": function () {
 | 
			
		||||
      if (!this.user.perm.admin) return;
 | 
			
		||||
      this.user.lockPassword = false;
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    ...mapMutations([ 'closeHovers', 'showHover', 'setUser' ]),
 | 
			
		||||
    async fetchData () {
 | 
			
		||||
    ...mapMutations(["closeHovers", "showHover", "setUser"]),
 | 
			
		||||
    async fetchData() {
 | 
			
		||||
      try {
 | 
			
		||||
        if (this.isNew) {
 | 
			
		||||
          let { defaults } = await settings.get()
 | 
			
		||||
          let { defaults } = await settings.get();
 | 
			
		||||
          this.user = {
 | 
			
		||||
            ...defaults,
 | 
			
		||||
            username: '',
 | 
			
		||||
            passsword: '',
 | 
			
		||||
            username: "",
 | 
			
		||||
            passsword: "",
 | 
			
		||||
            rules: [],
 | 
			
		||||
            lockPassword: false,
 | 
			
		||||
            id: 0
 | 
			
		||||
          }
 | 
			
		||||
            id: 0,
 | 
			
		||||
          };
 | 
			
		||||
        } else {
 | 
			
		||||
          const id = this.$route.params.pathMatch
 | 
			
		||||
          this.user = { ...await api.get(id) }
 | 
			
		||||
          const id = this.$route.params.pathMatch;
 | 
			
		||||
          this.user = { ...(await api.get(id)) };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.loaded = true
 | 
			
		||||
        this.loaded = true;
 | 
			
		||||
      } catch (e) {
 | 
			
		||||
        this.$router.push({ path: '/settings/users/new' })
 | 
			
		||||
        this.$router.push({ path: "/settings/users/new" });
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    deletePrompt () {
 | 
			
		||||
      this.showHover('deleteUser')
 | 
			
		||||
    deletePrompt() {
 | 
			
		||||
      this.showHover("deleteUser");
 | 
			
		||||
    },
 | 
			
		||||
    async deleteUser (event) {
 | 
			
		||||
      event.preventDefault()
 | 
			
		||||
    async deleteUser(event) {
 | 
			
		||||
      event.preventDefault();
 | 
			
		||||
 | 
			
		||||
      try {
 | 
			
		||||
        await api.remove(this.user.id)
 | 
			
		||||
        this.$router.push({ path: '/settings/users' })
 | 
			
		||||
        this.$showSuccess(this.$t('settings.userDeleted'))
 | 
			
		||||
        await api.remove(this.user.id);
 | 
			
		||||
        this.$router.push({ path: "/settings/users" });
 | 
			
		||||
        this.$showSuccess(this.$t("settings.userDeleted"));
 | 
			
		||||
      } 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) {
 | 
			
		||||
      event.preventDefault()
 | 
			
		||||
    async save(event) {
 | 
			
		||||
      event.preventDefault();
 | 
			
		||||
      let user = {
 | 
			
		||||
        ...this.originalUser,
 | 
			
		||||
        ...this.user
 | 
			
		||||
      }
 | 
			
		||||
        ...this.user,
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      try {
 | 
			
		||||
        if (this.isNew) {
 | 
			
		||||
          const loc = await api.create(user)
 | 
			
		||||
          this.$router.push({ path: loc })
 | 
			
		||||
          this.$showSuccess(this.$t('settings.userCreated'))
 | 
			
		||||
          const loc = await api.create(user);
 | 
			
		||||
          this.$router.push({ path: loc });
 | 
			
		||||
          this.$showSuccess(this.$t("settings.userCreated"));
 | 
			
		||||
        } else {
 | 
			
		||||
          await api.update(user)
 | 
			
		||||
          await api.update(user);
 | 
			
		||||
 | 
			
		||||
          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) {
 | 
			
		||||
        this.$showError(e)
 | 
			
		||||
        this.$showError(e);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,25 +3,34 @@
 | 
			
		|||
    <div class="column">
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <div class="card-title">
 | 
			
		||||
          <h2>{{ $t('settings.users') }}</h2>
 | 
			
		||||
          <router-link to="/settings/users/new"><button class="button">{{ $t('buttons.new') }}</button></router-link>
 | 
			
		||||
          <h2>{{ $t("settings.users") }}</h2>
 | 
			
		||||
          <router-link to="/settings/users/new"
 | 
			
		||||
            ><button class="button">
 | 
			
		||||
              {{ $t("buttons.new") }}
 | 
			
		||||
            </button></router-link
 | 
			
		||||
          >
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="card-content full">
 | 
			
		||||
          <table>
 | 
			
		||||
            <tr>
 | 
			
		||||
              <th>{{ $t('settings.username') }}</th>
 | 
			
		||||
              <th>{{ $t('settings.admin') }}</th>
 | 
			
		||||
              <th>{{ $t('settings.scope') }}</th>
 | 
			
		||||
              <th>{{ $t("settings.username") }}</th>
 | 
			
		||||
              <th>{{ $t("settings.admin") }}</th>
 | 
			
		||||
              <th>{{ $t("settings.scope") }}</th>
 | 
			
		||||
              <th></th>
 | 
			
		||||
            </tr>
 | 
			
		||||
 | 
			
		||||
            <tr v-for="user in users" :key="user.id">
 | 
			
		||||
              <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 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>
 | 
			
		||||
            </tr>
 | 
			
		||||
          </table>
 | 
			
		||||
| 
						 | 
				
			
			@ -32,21 +41,21 @@
 | 
			
		|||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { users as api } from '@/api'
 | 
			
		||||
import { users as api } from "@/api";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'users',
 | 
			
		||||
  name: "users",
 | 
			
		||||
  data: function () {
 | 
			
		||||
    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>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
module.exports = {
 | 
			
		||||
  runtimeCompiler: true,
 | 
			
		||||
  publicPath: '[{[ .StaticURL ]}]',
 | 
			
		||||
  publicPath: "[{[ .StaticURL ]}]",
 | 
			
		||||
  parallel: 2,
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue