Commit bae8cfdf authored by wanli's avatar wanli

update

parent 32f1fd2c
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -9,13 +9,18 @@ ...@@ -9,13 +9,18 @@
}, },
"dependencies": { "dependencies": {
"@antv/g2": "^3.2.7", "@antv/g2": "^3.2.7",
"ant-design-vue": "^1.1.2", "ant-design-vue": "^1.7.5",
"axios": "^0.18.0", "axios": "^0.18.0",
"codemirror": "^5.59.2",
"core-js": "^3.9.0",
"cropperjs": "^1.5.11",
"plyr": "^3.6.4",
"numeral": "^2.0.6", "numeral": "^2.0.6",
"vue": "^2.5.17", "vue": "^2.5.17",
"vue-i18n": "^8.1.0", "vue-i18n": "^8.1.0",
"vue-router": "^3.0.1", "vue-router": "^3.0.1",
"vuex": "^3.0.1", "vuex": "^3.0.1",
"vue-codemirror": "^4.0.6",
"vuex-router-sync": "^5.0.0" "vuex-router-sync": "^5.0.0"
}, },
"devDependencies": { "devDependencies": {
...@@ -26,7 +31,7 @@ ...@@ -26,7 +31,7 @@
"less": "^3.8.1", "less": "^3.8.1",
"less-loader": "^4.1.0", "less-loader": "^4.1.0",
"svg-sprite-loader": "^3.9.2", "svg-sprite-loader": "^3.9.2",
"vue-template-compiler": "^2.5.17" "vue-template-compiler": "^2.6.12"
}, },
"eslintConfig": { "eslintConfig": {
"root": true, "root": true,
......
tools/frontend/public/favicon.ico

1.12 KB | W: | H:

tools/frontend/public/favicon.ico

16.6 KB | W: | H:

tools/frontend/public/favicon.ico
tools/frontend/public/favicon.ico
tools/frontend/public/favicon.ico
tools/frontend/public/favicon.ico
  • 2-up
  • Swipe
  • Onion skin
<svg width="642" height="642" xmlns="http://www.w3.org/2000/svg" class="icon">
<defs>
<style type="text/css"/>
</defs>
<g>
<title>background</title>
<rect x="-1" y="-1" width="644" height="644" id="canvas_background" fill="none"/>
</g>
<g>
<title>Layer 1</title>
<path d="m546.6176,641.32967l-451.23517,0c-52.32527,0 -95.08571,-42.76044 -95.08571,-95.08571l0,-451.23517c0,-52.32527 42.76044,-95.08571 95.08571,-95.08571l451.23517,0c52.32527,0 95.08571,42.76044 95.08571,95.08571l0,451.23517c0,52.32527 -42.76044,95.08571 -95.08571,95.08571z" fill="#2ecccd" id="svg_1"/>
<path d="m321.46431,263.67473c-131.65714,0 -238.55824,-87.2088 -243.05934,-195.79781c0,-3.93846 -3.37582,-7.31428 -7.31429,-7.31428c-3.93846,0 -7.87692,3.37582 -7.31428,7.87692c5.06373,115.34066 118.71648,208.17582 258.25055,208.17583s253.18681,-92.27253 258.25055,-208.17583c0,-3.93846 -3.37583,-7.87692 -7.31429,-7.87692c-3.93846,0 -7.31428,3.37582 -7.31428,7.31428c-5.62638,108.58901 -112.52748,195.79781 -244.18462,195.79781z" fill="#FCFCFC" id="svg_2"/>
<path d="m322,324.43956m-14.06593,0a14.06593,14.06593 0 1 0 28.13186,0a14.06593,14.06593 0 1 0 -28.13186,0z" fill="#FCFCFC" id="svg_3"/>
<text fill="#ffffff" stroke-width="0" x="183.3125" y="488.8" id="svg_4" font-size="128" font-family="Helvetica, Arial, sans-serif" text-anchor="start" xml:space="preserve">EVM</text>
</g>
</svg>
\ No newline at end of file
tools/frontend/src/assets/logo.png

6.69 KB | W: | H:

tools/frontend/src/assets/logo.png

5.2 KB | W: | H:

tools/frontend/src/assets/logo.png
tools/frontend/src/assets/logo.png
tools/frontend/src/assets/logo.png
tools/frontend/src/assets/logo.png
  • 2-up
  • Swipe
  • Onion skin
...@@ -5,18 +5,6 @@ ...@@ -5,18 +5,6 @@
<a-icon type="question-circle-o" /> <a-icon type="question-circle-o" />
</a> </a>
</a-tooltip> </a-tooltip>
<a-tooltip title="Code" placement="bottom">
-->
<a
target="_blank"
href="https://github.com/ruyangit/seed-workbench-ui.git"
class="action"
>
<span class="action">
<a-icon type="codepen" theme="outlined" />
</span>
</a>
</a-tooltip>
<a-dropdown placement="bottomRight"> <a-dropdown placement="bottomRight">
<span class="action"> <span class="action">
<a-icon type="codepen" theme="outlined" /> <a-icon type="codepen" theme="outlined" />
...@@ -24,16 +12,16 @@ ...@@ -24,16 +12,16 @@
<a-menu slot="overlay" @click="handleMenuClick"> <a-menu slot="overlay" @click="handleMenuClick">
<a-menu-item key="gitee"> <a-menu-item key="gitee">
<!-- <a target="_blank" href="https://github.com/ruyangit/seed-workbench-ui.git"> --> <a target="_blank" href="https://gitee.com/scriptiot/evm">
<a-icon type="slack-square" theme="outlined" /> <a-icon type="slack-square" theme="outlined" />
Gitee (开源中国) Gitee
<!-- </a> --> </a>
</a-menu-item> </a-menu-item>
<a-menu-item key="github"> <a-menu-item key="github">
<!-- <a target="_blank" href="https://github.com/ruyangit/seed-workbench-ui.git"> --> <a target="_blank" href="https://github.com/scriptiot/evm">
<a-icon type="github" /> <a-icon type="github" />
Github (同性交友) Github
<!-- </a> --> </a>
</a-menu-item> </a-menu-item>
</a-menu> </a-menu>
</a-dropdown> </a-dropdown>
...@@ -124,7 +112,7 @@ ...@@ -124,7 +112,7 @@
src="https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png" src="https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png"
alt="avatar" alt="avatar"
/> />
<span class="name">Ryan Ru</span> <span class="name">EVM</span>
</span> </span>
<a-menu slot="overlay" class="menu"> <a-menu slot="overlay" class="menu">
...@@ -142,7 +130,7 @@ ...@@ -142,7 +130,7 @@
</a-menu-item> </a-menu-item>
<a-menu-divider /> <a-menu-divider />
<a-menu-item key="logout"> <a-menu-item key="logout" @click="logout">
<a-icon type="logout" /> <a-icon type="logout" />
退出登录 退出登录
</a-menu-item> </a-menu-item>
...@@ -192,7 +180,6 @@ export default { ...@@ -192,7 +180,6 @@ export default {
AAvatar: Avatar, AAvatar: Avatar,
ANoticeIcon: NoticeIcon, ANoticeIcon: NoticeIcon,
ANoticeIconTab: NoticeIcon.Tab, ANoticeIconTab: NoticeIcon.Tab,
ADivider: Divider, ADivider: Divider,
ASettingDrawer: SettingDrawer, ASettingDrawer: SettingDrawer,
}, },
...@@ -204,16 +191,19 @@ export default { ...@@ -204,16 +191,19 @@ export default {
handleMenuClick(e) { handleMenuClick(e) {
if (e.key === "gitee") { if (e.key === "gitee") {
window.open( window.open(
"https://gitee.com/ruyangit/seed-workbench-ui.git", "https://gitee.com/scriptiot/evm",
"_blank" "_blank"
); );
} else { } else {
window.open( window.open(
"https://github.com/ruyangit/seed-workbench-ui.git", "https://gitee.com/scriptiot/evm",
"_blank" "_blank"
); );
} }
}, },
logout() {
this.$router.push({ path: "/user/login" });
},
success() { success() {
Modal.success({ Modal.success({
title: "友好的一个提示", title: "友好的一个提示",
......
...@@ -17,6 +17,7 @@ const GlobalHeader = { ...@@ -17,6 +17,7 @@ const GlobalHeader = {
}, },
render() { render() {
const { spinning, collapsed, onCollapsed, theme,layout } = this const { spinning, collapsed, onCollapsed, theme,layout } = this
return ( return (
<div class="header-index"> <div class="header-index">
<Icon <Icon
......
<template> <template>
<div :class="cls"> <div :class="cls">
<div v-if="title" class="numberInfoTitle"> <div v-if="title" class="numberInfoTitle">
{{title}} {{ title }}
</div> </div>
<div v-if="subTitle" class="numberInfoSubTitle"> <div v-if="subTitle" class="numberInfoSubTitle">
{{subTitle}} {{ subTitle }}
</div> </div>
<div class="numberInfoValue" :style="{'margin-top:gap':gap}"> <div class="numberInfoValue" :style="{ 'margin-top:gap': gap }">
<span> <span>
{{total}} {{ total }}
<em v-if="suffix" class="suffix">{{suffix}}</em> <em v-if="suffix" class="suffix">{{ suffix }}</em>
</span> </span>
<span v-if="status || subTotal" class="subTotal"> <span v-if="status || subTotal" class="subTotal">
{{subTotal}} {{ subTotal }}
<a-icon v-if="status" :type="`caret-${status}`" />} <a-icon v-if="status" :type="`caret-${status}`" />}
</span> </span>
</div>
</div> </div>
</div>
</template> </template>
<script> <script>
...@@ -32,18 +32,18 @@ export default { ...@@ -32,18 +32,18 @@ export default {
"subTotal", "subTotal",
"status", "status",
"suffix", "suffix",
"gap" "gap",
], ],
components: { components: {
AIcon: Icon AIcon: Icon,
}, },
computed: { computed: {
cls() { cls() {
const { theme } = this; const { theme } = this;
return classNames("numberInfo", { return classNames("numberInfo", {
["numberInfo" + theme]: theme ["numberInfo" + theme]: theme,
}); });
} },
} },
}; };
</script> </script>
\ No newline at end of file
...@@ -8,21 +8,21 @@ export default { ...@@ -8,21 +8,21 @@ export default {
theme: { default: "dark", type: String }, theme: { default: "dark", type: String },
layout: { type: String }, layout: { type: String },
mode: { default: "inline", type: String }, mode: { default: "inline", type: String },
menuData: { default: [], type: Array }, menuData: { default: () => [], type: Array },
styles: { type: String } styles: { type: String },
}, },
computed: { computed: {
...mapGetters({ ...mapGetters({
loading: "global/nav/loading" loading: "global/nav/loading",
}), }),
}, },
components: { components: {
AMenu: Menu, AMenu: Menu,
AMenuItem: Menu.Item, AMenuItem: Menu.Item,
ASubMenu: Menu.SubMenu, ASubMenu: Menu.SubMenu,
AMenuDivider: Menu.Divider, AMenuDivider: Menu.Divider,
AMenuItemGroup: Menu.ItemGroup, AMenuItemGroup: Menu.ItemGroup,
AIcon: Icon AIcon: Icon,
}, },
methods: { methods: {
getIcon(icon) { getIcon(icon) {
...@@ -38,12 +38,11 @@ export default { ...@@ -38,12 +38,11 @@ export default {
return icon; return icon;
}, },
getNavMenuItems(menusData, parent) { getNavMenuItems(menusData, parent) {
// console.log(menusData) // console.log(menusData)
if (!menusData) { if (!menusData) {
return []; return [];
} }
return menusData.map(item => { return menusData.map((item) => {
if (item.name) { if (item.name) {
return this.getSubMenuOrItem(item, parent); return this.getSubMenuOrItem(item, parent);
} }
...@@ -54,10 +53,7 @@ export default { ...@@ -54,10 +53,7 @@ export default {
}, },
getSubMenuOrItem(item) { getSubMenuOrItem(item) {
// doc: add hideChildrenInMenu 隐藏菜单 // doc: add hideChildrenInMenu 隐藏菜单
if ( if (item.menus && item.menus.some((menu) => menu.name)) {
item.menus &&
item.menus.some(menu => menu.name)
) {
const name = this.$t(item.locale); const name = this.$t(item.locale);
return ( return (
<a-sub-menu <a-sub-menu
...@@ -108,7 +104,7 @@ export default { ...@@ -108,7 +104,7 @@ export default {
return `/${path || ""}`.replace(/\/+/g, "/"); return `/${path || ""}`.replace(/\/+/g, "/");
}, },
urlToList(url) { urlToList(url) {
const urllist = url.split("/").filter(i => i); const urllist = url.split("/").filter((i) => i);
return urllist.map( return urllist.map(
(urlItem, index) => `/${urllist.slice(0, index + 1).join("/")}` (urlItem, index) => `/${urllist.slice(0, index + 1).join("/")}`
); );
...@@ -116,30 +112,29 @@ export default { ...@@ -116,30 +112,29 @@ export default {
getOpenKeys(path) { getOpenKeys(path) {
const openKeys = this.urlToList(path); const openKeys = this.urlToList(path);
if (this.layout === "topmenu") { if (this.layout === "topmenu") {
return null return null;
} }
return openKeys.filter(item => item !== path); return openKeys.filter((item) => item !== path);
} },
}, },
render() { render() {
const { path } = this.$route; const { path } = this.$route;
const openKeys = this.getOpenKeys(path); const openKeys = this.getOpenKeys(path);
return ( return (
<Spin spinning={this.loading} class="baseMenuLoadding"> <Spin spinning={this.loading} class="baseMenuLoadding">
<a-menu <a-menu
defaultOpenKeys={openKeys} defaultOpenKeys={openKeys}
selectedKeys={[path]} selectedKeys={[path]}
key="Menu" key="Menu"
mode={this.mode} mode={this.mode}
theme={this.theme} theme={this.theme}
collapsed={this.collapsed} collapsed={this.collapsed}
style={this.styles} style={this.styles}
> >
{this.getNavMenuItems(this.menuData)}
{this.getNavMenuItems(this.menuData)} </a-menu>
</a-menu>
</Spin> </Spin>
); );
} },
}; };
</script> </script>
\ No newline at end of file
@import 'ant-design-vue/lib/style/themes/default.less'; @import "ant-design-vue/lib/style/themes/default.less";
@ai-sider-menu-prefix: ~"@{ai-prefix}-sider-menu"; @ai-sider-menu-prefix: ~"@{ai-prefix}-sider-menu";
.@{ai-sider-menu-prefix}{ .@{ai-sider-menu-prefix} {
.logo{ .logo {
width: 100%; width: 100%;
height: 64px; height: 64px;
position: relative; position: relative;
line-height: 64px; line-height: 64px;
padding-left: (@menu-collapsed-width - 32px) / 2; padding-left: (@menu-collapsed-width - 32px) / 2;
transition: all 0.3s; transition: all 0.3s;
background: #002140; background: #002140;
overflow: hidden; overflow: hidden;
img { img {
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
height: 32px; height: 32px;
} }
h1 { h1 {
color: white; color: white;
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
font-size: 20px; font-size: 20px;
margin: 0 0 0 12px; margin: 0 0 0 12px;
font-family: 'Myriad Pro', 'Helvetica Neue', Arial, Helvetica, sans-serif; font-family: "Myriad Pro", "Helvetica Neue", Arial, Helvetica, sans-serif;
font-weight: 600; font-weight: 600;
}
} }
}
} }
.sider { .sider {
min-height: 100vh; min-height: 100vh;
box-shadow: 2px 0 6px rgba(0, 21, 41, 0.35); box-shadow: 2px 0 6px rgba(0, 21, 41, 0.35);
position: relative; position: relative;
z-index: 10; z-index: 10;
&.fixSiderbar { &.fixSiderbar {
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
} }
&.light { &.light {
box-shadow: 2px 0 8px 0 rgba(29, 35, 41, 0.05); box-shadow: 2px 0 8px 0 rgba(29, 35, 41, 0.05);
background-color: white; background-color: white;
.logo { .logo {
background: white; background: white;
border-bottom: 1px solid @border-color-split; border-bottom: 1px solid @border-color-split;
border-right: 1px solid @border-color-split; border-right: 1px solid @border-color-split;
h1 { h1 {
color: @primary-color; color: @primary-color;
}
} }
} }
}
} }
.baseMenuLoadding{
.active-menu-item {
background-color: #2ecccd;
} }
.baseMenuLoadding {
}
...@@ -22,7 +22,7 @@ const TopNavHeader = { ...@@ -22,7 +22,7 @@ const TopNavHeader = {
theme = "dark", theme = "dark",
contentWidth = "Fixed", contentWidth = "Fixed",
layout, layout,
// title = "admin", title = "admin",
} = this; } = this;
return ( return (
<div class="top-nav-header"> <div class="top-nav-header">
...@@ -32,7 +32,7 @@ const TopNavHeader = { ...@@ -32,7 +32,7 @@ const TopNavHeader = {
<div class="logo"> <div class="logo">
<router-link to="/"> <router-link to="/">
<img src={logo} alt="logo" /> <img src={logo} alt="logo" />
<h1>Ant Design Pro</h1> <h1>{title}</h1>
</router-link> </router-link>
</div> </div>
<div <div
......
...@@ -7,5 +7,6 @@ export default { ...@@ -7,5 +7,6 @@ export default {
autoHideHeader: false, // auto hide header autoHideHeader: false, // auto hide header
fixSiderbar: false, // sticky siderbar fixSiderbar: false, // sticky siderbar
leftMenuTitle: "EVM 应用商店", // 左侧边栏顶部名称 leftMenuTitle: "EVM 应用商店", // 左侧边栏顶部名称
leftMenuIcon: "" // 左侧边栏顶部Logo leftMenuIcon: "", // 左侧边栏顶部Logo
appSlogan: "EVM,致力于为互联网行业提供物联网解决方案", // 应用宣传文案
} }
...@@ -5,7 +5,7 @@ import SiderMenu from "@/components/SiderMenu"; ...@@ -5,7 +5,7 @@ import SiderMenu from "@/components/SiderMenu";
import Header from './Header'; import Header from './Header';
import Footer from './Footer'; import Footer from './Footer';
import eventBus from '@/utils/eventBus.js' import eventBus from '@/utils/eventBus.js'
import logo from "@/assets/logo.png"; import logo from "@/assets/app-store.svg";
import { mapGetters } from "vuex"; import { mapGetters } from "vuex";
const BasicLayout = { const BasicLayout = {
data: () => ({ data: () => ({
......
...@@ -8,27 +8,27 @@ const FooterView = { ...@@ -8,27 +8,27 @@ const FooterView = {
<GlobalFooter <GlobalFooter
links={[ links={[
{ {
key: 'Pro 首页', key: 'EVM',
title: 'Pro 首页', title: 'EVM 首页',
href: 'https://github.com/ruyangit/seed-workbench-ui.git', href: 'https://gitee.com/scriptiot/evm',
blankTarget: true, blankTarget: true,
}, },
{ {
key: 'github', key: 'gitee',
title: <Icon type="github" />, title: <Icon type="github" />,
href: 'https://github.com/ruyangit/seed-workbench-ui.git', href: 'https://gitee.com/scriptiot/evm',
blankTarget: true, blankTarget: true,
}, },
{ {
key: 'Ant Design', key: 'ByteCode',
title: 'Ant Design', title: 'ByteCode',
href: 'https://ant.design', href: 'http://evmiot.com',
blankTarget: true, blankTarget: true,
}, },
]} ]}
copyright={ copyright={
<div> <div>
Copyright <Icon type="copyright" /> 2018 Ryan Ru 金服体验技术部出品 Copyright <Icon type="copyright" /> 2021 武汉市字节码科技有限公司
</div> </div>
} }
/> />
......
import './UserLayout.less' import './UserLayout.less'
import logo from '@/assets/logo.png'; import logo from '@/assets/app-store.svg';
import { mapGetters } from "vuex";
const UserLayout = { const UserLayout = {
props: { props: {
logo: { default: logo, types: String } logo: { default: logo, types: String }
}, },
computed: {
...mapGetters({
settings: "global/settings"
})
},
render() { render() {
const { leftMenuTitle, appSlogan } = this.settings;
return ( return (
<div class="ai-user-layout-container"> <div class="ai-user-layout-container">
<div class="content"> <div class="content">
...@@ -12,11 +20,11 @@ const UserLayout = { ...@@ -12,11 +20,11 @@ const UserLayout = {
<div class="header"> <div class="header">
<img alt="logo" class="logo" src={this.logo} /> <img alt="logo" class="logo" src={this.logo} />
<span class="title"> <span class="title">
Ant Design {leftMenuTitle}
</span> </span>
</div> </div>
<div class="desc"> <div class="desc">
Ant Design 是西湖区最具影响力的 Web 设计规范 {appSlogan}
</div> </div>
</div> </div>
<router-view /> <router-view />
......
/**
* Arabic translate - D34DlyM4N(https://github.com/D34DlyM4N)
* @type Object
*/
const ar = {
btn: {
about: 'حول',
back: 'رجوع',
cancel: 'الغاء',
clear: 'مسح',
copy: 'نسخ',
cut: 'قص',
delete: 'حذف',
edit: 'تعديل',
forward: 'الى الامام',
folder: 'مجلد جديد',
file: 'ملف جديد',
fullScreen: 'ملء الشاشة',
grid: 'شبكة',
paste: 'لصق',
refresh: 'تحديث',
submit: 'ارسال',
table: 'جدول',
upload: 'رفع',
uploadSelect: 'اختر الملفات',
hidden: 'الملفات المخفية',
},
clipboard: {
actionType: 'نوع',
copy: 'نسخ',
cut: 'قص',
none: 'لا شيء محدد',
title: 'ذاكرة النصوص',
},
contextMenu: {
copy: 'نسخ',
cut: 'قص',
delete: 'حذف',
download: 'تحميل',
info: 'اختير:',
open: 'فتح',
paste: 'لصق',
properties: 'الخصائص',
rename: 'اعادة تسمية',
select: 'اختيار',
view: 'عرض',
zip: 'ضغط',
unzip: 'أستخراج',
edit: 'تعديل',
audioPlay: 'تشغيل',
videoPlay: 'تشغيل',
},
info: {
directories: 'المجلدات:',
files: 'الملفات:',
selected: 'أختيرت:',
selectedSize: 'حجم الملفات:',
size: 'حجم الملفات:',
},
manager: {
table: {
date: 'تأريخ',
folder: 'مجلد',
name: 'أسم',
size: 'حجم',
type: 'نوع',
},
},
modal: {
about: {
developer: 'مطور',
name: 'Laravel File Manager',
title: 'حول',
version: 'الإصدار',
},
delete: {
noSelected: 'لا شيء محدد!',
title: 'حذف',
},
newFile: {
fieldName: 'أسم الملف',
fieldFeedback: 'الملف موجود!',
title: 'أنشاء ملف جديد',
},
newFolder: {
fieldName: 'أسم المجلد',
fieldFeedback: 'المجلد موجود!',
title: 'انشاء مجلد جديد',
},
preview: {
title: 'عرض',
},
properties: {
disk: 'قرص',
modified: 'تم التعديل',
name: 'أسم',
path: 'مسار',
size: 'حجم',
title: 'خصائص',
type: 'نوع',
url: 'رابط',
access: 'التمكن من',
access_0: 'تم الرفض',
access_1: 'قراءة فقط',
access_2: 'اقرا و اكتب',
},
rename: {
directoryExist: 'المجلد موجود',
fieldName: 'ادخال اسم جديد',
fieldFeedback: 'اسم خاطئ',
fileExist: 'الملف موجود',
title: 'اعادة تسمية',
},
status: {
noErrors: 'لايوجد خطأ!',
title: 'الحالة',
},
upload: {
ifExist: 'اذا الملف موجود:',
noSelected: 'لا توجد ملفات مختارة!',
overwrite: 'اعادة الكتابة!',
selected: 'المختارة:',
size: 'الحجم:',
skip: 'تخطي',
title: 'رفع الملفات',
},
editor: {
title: 'محرر',
},
audioPlayer: {
title: 'مشغل الاصوات',
},
videoPlayer: {
title: 'مشغل الفيديو',
},
zip: {
title: 'أنشاء أرشيف',
fieldName: 'أسم الارشيف',
fieldFeedback: 'الارشيف موجود!',
},
unzip: {
title: 'فك الارشيف',
fieldName: 'أسم المجلد',
fieldRadioName: 'أستخراج الى:',
fieldRadio1: 'الى المجلد الحالي',
fieldRadio2: 'في مجلد جديد',
fieldFeedback: 'المجلد موجود!',
warning: 'تحذير! اذا تشابهت الاسماء, سيتم استبدال الملفات!',
},
cropper: {
title: 'قص',
apply: 'تطبيق',
reset: 'اعادة تعين',
save: 'حفظ',
},
},
notifications: {
cutToClipboard: 'قص إلى الحافظة!',
copyToClipboard: 'نسخ إلى الحافظة!',
},
response: {
noConfig: 'الاعدادت غير متوفرة!',
notFound: 'غير متوفر!',
diskNotFound: 'القرص غير موجود!',
pathNotFound: 'مسار غير موجود!',
diskSelected: 'تم اختيار القرص!',
// files
fileExist: 'الملف موجود بالفعل!',
fileCreated: 'تم إنشاء الملف!',
fileUpdated: 'تم تحديث الملف!',
fileNotFound: 'الملف غير موجود!',
// directories
dirExist: 'المجلد موجود بالفعل!',
dirCreated: 'تم أنشاء المجلد!',
dirNotFound: 'المجلد غير موجود',
// actions
uploaded: 'تم تحديث كل الملفات!',
notAllUploaded: 'بعض الملفات غير المحملة!',
delNotFound: 'بعض الملفات غير موجودة! تحديث!',
deleted: 'تم الحذف!',
renamed: 'أعيدت تسميتها!',
copied: 'تم النسخ بنجاح!',
// zip
zipError: 'خطأ في إنشاء الأرشيف!',
// acl
aclError: 'تم الرفض!',
},
};
export default ar;
/**
* Czech translate
* Aleš Nejdr - mige
* @type Object
*/
const cs = {
btn: {
about: 'O aplikaci',
back: 'Zpět',
cancel: 'Zrušit',
clear: 'Vymazat',
copy: 'Kopírovat',
cut: 'Vyjmout',
delete: 'Smazat',
edit: 'Upravit',
forward: 'Vpřed',
folder: 'Nová složka',
file: 'Nový soubor',
fullScreen: 'Celá obrazovka',
grid: 'Mřížka',
paste: 'Vložit',
refresh: 'Obnovit',
submit: 'Odeslat',
table: 'Tabulka',
upload: 'Nahrát',
uploadSelect: 'Vybrat soubory',
hidden: ' Skryté soubory',
},
clipboard: {
actionType: 'Typ',
copy: 'Kopírovat',
cut: 'Vyjmout',
none: 'Nic nevybráno',
title: 'Schránka',
},
contextMenu: {
copy: 'Kopírovat',
cut: 'Vyjmout',
delete: 'Smazat',
download: 'Stáhnout',
info: 'Vybráno:',
open: 'Otevřit',
paste: 'Vložit',
properties: 'Vlastnosti',
rename: 'Přejmenovat',
select: 'Vybrat',
view: 'Zobrazit',
zip: 'Zabalit (Zip)',
unzip: 'Rozbalit (Zip)',
edit: 'Upravit',
audioPlay: 'Přehrát',
videoPlay: 'Přehrát',
},
info: {
directories: 'Složky:',
files: 'Soubory:',
selected: 'Vybráno:',
selectedSize: 'Velikost souborů:',
size: 'Velikost souborů:',
},
manager: {
table: {
date: 'Změněno',
folder: 'Složka',
name: 'Název',
size: 'Velikost',
type: 'Typ',
},
},
modal: {
about: {
developer: 'Vývojář',
name: 'Laravel File Manager',
title: 'O aplikaci',
version: 'Verze',
},
delete: {
noSelected: 'Nic nevybráno!',
title: 'Smazat',
},
newFile: {
fieldName: 'Název souboru',
fieldFeedback: 'Soubor již existuje!',
title: 'Vytvořit nový soubor',
},
newFolder: {
fieldName: 'Název složky',
fieldFeedback: 'Složka již existuje!',
title: 'Vytvořit novou složku',
},
preview: {
title: 'Náhled',
},
properties: {
disk: 'Disk',
modified: 'Změněno',
name: 'Název',
path: 'Cesta',
size: 'Velikost',
title: 'Vlastnosti',
type: 'Typ',
url: 'URL',
access: 'Přístup',
access_0: 'Přístup odepřen',
access_1: 'Pouze ke čtení',
access_2: 'Čtení a zápis',
},
rename: {
directoryExist: 'Složka již existuje',
fieldName: 'Vložte nové jméno',
fieldFeedback: 'Neplatné jméno',
fileExist: 'Soubor již existuje',
title: 'Přejmenovat',
},
status: {
noErrors: 'Žádná chyba!',
title: 'Stav',
},
upload: {
ifExist: 'Pokud soubor již existuje:',
noSelected: 'Nevybrány žádné soubory!',
overwrite: 'Přepsat!',
selected: 'Vybráno:',
size: 'Velikost:',
skip: 'Přeskočit',
title: 'Nahrát soubory',
},
editor: {
title: 'Editor',
},
audioPlayer: {
title: 'Audio přehrávač',
},
videoPlayer: {
title: 'Video přehrávač',
},
zip: {
title: 'Vytvořit archiv',
fieldName: 'Název archivu',
fieldFeedback: 'Archiv již existuje!',
},
unzip: {
title: 'Rozbalit archiv',
fieldName: 'Název složky',
fieldRadioName: 'Rozbalit do:',
fieldRadio1: 'Do aktuální složky',
fieldRadio2: 'Do nové složky',
fieldFeedback: 'Složka již existuje!',
warning: 'Pozor! Pokud se jména shodují, budou soubory přepsány!',
},
cropper: {
title: 'Oříznutí',
apply: 'Aplikovat',
reset: 'Obnovit',
save: 'Uložit',
},
},
notifications: {
cutToClipboard: 'Vyjmuto do schránky!',
copyToClipboard: 'Zkopírováno do schránky!',
},
response: {
noConfig: 'Konfigurace nebyla nalezena!',
notFound: 'Nenalezeno!',
diskNotFound: 'Disk nebyla nalezen!',
pathNotFound: 'Cesta nebyla nalezena!',
diskSelected: 'Disk byl vybrán!',
// files
fileExist: 'Soubor již existuje!',
fileCreated: 'Soubor byl vytvořen!',
fileUpdated: 'Soubor byl aktualizován!',
fileNotFound: 'Soubor nebyl nalezen!',
// directories
dirExist: 'Složka již existuje!',
dirCreated: 'Složka byla vytvořena!',
dirNotFound: 'Složka nebyla nalezena',
// actions
uploaded: 'Všechny soubory byly nahrány!',
notAllUploaded: 'Některé soubory nebyly nahrány!',
delNotFound: 'Některé položky nebyly nalezeny!',
deleted: 'Smazáno!',
renamed: 'Přejmenováno!',
copied: 'Úspěšně zkopírováno!',
// zip
zipError: 'Chyba při vytváření archivu!',
// acl
aclError: 'Přístup odepřen!',
},
};
export default cs;
/**
* German translate
* @type Object
*/
const de = {
btn: {
about: 'Über',
back: 'Zurück',
cancel: 'Abbrechen',
clear: 'Leeren',
copy: 'Kopieren',
cut: 'Ausschneiden',
delete: 'Löschen',
edit: 'Bearbeiten',
forward: 'Weiter',
folder: 'Neuer Order',
file: 'Neue Datei',
fullScreen: 'Vollbildschirm',
grid: 'Raster',
paste: 'Einfügen',
refresh: 'Neu laden',
submit: 'Bestätigen',
table: 'Detailansicht',
upload: 'Hochladen',
uploadSelect: 'Auswählen',
hidden: ' Versteckte Dateien',
},
clipboard: {
actionType: 'Type',
copy: 'Kopieren',
cut: 'Ausschneiden',
none: 'Nichts ausgewählt',
title: 'Zwischenablage',
},
contextMenu: {
copy: 'Kopieren',
cut: 'Ausschneiden',
delete: 'Löschen',
download: 'Herunterladen',
info: 'Ausgewählt:',
open: 'Öffnen',
paste: 'Einfügen',
properties: 'Einstellungen',
rename: 'Umbenennen',
select: 'Wählen',
view: 'Vorschau',
zip: 'Zip',
unzip: 'Unzip',
edit: 'Bearbeiten',
audioPlay: 'Abspielen',
videoPlay: 'Abspielen',
},
info: {
directories: 'Ordner:',
files: 'Dateien:',
selected: 'Ausgewählt:',
selectedSize: 'Dateigröße:',
size: 'Dateigröße:',
},
manager: {
table: {
date: 'Datum',
folder: 'Ordner',
name: 'Name',
size: 'Größe',
type: 'Type',
},
},
modal: {
about: {
developer: 'Entwickler',
name: 'Laravel File Manager',
title: 'Über',
version: 'Version',
},
delete: {
noSelected: 'Nichts ausgewählt!',
title: 'Löschen',
},
newFile: {
fieldName: 'Dateiname',
fieldFeedback: 'Datei existiert!',
title: 'Neue Datei erstellen',
},
newFolder: {
fieldName: 'Ordnername',
fieldFeedback: 'Ordner existiert!',
title: 'Neuen Ordner erstellen',
},
preview: {
title: 'Vorschau',
},
properties: {
disk: 'Festplatte',
modified: 'Geändert',
name: 'Name',
path: 'Pfad',
size: 'Größe',
title: 'Eigenschaften',
type: 'Type',
url: 'URL',
access: 'Zugang',
access_0: 'Zugriff verweigert',
access_1: 'Nur Lesezugriff',
access_2: 'Lesen- und Schreibenzugriff',
},
rename: {
directoryExist: 'Verzeichnis ist vorhanden',
fieldName: 'Neuen Namen eingeben',
fieldFeedback: 'Ungültiger Name',
fileExist: 'Datei ist vorhanden',
title: 'Umbenennen',
},
status: {
noErrors: 'Keine Fehler!',
title: 'Status',
},
upload: {
ifExist: 'Datei existiert:',
noSelected: 'Keine Dateien selektiert!',
overwrite: 'Überschreiben!',
selected: 'Ausgewählt:',
size: 'Größe:',
skip: 'Überspringen',
title: 'Hochladen von Dateien',
},
editor: {
title: 'Editor',
},
audioPlayer: {
title: 'Audio-Player',
},
videoPlayer: {
title: 'Video-Player',
},
zip: {
title: 'Archiv erzeugen',
fieldName: 'Archiv Name',
fieldFeedback: 'Archiv existiert!',
},
unzip: {
title: 'Archiv entpacken',
fieldName: 'Ordnername',
fieldRadioName: 'Extrahieren in:',
fieldRadio1: 'Zum aktuellen Verzeichnis',
fieldRadio2: 'In einem neuen Ordner',
fieldFeedback: 'Ordner ist vorhanden!',
warning: 'Achtung! Wenn die Namen übereinstimmen, werden die Dateien überschrieben!',
},
cropper: {
title: 'Beschneiden',
apply: 'Übernehmen',
reset: 'Zurücksetzen',
save: 'Speichern',
},
},
notifications: {
cutToClipboard: 'Ausgeschnitten in die Zwischenablage!',
copyToClipboard: 'Kopiert in die Zwischenablage!',
},
response: {
noConfig: 'Konfiguration nicht gefunden!',
notFound: 'Nicht gefunden!',
diskNotFound: 'Festplatte nicht gefunden!',
pathNotFound: 'Pfad nicht gefunden!',
diskSelected: 'Festplatte ausgewählt!',
// files
fileExist: 'Datei existiert bereits!',
fileCreated: 'Datei erstellt!',
fileUpdated: 'Datei wurde aktualisiert!',
fileNotFound: 'Datei nicht gefunden!',
// directories
dirExist: 'Ordner existiert bereits!',
dirCreated: 'Ordner angelegt!',
dirNotFound: 'Ordner nicht gefunden',
// actions
uploaded: 'Alle Dateien wurden hochgeladen!',
notAllUploaded: 'Einige Dateien wurden nicht hochgeladen!',
delNotFound: 'Einige Dateien wurden nicht gefunden!',
deleted: 'Gelöscht!',
renamed: 'Umbenannt!',
copied: 'Erfolgreich kopiert!',
// zip
zipError: 'Fehler bei der Erstellung des Archivs!',
// acl
aclError: 'Zugriff verweigert!',
},
};
export default de;
/**
* English translate
* @type Object
*/
const en = {
btn: {
about: 'About',
back: 'Back',
cancel: 'Cancel',
clear: 'Clear',
copy: 'Copy',
cut: 'Cut',
delete: 'Delete',
edit: 'Edit',
forward: 'Forward',
folder: 'New folder',
file: 'New file',
fullScreen: 'Full screen',
grid: 'Grid',
paste: 'Paste',
refresh: 'Refresh',
submit: 'Submit',
table: 'Table',
upload: 'Upload',
uploadSelect: 'Select files',
hidden: ' Hidden files',
},
clipboard: {
actionType: 'Type',
copy: 'Copy',
cut: 'Cut',
none: 'Nothing selected',
title: 'Clipboard',
},
contextMenu: {
copy: 'Copy',
cut: 'Cut',
delete: 'Delete',
download: 'Download',
info: 'Selected:',
open: 'Open',
paste: 'Paste',
properties: 'Properties',
rename: 'Rename',
select: 'Select',
view: 'View',
zip: 'Zip',
unzip: 'Unzip',
edit: 'Edit',
audioPlay: 'Play',
videoPlay: 'Play',
},
info: {
directories: 'Folders:',
files: 'Files:',
selected: 'Selected:',
selectedSize: 'Files size:',
size: 'Files size:',
},
manager: {
table: {
date: 'Date',
folder: 'Folder',
name: 'Name',
size: 'Size',
type: 'Type',
},
},
modal: {
about: {
developer: 'Developer',
name: 'Laravel File Manager',
title: 'About',
version: 'Version',
},
delete: {
noSelected: 'Nothing selected!',
title: 'Delete',
},
newFile: {
fieldName: 'File name',
fieldFeedback: 'File exists!',
title: 'Create new file',
},
newFolder: {
fieldName: 'Folder name',
fieldFeedback: 'Folder exists!',
title: 'Create new folder',
},
preview: {
title: 'Preview',
},
properties: {
disk: 'Disk',
modified: 'Modified',
name: 'Name',
path: 'Path',
size: 'Size',
title: 'Properties',
type: 'Type',
url: 'URL',
access: 'Access',
access_0: 'Access denied',
access_1: 'Only Read',
access_2: 'Read and Write',
},
rename: {
directoryExist: 'Directory exists',
fieldName: 'Enter new name',
fieldFeedback: 'Invalid name',
fileExist: 'File exists',
title: 'Rename',
},
status: {
noErrors: 'No errors!',
title: 'Status',
},
upload: {
ifExist: 'If file exist:',
noSelected: 'No files selected!',
overwrite: 'Overwrite!',
selected: 'Selected:',
size: 'Size:',
skip: 'Skip',
title: 'Upload files',
},
editor: {
title: 'Editor',
},
audioPlayer: {
title: 'Audio player',
},
videoPlayer: {
title: 'Video player',
},
zip: {
title: 'Create archive',
fieldName: 'Archive name',
fieldFeedback: 'Archive exists!',
},
unzip: {
title: 'Unpack archive',
fieldName: 'Folder name',
fieldRadioName: 'Extract to:',
fieldRadio1: 'To current folder',
fieldRadio2: 'In a new folder',
fieldFeedback: 'Folder exists!',
warning: 'Attention! If the names match, the files will be overwritten!',
},
cropper: {
title: 'Cropping',
apply: 'Apply',
reset: 'Reset',
save: 'Save',
},
},
notifications: {
cutToClipboard: 'Cut to clipboard!',
copyToClipboard: 'Copied to clipboard!',
},
response: {
noConfig: 'Config not found!',
notFound: 'Not found!',
diskNotFound: 'Disk not found!',
pathNotFound: 'Path not found!',
diskSelected: 'Disk selected!',
// files
fileExist: 'File already exists!',
fileCreated: 'File created!',
fileUpdated: 'File updated!',
fileNotFound: 'File not found!',
// directories
dirExist: 'Directory already exists!',
dirCreated: 'Directory created!',
dirNotFound: 'Directory not found',
// actions
uploaded: 'All files uploaded!',
notAllUploaded: 'Some files weren\'t uploaded!',
delNotFound: 'Some items weren\'t founded!',
deleted: 'Deleted!',
renamed: 'Renamed!',
copied: 'Copied successfully!',
// zip
zipError: 'Error creating archive!',
// acl
aclError: 'Access denied!',
},
};
export default en;
/**
* Spanish translate
* Marc Garcia Torrent - https://github.com/mgarcia96
* @type Object
*/
const es = {
btn: {
about: 'Acerca de',
back: 'Atras',
cancel: 'Cancelar',
clear: 'Limpiar',
copy: 'Copiar',
cut: 'Cortar',
delete: 'Eliminar',
edit: 'Editar',
forward: 'Siguiente',
folder: 'Nueva carpeta',
file: 'Crear archivo',
fullScreen: 'Pantalla completa',
grid: 'Cuadrícula',
paste: 'Pegar',
refresh: 'Actualizar',
submit: 'Guardar',
table: 'Tabla',
upload: 'Subir',
uploadSelect: 'Seleccionar archivos',
hidden: ' Archivos ocultos',
},
clipboard: {
actionType: 'Tipo',
copy: 'Copiar',
cut: 'Cortar',
none: 'Nada seleccionado',
title: 'Portapapeles',
},
contextMenu: {
copy: 'Copiar',
cut: 'Cortar',
delete: 'Eliminar',
download: 'Descargar',
info: 'Seleccionar:',
open: 'Abrir',
paste: 'Pegar',
properties: 'Propiedades',
rename: 'Renombrar',
select: 'Seleccionar',
view: 'Vista',
zip: 'Zip',
unzip: 'Unzip',
edit: 'Editar',
audioPlay: 'Play',
videoPlay: 'Play',
},
info: {
directories: 'Carpetas:',
files: 'Archivos:',
selected: 'Seleccionar:',
selectedSize: 'Tamaño archivos:',
size: 'Tamaño archivos:',
},
manager: {
table: {
date: 'Fecha',
folder: 'Carpeta',
name: 'Nombre',
size: 'Tamaño',
type: 'Tipo',
},
},
modal: {
about: {
developer: 'Developer',
name: 'Laravel File Manager',
title: 'About',
version: 'Version',
},
delete: {
noSelected: 'Nada seleccionado',
title: 'Eliminar',
},
newFile: {
fieldName: 'Nombre del archivo',
fieldFeedback: 'El archivo ya existe',
title: 'Crear nuevo archivo',
},
newFolder: {
fieldName: 'Nombre de la carpeta',
fieldFeedback: 'La carpeta ya existe',
title: 'Crear nueva carpeta',
},
preview: {
title: 'Preview',
},
properties: {
disk: 'Disk',
modified: 'Modificado',
name: 'Nombre',
path: 'Path',
size: 'Tamaño',
title: 'Propiedades',
type: 'Tipo',
url: 'URL',
access: 'Acceso',
access_0: 'Access denied',
access_1: 'Only Read',
access_2: 'Read and Write',
},
rename: {
directoryExist: 'Ya existe el directorio',
fieldName: 'Nuevo nombre',
fieldFeedback: 'Nombre invalido',
fileExist: 'Ya existe el archivo',
title: 'Renombrar',
},
status: {
noErrors: 'No errors!',
title: 'Status',
},
upload: {
ifExist: 'Si el archivo ya existe:',
noSelected: 'No has seleccionado nada!',
overwrite: 'Sobreescribir',
selected: 'Seleccionar:',
size: 'Size:',
skip: 'Omitir',
title: 'Subir archivos',
},
editor: {
title: 'Editor',
},
audioPlayer: {
title: 'Audio player',
},
videoPlayer: {
title: 'Video player',
},
zip: {
title: 'Crear archivo',
fieldName: 'Nombre del archivo',
fieldFeedback: 'Ya existe!',
},
unzip: {
title: 'Descomprimir',
fieldName: 'Nombre del directorio',
fieldRadioName: 'Extraer en:',
fieldRadio1: 'Carpeta actual',
fieldRadio2: 'Nueva carpeta',
fieldFeedback: 'Carpeta existente!',
warning: 'Attention! If the names match, the files will be overwritten!',
},
cropper: {
title: 'Cropping',
apply: 'Aceptar',
reset: 'Reset',
save: 'Guardar',
},
},
notifications: {
cutToClipboard: 'Copiado!',
copyToClipboard: 'Copiado!',
},
// todo - need to translate
response: {
noConfig: 'Configuración no encontrada!',
notFound: 'Extraviado!',
diskNotFound: 'Disco no encontrado!',
pathNotFound: 'Camino no encontrado!',
diskSelected: 'Disco seleccionado!',
// files
fileExist: 'El archivo ya existe!',
fileCreated: 'Archivo creado!',
fileUpdated: 'Archivo actualizado!',
fileNotFound: 'Archivo no encontrado!',
// directories
dirExist: 'El directorio ya existe!',
dirCreated: 'Directorio creado!',
dirNotFound: 'Directorio no encontrado',
// actions
uploaded: 'Todos los archivos cargados!',
notAllUploaded: 'Algunos archivos no fueron subidos!',
delNotFound: 'Algunos artículos no fueron encontrados!',
deleted: 'Eliminado!',
renamed: 'Renombrado!',
copied: 'Copiado exitosamente!',
// zip
zipError: 'Error al crear archivo!',
// acl
aclError: 'Acceso denegado!',
},
};
export default es;
/**
* Farsi translate
* vahidalvandi
* @type Object
*/
const fa = {
btn: {
about: 'درباره',
back: 'عقب',
cancel: 'لغو',
clear: 'پاک کردن',
copy: 'رونوشت',
cut: 'برش',
delete: 'حذف',
edit: 'ویرایش',
forward: 'ارسال به دیگری',
folder: 'پوشه جدید',
file: 'فایل جدید',
fullScreen: 'تمام صفحه',
grid: 'شبکه',
paste: 'جانمایی/چسباندن/جاگذاری',
refresh: 'تازه کردن صفحه',
submit: 'تایید و ارسال',
table: 'جدول',
upload: 'بارگذاری',
uploadSelect: 'انتخاب فایل',
hidden: ' فایل های مخفی',
},
clipboard: {
actionType: 'نوع',
copy: 'رونوشت',
cut: 'برش',
none: 'چیزی انتخاب نشده است',
title: 'کلیپ بورد',
},
contextMenu: {
copy: 'رونوشت',
cut: 'برش',
delete: 'حذف',
download: 'دانلود',
info: 'انتخاب شده:',
open: 'باز کردن',
paste: 'جاگذاری',
properties: 'ویژگی ها',
rename: 'تغییر نام',
select: 'انتخاب',
view: 'مشاهده',
zip: 'فشرده کردن',
unzip: 'از حالت فشرده خارج کردن',
edit: 'ویرایش',
audioPlay: 'پخش',
videoPlay: 'نمایش',
},
info: {
directories: 'پوشه ها:',
files: 'فایل ها:',
selected: 'انتخاب شده ها:',
selectedSize: 'اندازه فایل ها:',
size: 'اندازه فایل ها:',
},
manager: {
table: {
date: 'تاریخ',
folder: 'پوشه',
name: 'نام',
size: 'اندازه',
type: 'نوع',
},
},
modal: {
about: {
developer: 'توسعه دهنده',
name: 'مدیریت فایل',
title: 'درباره',
version: 'نسخه',
},
delete: {
noSelected: 'چیزی انتخاب نشده است',
title: 'حذف',
},
newFile: {
fieldName: 'نام فایل',
fieldFeedback: 'فایل وجود دارد!',
title: 'فایل جدید ایجاد کنید',
},
newFolder: {
fieldName: 'نام پوشه',
fieldFeedback: 'پوشه وجود دارد!',
title: 'پوشه جدید ایجاد کنید',
},
preview: {
title: 'پیش نمایش',
},
properties: {
disk: 'Disk',
modified: 'اصلاح شده',
name: 'نام',
path: 'مسیر',
size: 'اندازه',
title: 'ویژگی ها',
type: 'نوع',
url: 'آدرس اینترنتی',
access: 'دسترسی',
access_0: 'دسترسی امکان پذیر نیست',
access_1: 'فقط خواندن',
access_2: 'خواندن و نوشتن',
},
rename: {
directoryExist: 'فهرست وجود دارد',
fieldName: 'نام جدید را وارد نمایید',
fieldFeedback: 'نام نامعتبر است',
fileExist: 'فایل وجود دارد',
title: 'تغییر نام',
},
status: {
noErrors: 'خطایی وجود ندارد!',
title: 'وضعیت',
},
upload: {
ifExist: 'اگر فایل وجود دارد:',
noSelected: 'هیچ فایلی انتخاب نشده است!',
overwrite: 'بازنویسی!',
selected: 'انتخاب شده ها/انتخاب شده است:',
size: 'اندازه:',
skip: 'رد شدن',
title: 'بارگزاری فایل ها',
},
editor: {
title: 'ویرایشگر',
},
audioPlayer: {
title: 'پخش کننده فایل صوتی',
},
videoPlayer: {
title: 'نمایش دهنده ویدیو',
},
zip: {
title: 'ایجاد بایگانی',
fieldName: 'نام بایگانی',
fieldFeedback: 'بایگانی وجود دارد',
},
unzip: {
title: 'باز کردن بایگانی',
fieldName: 'نام پوشه',
fieldRadioName: 'استخراج شود به:',
fieldRadio1: 'به پوشه فعلی',
fieldRadio2: 'در یک پوشه جدید',
fieldFeedback: 'پوشه وجود دارد!',
warning: 'توجه! اگر نام ها تکراری باشند، فایل های قدیمی با فایل های جدید جایگزین خواهند شد',
},
cropper: {
title: 'کوچک کردن',
apply: 'اجرا',
reset: 'تنظیم مجدد',
save: 'ذخیره',
},
},
notifications: {
cutToClipboard: 'برش یه کلیپ بورد!',
copyToClipboard: 'رونوشت به کلیپ بورد!',
},
response: {
noConfig: 'پیکربندی یافت نشد',
notFound: 'یافت نشد',
diskNotFound: 'دیسک یافت نشد !',
pathNotFound: 'مسیر یافت نشد!',
diskSelected: 'دیسک انتخاب شد !',
// files
fileExist: ' در حال حاضر فایل مورد نظر وجود دارد!',
fileCreated: 'فایل ایجاد شد!',
fileUpdated: 'فایل بروزرسانی شد!',
fileNotFound: 'فایل یافت نشد!',
// directories
dirExist: 'در حال حاضر پیکربندی مورد نظر وجود دارد!',
dirCreated: 'پیکربندی ایجاد شد!',
dirNotFound: 'پیکربندی یافت نشد',
// actions
uploaded: 'همه فایل ها بارگذاری شده اند!',
notAllUploaded: 'برخی از فایل ها بارگذاری نشده اند!',
delNotFound: 'برخی از بخش ها یافت نشد!',
deleted: 'حذف شد!',
renamed: 'تغییر نام یافت!',
copied: 'رونوشت با موفقیت انجام شد!',
// zip
zipError: 'خطای ایجاد بایگانی! zip',
// acl
aclError: 'دسترسی امکان پذیر نیست!',
},
};
export default fa;
/**
* French translate
* @type Object
*/
const fr = {
btn: {
about: 'À propos',
back: 'Retour',
cancel: 'Annuler',
clear: 'Effacer',
copy: 'Copier',
cut: 'Couper',
delete: 'Supprimer',
edit: 'Modifier',
forward: 'Suivant',
folder: 'Nouveau dossier',
file: 'Nouveau fichier',
fullScreen: 'Plein écran',
grid: 'Grille',
paste: 'Coller',
refresh: 'Rafraîchir',
submit: 'Envoyer',
table: 'Tableau',
upload: 'Télécharger',
uploadSelect: 'Sélectionner fichiers',
hidden: ' Masquer fichiers',
},
clipboard: {
actionType: 'Type',
copy: 'Copier',
cut: 'Coller',
none: 'Aucune sélection',
title: 'Clipboard',
},
contextMenu: {
copy: 'Copier',
cut: 'Coller',
delete: 'Supprimer',
download: 'Télécharger',
info: 'Sélectionné:',
open: 'Ouvrir',
paste: 'Coller',
properties: 'Propriétés',
rename: 'Renommer',
select: 'Sélectionner',
view: 'Voir',
zip: 'Zipper',
unzip: 'Dézipper',
edit: 'Modifier',
audioPlay: 'Lire',
videoPlay: 'Lire',
},
info: {
directories: 'Dossiers:',
files: 'Fichiers:',
selected: 'Sélectionné:',
selectedSize: 'Taille fichiers:',
size: 'Taille fichiers:',
},
manager: {
table: {
date: 'Date',
folder: 'Dossier',
name: 'Nom',
size: 'Taille',
type: 'Type',
},
},
modal: {
about: {
developer: 'Développeur',
name: 'Laravel File Manager',
title: 'À propos',
version: 'Version',
},
delete: {
noSelected: 'Aucune sélection!',
title: 'Supprimer',
},
newFile: {
fieldName: 'Nom du fichier',
fieldFeedback: 'Ce fichier existe!',
title: 'Créer un fichier',
},
newFolder: {
fieldName: 'Nom du dossier',
fieldFeedback: 'Ce dossier existe!',
title: 'Créer un dossier',
},
preview: {
title: 'Prévisualisation',
},
properties: {
disk: 'Disque',
modified: 'Modifié',
name: 'Nom',
path: 'Chemin',
size: 'Taille',
title: 'Propriétés',
type: 'Type',
url: 'URL',
access: 'Accès',
access_0: 'Accès refusé',
access_1: 'Lecture seul',
access_2: 'Lecture/écriture',
},
rename: {
directoryExist: 'Dossier existant',
fieldName: 'Entrer un nom',
fieldFeedback: 'Nom invalide',
fileExist: 'Fichier existant',
title: 'Renommer',
},
status: {
noErrors: 'Aucune erreurs!',
title: 'Statut',
},
upload: {
ifExist: 'Si le fichier existe:',
noSelected: 'Aucun fichier sélectionné!',
overwrite: 'Écraser!',
selected: 'Sélectionné:',
size: 'Taille:',
skip: 'Passer',
title: 'Télécharger fichiers',
},
editor: {
title: 'Editeur',
},
audioPlayer: {
title: 'Lecteur audio',
},
videoPlayer: {
title: 'Lecteur video',
},
zip: {
title: 'Créer une archive',
fieldName: 'Nom archive',
fieldFeedback: 'Archive existante!',
},
unzip: {
title: 'Extraite l\'archive',
fieldName: 'Nom du dossier',
fieldRadioName: 'Extraire vers:',
fieldRadio1: 'Dossier actuel',
fieldRadio2: 'Dans un nouveau dossier',
fieldFeedback: 'Dossier existant!',
warning: 'Attention! Si le nom correspond, les fichiers seront écrasés!',
},
cropper: {
title: 'Recadrer',
apply: 'Appliquer',
reset: 'Réinitialisé',
save: 'Sauvegarder',
},
},
notifications: {
cutToClipboard: 'Coller dans le presse-papier!',
copyToClipboard: 'Copied dans le presse-papier!',
},
response: {
noConfig: 'Configuration introuvable!',
notFound: 'Introuvable!',
diskNotFound: 'Disque introuvable!',
pathNotFound: 'Chemin introuvable!',
diskSelected: 'Disque sélectionné!',
// files
fileExist: 'Fichier existant!',
fileCreated: 'Fichier créé!',
fileUpdated: 'Fichier téléchargé!',
fileNotFound: 'Fichier introuvable!',
// directories
dirExist: 'Dossier existant!',
dirCreated: 'Dossier créé!',
dirNotFound: 'Dossier introuvable',
// actions
uploaded: 'Tous les fichiers ont été téléchargés!',
notAllUploaded: 'Certains fichiers n\'ont pas été téléchargés!',
delNotFound: 'Certains éléments n\'ont pas été trouvés!',
deleted: 'Supprimé!',
renamed: 'Renommé!',
copied: 'Copié!',
// zip
zipError: 'Erreur dans la création de l\'archive!',
// acl
aclError: 'Accès refusé!',
},
};
export default fr;
/**
* Italian translate
* Ezio
* @type Object
*/
const it = {
btn: {
about: 'Informazioni',
back: 'Indietro',
cancel: 'Annulla',
clear: 'Pulisci',
copy: 'Copia',
cut: 'Taglia',
delete: 'Elimina',
edit: 'Modifica',
forward: 'Inoltra',
folder: 'Nuova Cartella',
file: 'Nuovo File',
fullScreen: 'Visualizzazione a schermo intero',
grid: 'Griglia',
paste: 'Incolla',
refresh: 'Ricarica',
submit: 'Conferma',
table: 'Tabella',
upload: 'Upload',
uploadSelect: 'Seleziona files',
hidden: ' Files Nascosti',
},
clipboard: {
actionType: 'Tipo',
copy: 'Copia',
cut: 'Taglia',
none: 'Nessun elemento selezionato',
title: 'Appunti',
},
contextMenu: {
copy: 'Copia',
cut: 'Taglia',
delete: 'Elimina',
download: 'Scarica',
info: 'Selezionati:',
open: 'Apri',
paste: 'Incolla',
properties: 'Proprietà',
rename: 'Rinomina',
select: 'Seleziona',
view: 'Anteprima',
zip: 'Zip',
unzip: 'Estrai zip',
edit: 'Modifica',
audioPlay: 'Play',
videoPlay: 'Play',
},
info: {
directories: 'Cartelle:',
files: 'Files:',
selected: 'Selezionati:',
selectedSize: 'Dimensione files:',
size: 'Dimensione files:',
},
manager: {
table: {
date: 'Data',
folder: 'Cartella',
name: 'Nome',
size: 'Dim.',
type: 'Tipo',
},
},
modal: {
about: {
developer: 'Developer',
name: 'Laravel File Manager',
title: 'Informazioni',
version: 'Versione',
},
delete: {
noSelected: 'Nessuna selezione!',
title: 'Elimina',
},
newFile: {
fieldName: 'Nome del file',
fieldFeedback: 'Il file esiste!',
title: 'Crea nuovo file',
},
newFolder: {
fieldName: 'Nome cartella',
fieldFeedback: 'La cartella esiste!',
title: 'Crea nuova cartella',
},
preview: {
title: 'Anteprima',
},
properties: {
disk: 'Disco',
modified: 'Mod.',
name: 'Nome',
path: 'Percorso',
size: 'Dim.',
title: 'Proprietà',
type: 'Tipo',
url: 'URL',
access: 'Accesso',
access_0: 'Accesso negato',
access_1: 'Sola lettura',
access_2: 'Lettura e Scrittura',
},
rename: {
directoryExist: 'La cartella esiste',
fieldName: 'Inserisci il nome',
fieldFeedback: 'Nome non valido',
fileExist: 'Il file esiste',
title: 'Rinomina',
},
status: {
noErrors: 'Nessun errore!',
title: 'Stato',
},
upload: {
ifExist: 'Il file esiste:',
noSelected: 'Nessun files selezionato!',
overwrite: 'Sovrascrivi!',
selected: 'Selezionato:',
size: 'Dim.:',
skip: 'Salta',
title: 'Carica files',
},
editor: {
title: 'Editor',
},
audioPlayer: {
title: 'Player Audio',
},
videoPlayer: {
title: 'Player Video',
},
zip: {
title: 'Crea Archivio',
fieldName: 'Nome Archivio',
fieldFeedback: 'Archivio esistente!',
},
unzip: {
title: 'Estrai archivio',
fieldName: 'Nom cartella',
fieldRadioName: 'Estrai in:',
fieldRadio1: 'Nella cartella corrente',
fieldRadio2: 'In una nuova cartella',
fieldFeedback: 'Cartella esistente!',
warning: 'Attenzione! se i nomi dei file coincidono i file presenti verranno sovrascritti!',
},
cropper: {
title: 'Ritaglia',
apply: 'Applica',
reset: 'Reset',
save: 'Salva',
},
},
notifications: {
cutToClipboard: 'Tagliato e salvato negli appunti!',
copyToClipboard: 'Copiato negli appunti!',
},
response: {
noConfig: 'File di configuraizone non trovato!',
notFound: 'Non trovato!',
diskNotFound: 'Disco non trovato!',
pathNotFound: 'Cartella non trovata!',
diskSelected: 'Disco selezionato!',
// files
fileExist: 'File già esistente!',
fileCreated: 'File creato!',
fileUpdated: 'File caricato!',
fileNotFound: 'File non trovato!',
// directories
dirExist: 'La cartella è già presente!',
dirCreated: 'Cartella creata!',
dirNotFound: 'Cartella non trovata',
// actions
uploaded: 'Tutti i file sono stati caricati!',
notAllUploaded: 'Alcuni file NON sono stati caricati!',
delNotFound: 'Alcuni elementi NON sono stati trovati!',
deleted: 'Eliminato!',
renamed: 'Rinominato!',
copied: 'Copiato con successo!',
// zip
zipError: "Errore dirante la creazione dell'archivio!",
// acl
aclError: 'Accesso negato!',
},
};
export default it;
/**
* Dutch (Netherlands) translate
* Laurens - https://github.com/Laussii078
* @type Object
*/
const nl = {
// todo - need to translate
btn: {
about: 'About',
back: 'Back',
cancel: 'Cancel',
clear: 'Clear',
copy: 'Copy',
cut: 'Cut',
delete: 'Delete',
edit: 'Edit',
forward: 'Forward',
folder: 'New folder',
file: 'New file',
fullScreen: 'Full screen',
grid: 'Grid',
paste: 'Paste',
refresh: 'Refresh',
submit: 'Submit',
table: 'Table',
upload: 'Upload',
uploadSelect: 'Select files',
hidden: ' Verborgen bestanden',
},
clipboard: {
actionType: 'Type',
copy: 'Copy',
cut: 'Cut',
none: 'Nothing selected',
title: 'Clipboard',
},
contextMenu: {
copy: 'Copy',
cut: 'Cut',
delete: 'Delete',
download: 'Download',
info: 'Selected:',
open: 'Open',
paste: 'Paste',
properties: 'Properties',
rename: 'Rename',
select: 'Select',
view: 'View',
zip: 'Zip',
unzip: 'Unzip',
edit: 'Edit',
audioPlay: 'Play',
videoPlay: 'Play',
},
info: {
directories: 'Folders:',
files: 'Files:',
selected: 'Selected:',
selectedSize: 'Files size:',
size: 'Files size:',
},
manager: {
table: {
date: 'Date',
folder: 'Folder',
name: 'Name',
size: 'Size',
type: 'Type',
},
},
modal: {
about: {
developer: 'Developer',
name: 'Laravel File Manager',
title: 'About',
version: 'Version',
},
delete: {
noSelected: 'Nothing selected!',
title: 'Delete',
},
newFile: {
fieldName: 'File name',
fieldFeedback: 'File exists!',
title: 'Create new file',
},
newFolder: {
fieldName: 'Folder name',
fieldFeedback: 'Folder exists!',
title: 'Create new folder',
},
preview: {
title: 'Preview',
},
properties: {
disk: 'Disk',
modified: 'Modified',
name: 'Name',
path: 'Path',
size: 'Size',
title: 'Properties',
type: 'Type',
url: 'URL',
access: 'Access',
access_0: 'Access denied',
access_1: 'Only Read',
access_2: 'Read and Write',
},
rename: {
directoryExist: 'Directory exists',
fieldName: 'Enter new name',
fieldFeedback: 'Invalid name',
fileExist: 'File exists',
title: 'Rename',
},
status: {
noErrors: 'No errors!',
title: 'Status',
},
upload: {
ifExist: 'If file exist:',
noSelected: 'No files selected!',
overwrite: 'Overwrite!',
selected: 'Selected:',
size: 'Size:',
skip: 'Skip',
title: 'Upload files',
},
editor: {
title: 'Editor',
},
audioPlayer: {
title: 'Audio player',
},
videoPlayer: {
title: 'Video player',
},
zip: {
title: 'Create archive',
fieldName: 'Archive name',
fieldFeedback: 'Archive exists!',
},
unzip: {
title: 'Unpack archive',
fieldName: 'Folder name',
fieldRadioName: 'Extract to:',
fieldRadio1: 'To current folder',
fieldRadio2: 'In a new folder',
fieldFeedback: 'Folder exists!',
warning: 'Attention! If the names match, the files will be overwritten!',
},
cropper: {
title: 'Cropping',
apply: 'Apply',
reset: 'Reset',
save: 'Save',
},
},
notifications: {
cutToClipboard: 'Cut to clipboard!',
copyToClipboard: 'Copied to clipboard!',
},
// todo - need to translate - end
response: {
noConfig: 'Config niet gevonden!',
notFound: 'Niet gevonden!',
diskNotFound: 'Schijf niet gevonden!',
pathNotFound: 'Pad niet gevonden!',
diskSelected: 'Schijf geselecteerd!',
// files
fileExist: 'Bestand bestaat al!',
fileCreated: 'Bestand aangemaakt!',
fileUpdated: 'Bestand bijgewerkt!',
fileNotFound: 'Bestand niet gevonden!',
// directories
dirExist: 'Folder bestaat al!',
dirCreated: 'Folder aangemaakt!',
dirNotFound: 'Folder niet gevonden',
// actions
uploaded: 'Alle bestanden geüpload!',
notAllUploaded: 'Sommige bestanden zijn niet geüpload!',
delNotFound: 'Sommige bestanden konden niet worden gevonden!',
deleted: 'Verwijderd!',
renamed: 'Hernoemd!',
copied: 'Succesvol gekopieerd!',
// zip
zipError: 'Fout bij het maken van archief!',
// acl
aclError: 'Toegang geweigerd!',
},
};
export default nl;
/**
* Polish
* @type Object
*/
const pl = {
btn: {
about: 'O Programie',
back: 'Wstecz',
cancel: 'Anuluj',
clear: 'Wyczyść',
copy: 'Kopiuj',
cut: 'Wytnij',
delete: 'Usuń',
edit: 'Edycja',
forward: 'Do przodu',
folder: 'Nowy folder',
file: 'Nowy plik',
fullScreen: 'Pełny ekran',
grid: 'Siatka',
paste: 'Wklej',
refresh: 'Odśwież',
submit: 'Zatwierdź',
table: 'Tabela',
upload: 'Wyślij plik',
uploadSelect: 'Wybierz pliki',
hidden: 'Ukryte pliki',
},
clipboard: {
actionType: 'Rodzaj',
copy: 'Kopiuj',
cut: 'Przytnij',
none: 'Nic nie zostało zaznaczone',
title: 'Schowek',
},
contextMenu: {
copy: 'Kopiuj',
cut: 'Przytnij',
delete: 'Usuń',
download: 'Pobierz',
info: 'Wybrano:',
open: 'Otwórz',
paste: 'Wklej',
properties: 'Właściwości',
rename: 'Zmień nazwę',
select: 'Wybierz',
view: 'Widok',
zip: 'Spakuj',
unzip: 'Rozpakuj',
edit: 'Edycja',
audioPlay: 'Odtwórz',
videoPlay: 'Odtwórz',
},
info: {
directories: 'Katalogi',
files: 'Pliki:',
selected: 'Wybrany:',
selectedSize: 'Rozmiar plików:',
size: 'Rozmiar plików:',
},
manager: {
table: {
date: 'Data',
folder: 'Folder',
name: 'Nazwa',
size: 'Rozmiar',
type: 'Rodzaj',
},
},
modal: {
about: {
developer: 'Deweloper',
name: 'Menedżer plików',
title: 'O',
version: 'Wersja',
},
delete: {
noSelected: 'Nic nie zostało zaznaczone!',
title: 'Usuń',
},
newFile: {
fieldName: 'Nazwa pliku',
fieldFeedback: 'Plik istnieje!',
title: 'Utwórz nowy plik',
},
newFolder: {
fieldName: 'Nazwa folderu',
fieldFeedback: 'Katalog istnieje!',
title: 'Stwórz nowy folder',
},
preview: {
title: 'Podgląd',
},
properties: {
disk: 'Dysk',
modified: 'Zmodyfikowano',
name: 'Nazwa',
path: 'Ścieżka',
size: 'Rozmiar',
title: 'Właściwości',
type: 'Rodzaj',
url: 'URL',
access: 'Dostęp',
access_0: 'Brak dostępu',
access_1: 'Tylko do odczytu',
access_2: 'Odczyt i zapis',
},
rename: {
directoryExist: 'Katalog istnieje',
fieldName: 'Wpisz nową nazwę',
fieldFeedback: 'Błędna nazwa',
fileExist: 'Plik istnieje',
title: 'Zmień nazwę',
},
status: {
noErrors: 'Bez błędów!',
title: 'Status',
},
upload: {
ifExist: 'Jeśli plik istnieje:',
noSelected: 'Nie wybrano plików!',
overwrite: 'Nadpisz',
selected: 'Wybrano:',
size: 'Rozmiar:',
skip: 'Pomiń',
title: 'Prześlij pliki',
},
editor: {
title: 'Edytor',
},
audioPlayer: {
title: 'Odtwarzacz muzyki',
},
videoPlayer: {
title: 'Odtwarzacz wideo',
},
zip: {
title: 'Utwórz archiwum',
fieldName: 'Nazwa archiwum',
fieldFeedback: 'Archiwum istnieje!',
},
unzip: {
title: 'Rozpakuj archiwum',
fieldName: 'Nazwa folderu',
fieldRadioName: 'Wypakować do:',
fieldRadio1: 'Do bieżącego folderu',
fieldRadio2: 'W nowym folderze',
fieldFeedback: 'Katalog istnieje!',
warning: 'Uwaga! Przy identycznej nazwie, pliki zostaną nadpisane!',
},
cropper: {
title: 'Przycinanie',
apply: 'Zastosuj',
reset: 'Reset',
save: 'Zapisz',
},
},
notifications: {
cutToClipboard: 'Wytnij do schowka!',
copyToClipboard: 'Skopiowane do schowka!',
},
response: {
noConfig: 'Nie znaleziono konfiguracji!',
notFound: 'Nie znaleziono!',
diskNotFound: 'Nie znaleziono dysku!',
pathNotFound: 'Ścieżka nie znaleziona!',
diskSelected: 'Dysk wybrany!',
// files
fileExist: 'Plik już istnieje!',
fileCreated: 'Plik utworzony!',
fileUpdated: 'Plik zaktualizowany!',
fileNotFound: 'Nie znaleziono pliku!',
// directories
dirExist: 'Katalog już istnieje!',
dirCreated: 'Katalog utworzony!',
dirNotFound: 'Nie znaleziono katalogu',
// actions
uploaded: 'Przesłano wszystkie pliki!',
notAllUploaded: 'Niektóre pliki nie zostały przesłane!',
delNotFound: 'Niektóre pozycje nie zostały znalezione!',
deleted: 'Usunięto!',
renamed: 'Zmieniono nazwę!',
copied: 'Skopiowano pomyślnie!',
// zip
zipError: 'Błąd podczas tworzenia archiwum!',
// acl
aclError: 'Brak dostępu!',
},
};
export default pl;
/**
* Portuguese Brazilian translate
* @type Object
*/
/* eslint camelcase: 0 */
const pt_BR = {
btn: {
about: 'Sobre',
back: 'Voltar',
cancel: 'Cancelar',
clear: 'Limpar',
copy: 'Copiar',
cut: 'Recortar',
delete: 'Apagar',
edit: 'Editar',
forward: 'Avançar',
folder: 'Nova pasta',
file: 'Novo arquivo',
fullScreen: 'Tela cheia',
grid: 'Grade',
paste: 'Colar',
refresh: 'Atualizar',
submit: 'Criar',
table: 'Tabela',
upload: 'Upload',
uploadSelect: 'Selecionar arquivos',
hidden: ' Arquivos ocultos',
},
clipboard: {
actionType: 'Formato',
copy: 'Copiar',
cut: 'Recortar',
none: 'Nada selecionado',
title: 'Área de transferência',
},
contextMenu: {
copy: 'Copiar',
cut: 'Colar',
delete: 'Apagar',
download: 'Download',
info: 'Selecionado:',
open: 'Abrir',
paste: 'Colar',
properties: 'Propriedades',
rename: 'Renomear',
select: 'Selecionar',
view: 'Visualizar',
zip: 'Compactar',
unzip: 'Descompactar',
edit: 'Editar',
audioPlay: 'Play',
videoPlay: 'Play',
},
info: {
directories: 'Pastas:',
files: 'Arquivos:',
selected: 'Selecionado:',
selectedSize: 'Tamanho dos arquivos:',
size: 'Tamanho dos arquivos:',
},
manager: {
table: {
date: 'Data',
folder: 'Pasta',
name: 'Nome',
size: 'Tamanho',
type: 'Tipo',
},
},
modal: {
about: {
developer: 'Desenvolvedor',
name: 'Laravel File Manager',
title: 'Sobre',
version: 'Versão',
},
delete: {
noSelected: 'Nada selecionado!',
title: 'Apagar',
},
newFile: {
fieldName: 'Nome do arquivo',
fieldFeedback: 'Arquivo existente!',
title: 'Criar novo arquivo',
},
newFolder: {
fieldName: 'Nome da pasta',
fieldFeedback: 'Pasta existente!',
title: 'Criar nova pasta',
},
preview: {
title: 'Visualizar',
},
properties: {
disk: 'Disco',
modified: 'Modificado',
name: 'Nome',
path: 'Caminho',
size: 'Tamanho',
title: 'Propriedades',
type: 'Tipo',
url: 'URL',
access: 'Acesso',
access_0: 'Acesso negado',
access_1: 'Apenas leitura',
access_2: 'Leitura e escrita',
},
rename: {
directoryExist: 'Pasta existente',
fieldName: 'Digite o novo nome',
fieldFeedback: 'Nome inválido',
fileExist: 'Arquivo existente',
title: 'Renomear',
},
status: {
noErrors: 'Nenhum erro!',
title: 'Status',
},
upload: {
ifExist: 'Se arquivo não existir:',
noSelected: 'Nenhum arquivo selecionado!',
overwrite: 'Substituir!',
selected: 'Selecionado:',
size: 'Tamanho:',
skip: 'Pular',
title: 'Upload de arquivos',
},
editor: {
title: 'Editor',
},
audioPlayer: {
title: 'Áudio player',
},
videoPlayer: {
title: 'Video player',
},
zip: {
title: 'Compactar arquivo',
fieldName: 'Nome do arquivo',
fieldFeedback: 'Arquivo existente!',
},
unzip: {
title: 'Descompactar arquivo',
fieldName: 'Nome da pasta',
fieldRadioName: 'Extrair para:',
fieldRadio1: 'Pasta atual',
fieldRadio2: 'Nova pasta',
fieldFeedback: 'Pasta existente!',
warning: 'Atenção! Se os nomes forem idênticos, os arquivos serão substituídos!',
},
cropper: {
title: 'Cortar',
apply: 'Aplicar',
reset: 'Resetar',
save: 'Salvar',
},
},
notifications: {
cutToClipboard: 'Recortado para área de transferência!',
copyToClipboard: 'Copiado para área de transferência!',
},
response: {
noConfig: 'Configuração não encontrada!',
notFound: 'Não encontrado!',
diskNotFound: 'Disco não encontrado!',
pathNotFound: 'Caminho não encontrado!',
diskSelected: 'Disco selecionado!',
// files
fileExist: 'Arquivo já existe!',
fileCreated: 'Arquivo criado!',
fileUpdated: 'Arquivo atualizado!',
fileNotFound: 'Arquivo não encontrado!',
// directories
dirExist: 'Pasta já existe!',
dirCreated: 'Pasta criada!',
dirNotFound: 'Pasta não encontrada',
// actions
uploaded: 'Todos os arquivo realizarm o upload!',
notAllUploaded: 'Alguns arquivos não realizaram o upload!',
delNotFound: 'Alguns itens não foram encontrados!',
deleted: 'Deletado!',
renamed: 'Renomeado!',
copied: 'Copiado com sucesso!',
// zip
zipError: 'Erro ao compactar!',
// acl
aclError: 'Acesso negado!',
},
};
export default pt_BR;
/**
* Russian translate
* @type Object
*/
const ru = {
btn: {
about: 'О программе',
back: 'Назад',
cancel: 'Отменить',
clear: 'Очистить',
copy: 'Копировать',
cut: 'Вырезать',
delete: 'Удалить',
edit: 'Редактировать',
forward: 'Вперед',
folder: 'Новая папка',
file: 'Новый файл',
fullScreen: 'На весь экран',
grid: 'Сетка',
paste: 'Вставить',
refresh: 'Обновить',
submit: 'Отправить',
table: 'Таблица',
upload: 'Загрузить',
uploadSelect: 'Выбрать файлы',
hidden: 'Скрытые файлы',
},
clipboard: {
actionType: 'Тип операции',
copy: 'Копировать',
cut: 'Вырезать',
none: 'Ничего не выбрано',
title: 'Буфер обмена',
},
contextMenu: {
copy: 'Копировать',
cut: 'Вырезать',
delete: 'Удалить',
download: 'Скачать',
info: 'Выбрано:',
open: 'Открыть',
paste: 'Вставить',
properties: 'Свойства',
rename: 'Переименовать',
select: 'Выбрать',
view: 'Просмотр',
zip: 'Архивировать',
unzip: 'Разархивировать',
edit: 'Редактировать',
audioPlay: 'Воспроизвести',
videoPlay: 'Воспроизвести',
},
info: {
directories: 'Папок:',
files: 'Файлов:',
selected: 'Выбрано:',
selectedSize: 'Размер:',
size: 'Размер файлов:',
},
manager: {
table: {
date: 'Дата',
folder: 'Папка',
name: 'Имя',
size: 'Размер',
type: 'Тип',
},
},
modal: {
about: {
developer: 'Разработчик',
name: 'Laravel File Manager',
title: 'О программе',
version: 'Версия',
},
delete: {
noSelected: 'Ничего не выбрано!',
title: 'Удалить',
},
newFile: {
fieldName: 'Имя файла',
fieldFeedback: 'Такой файл уже существует!',
title: 'Создать новый файл',
},
newFolder: {
fieldName: 'Имя папки',
fieldFeedback: 'Такакя папка уже существует!',
title: 'Создать новую папку',
},
preview: {
title: 'Предпросмотр',
},
properties: {
disk: 'Диск',
modified: 'Изменен',
name: 'Имя',
path: 'Путь',
size: 'Размер',
title: 'Свойства',
type: 'Тип',
url: 'URL',
access: 'Доступ',
access_0: 'Нет доступа',
access_1: 'Только чтение',
access_2: 'Чтение и Запись',
},
rename: {
directoryExist: 'Папка существует',
fieldName: 'Введите новое имя',
fieldFeedback: 'Некорректное имя',
fileExist: 'Файл существует',
title: 'Переименовать',
},
status: {
noErrors: 'Ошибок нет!',
title: 'Состояние',
},
upload: {
ifExist: 'Если файл существует:',
noSelected: 'Ни одного файла не выбрано!',
overwrite: 'Перезаписать!',
selected: 'Выбрано:',
size: 'Размер:',
skip: 'Пропустить',
title: 'Загрузить файлы',
},
editor: {
title: 'Редактор',
},
audioPlayer: {
title: 'Аудиоплеер',
},
videoPlayer: {
title: 'Видеоплеер',
},
zip: {
title: 'Создать архив',
fieldName: 'Имя архива',
fieldFeedback: 'Такой файл уже существует!',
},
unzip: {
title: 'Распаковать архив',
fieldName: 'Имя папки',
fieldRadioName: 'Извлечь в:',
fieldRadio1: 'В текущую папку',
fieldRadio2: 'В новую папку',
fieldFeedback: 'Папка существует!',
warning: 'Внимание! При совпадении имен файлы будут перезаписаны!',
},
cropper: {
title: 'Обрезка',
apply: 'Применить',
reset: 'Сбросить',
save: 'Сохранить',
},
},
notifications: {
cutToClipboard: 'Вырезано!',
copyToClipboard: 'Скопировано!',
},
response: {
noConfig: 'Конфигурация не найдена!',
notFound: 'Не найдено!',
diskNotFound: 'Диск не найден!',
pathNotFound: 'Путь не существует!',
diskSelected: 'Диск выбран!',
// files
fileExist: 'Файл существует!',
fileCreated: 'Файл создан!',
fileUpdated: 'Файл обновлен!',
fileNotFound: 'Файл не найден!',
// directories
dirExist: 'Директория существует!',
dirCreated: 'Директория создана!',
dirNotFound: 'Директория не найдена',
// actions
uploaded: 'Все файлы загружены!',
notAllUploaded: 'Не все файлы загружены!',
delNotFound: 'Не все элементы найдены!',
deleted: 'Удалено!',
renamed: 'Переименовано!',
copied: 'Скопировано!',
// zip
zipError: 'Ошибка создания архива!',
// acl
aclError: 'В доступе отказано!',
},
};
export default ru;
/**
* Serbian translate
* Aleksandar Stevanović - aleks989
* @type Object
*/
const sr = {
btn: {
about: 'O Nama',
back: 'Nazad',
cancel: 'Otkaži',
clear: 'Očisti',
copy: 'Kopiraj',
cut: 'Iseci',
delete: 'Obriši',
edit: 'Izmeni',
forward: 'Napred',
folder: 'Novi direktorijum',
file: 'Nova datoteka',
fullScreen: 'Ceo ekran',
grid: 'Mrežasti prikaz',
paste: 'Nalepi',
refresh: 'Osveži',
submit: 'Potvrdi',
table: 'Tabela',
upload: 'Upload',
uploadSelect: 'Izaberi datoteke',
hidden: ' Skrivene datoteke',
},
clipboard: {
actionType: 'Tip operacije',
copy: 'Kopiraj',
cut: 'Iseci',
none: 'Ništa niste izabrali!',
title: 'Clipboard',
},
contextMenu: {
copy: 'Kopiraj',
cut: 'Iseci',
delete: 'Obriši',
download: 'Preuzimanje',
info: 'Izabrano:',
open: 'Otvori',
paste: 'Nalepi',
properties: 'Svojstva',
rename: 'Preimenuj',
select: 'Izaberi',
view: 'Pregledaj',
zip: 'Arhiviraj',
unzip: 'Izbaci iz arhive',
edit: 'Izmeni',
audioPlay: 'Reprodukuj',
videoPlay: 'Reprodukuj',
},
info: {
directories: 'Direktorijumi:',
files: 'Datoteke:',
selected: 'Izabrano:',
selectedSize: 'Veličina fajla:',
size: 'Veličina fajla:',
},
manager: {
table: {
date: 'Datum',
folder: 'Datoteka',
name: 'Naziv',
size: 'Veličina',
type: 'Vrsta',
},
},
modal: {
about: {
developer: 'Razvio',
name: 'Laravel File Manager',
title: 'O Nama',
version: 'Verzija',
},
delete: {
noSelected: 'Ništa niste izabrali!',
title: 'Obriši',
},
newFile: {
fieldName: 'Naziv datoteke',
fieldFeedback: 'Datoteka već postoji!',
title: 'Kreiraj novu datoteku',
},
newFolder: {
fieldName: 'Naziv direktorijuma',
fieldFeedback: 'Direktorijum već postoji!',
title: 'Kreiraj novi direktorijum',
},
preview: {
title: 'Pregled',
},
properties: {
disk: 'Disk',
modified: 'Izmenjen',
name: 'Naziv',
path: 'Lokacija',
size: 'Veličina',
title: 'Svojstva',
type: 'Tip datoteke',
url: 'URL',
access: 'Pristup',
access_0: 'Pristup odbijen',
access_1: 'Samo za čitanje',
access_2: 'Pristup za čitanje i pisanje',
},
rename: {
directoryExist: 'Direktorijum postoji',
fieldName: 'Unesite novi naziv',
fieldFeedback: 'Neispravan naziv',
fileExist: 'Datoteka već postoji',
title: 'Preimenuj',
},
status: {
noErrors: 'Nema Grešaka!',
title: 'Status',
},
upload: {
ifExist: 'Ako datoteka postoji:',
noSelected: 'Nema izabranih fajlova!',
overwrite: 'Zameni!',
selected: 'Izabrano:',
size: 'Veličina:',
skip: 'Preskoči',
title: 'DOdaj fajlove',
},
editor: {
title: 'Editor',
},
audioPlayer: {
title: 'Audio plejer',
},
videoPlayer: {
title: 'Video plejer',
},
zip: {
title: 'Napravi arhivu',
fieldName: 'Naziv Arhive',
fieldFeedback: 'Arhiva Postoji!',
},
unzip: {
title: 'Otpakuj arhivu',
fieldName: 'Naziv direktorijuma',
fieldRadioName: 'Otpakuj u:',
fieldRadio1: 'U aktivni direktorijum',
fieldRadio2: 'U novi direktorijum',
fieldFeedback: 'Direktorijum Postoji!',
warning: 'Pažnja! Ako se nazivi poklapaju, datoteke će biti prepisane!',
},
cropper: {
title: 'Orezivanje',
apply: 'Primeni',
reset: 'Resetuj',
save: 'Sačuvaj',
},
},
notifications: {
cutToClipboard: 'Isečeno u klipbord!',
copyToClipboard: 'Kopirano u klipbord!',
},
response: {
noConfig: 'Nema konfiguracije!',
notFound: 'Nije pronađeno!',
diskNotFound: 'Disk nije pronađen!',
pathNotFound: 'Putanja nije pronađena!',
diskSelected: 'Disk izabran!',
// files
fileExist: 'Datoteka već postoji!',
fileCreated: 'Nova datoteka napravljena!',
fileUpdated: 'Datoteka izmenjena!',
fileNotFound: 'Datoteka nije pronadjena!',
// directories
dirExist: 'Direktorijum već postoji!',
dirCreated: 'Novi direktorijum napravljen!',
dirNotFound: 'Direktorijum nije pronađen',
// actions
uploaded: 'Sve datoteke poslate!',
notAllUploaded: 'Some files weren\'t uploaded!',
delNotFound: 'Nekoliko stavki nije pronađeno! Osvežite!',
deleted: 'Obrisano!',
renamed: 'Preimenovano!',
copied: 'Uspešno kopirano!',
// zip
zipError: 'Greška u pravljenju arhive!',
// acl
aclError: 'Pristup odbijen!',
},
};
export default sr;
/**
* Turkish translate
* @type Object
*/
const tr = {
btn: {
about: 'Hakkında',
back: 'Geri',
cancel: 'İptal',
clear: 'Temizle',
copy: 'Kopyala',
cut: 'Kes',
delete: 'Sil',
edit: 'Düzenle',
forward: 'İleri',
folder: 'Yeni klasör',
file: 'Yeni dosya',
fullScreen: 'Tam ekran',
grid: 'Izgara',
paste: 'Yapıştır',
refresh: 'Yenile',
submit: 'Gönder',
table: 'Tablo',
upload: 'Yükle',
uploadSelect: 'Dosyaları seç',
hidden: ' Gizli dosyalar',
},
clipboard: {
actionType: 'İşlem türü',
copy: 'Kopyala',
cut: 'Yapıştır',
none: 'Hiç bir şey seçilmedi',
title: 'Pano',
},
contextMenu: {
copy: 'Kopyala',
cut: 'Yapıştır',
delete: 'Sil',
download: 'İndir',
info: 'Seçilenler:',
open: '',
paste: 'Yapıştır',
properties: 'Özellikler',
rename: 'Yeniden adlandır',
select: 'Seç',
view: 'Gör',
zip: 'Zip',
unzip: 'Zip aç',
edit: 'Düzenle',
audioPlay: 'Oynat',
videoPlay: 'Oynat',
},
info: {
directories: 'Klasörler:',
files: 'Dosyalar:',
selected: 'Seçilenler:',
selectedSize: 'Dosyaların boyutu:',
size: 'Dosyaların boyutu:',
},
manager: {
table: {
date: 'Tarih',
folder: 'Klasör',
name: 'İsim',
size: 'Boyut',
type: 'Tür',
},
},
modal: {
about: {
developer: 'Geliştirici',
name: 'Laravel File Manager',
title: 'Hakkında',
version: 'Sürüm',
},
delete: {
noSelected: 'Hiç bir şey seçilmedi!',
title: 'Sil',
},
newFile: {
fieldName: 'Dosya adı',
fieldFeedback: 'Aynı isimli dosya var!',
title: 'Yeni dosya yarat',
},
newFolder: {
fieldName: 'Klasör adı',
fieldFeedback: 'Aynı isimli klasör var!',
title: 'Yeni klasör yarat',
},
preview: {
title: 'Önizleme',
},
properties: {
disk: 'Disk',
modified: 'Değiştirilme',
name: 'İsim',
path: 'Yol',
size: 'Boyut',
title: 'Özellikler',
type: 'Tür',
url: 'URL',
access: 'Erişim',
access_0: 'Erişim engellendi',
access_1: 'Salt okunur',
access_2: 'Okuma ve yazma',
},
rename: {
directoryExist: 'Klasör mevcut',
fieldName: 'Yeni isim girin',
fieldFeedback: 'Geçersiz isim',
fileExist: 'Dosya mevcut',
title: 'Yeniden adlandır',
},
status: {
noErrors: 'Hata yok!',
title: 'Durum',
},
upload: {
ifExist: 'Eğer dosya mevcutsa:',
noSelected: 'Hiç bir dosya seçilmedi!',
overwrite: 'Üzerine yaz!',
selected: 'Seçilen:',
size: 'Boyut:',
skip: 'Atla',
title: 'Dosyaları yükle',
},
editor: {
title: 'Editör',
},
audioPlayer: {
title: 'Ses oynatıcı',
},
videoPlayer: {
title: 'Video oynatıcı',
},
zip: {
title: 'Arşiv yarat',
fieldName: 'Arşiv adı',
fieldFeedback: 'Arşiv mevcut!',
},
unzip: {
title: 'Arşivi aç',
fieldName: 'Klasör adı',
fieldRadioName: 'Hedef:',
fieldRadio1: 'Şu anki klasör',
fieldRadio2: 'Yeni klasör',
fieldFeedback: 'Klasör mevcut!',
warning: 'Dikkat! Eğer dosya isimleri aynı olursa, üzerine yazılacak!',
},
cropper: {
title: 'Kırpma',
apply: 'Uygula',
reset: 'Sıfırla',
save: 'Kaydet',
},
},
notifications: {
cutToClipboard: 'Panoya kesildi!',
copyToClipboard: 'Panoya kopyalandı!',
},
response: {
noConfig: 'Ayarlar bulunamadı!',
notFound: 'Bulunamadı!',
diskNotFound: 'Disk bulunamadı!',
pathNotFound: 'Yol bulunamadı!',
diskSelected: 'Disk seçildi!',
// files
fileExist: 'Dosya zaten var!',
fileCreated: 'Dosya yaratıldı!',
fileUpdated: 'Dosya güncellendi!',
fileNotFound: 'Dosya bulunamadı!',
// directories
dirExist: 'Klasör zaten var!',
dirCreated: 'Klasör yaratıldı!',
dirNotFound: 'Klasör bulunamadı',
// actions
uploaded: 'Tüm dosyalar yüklendi!',
notAllUploaded: 'Bazı dosyalar yüklenemedi!',
delNotFound: 'Bazı öğeler bulunamadı!',
deleted: 'Silindi!',
renamed: 'Yeniden adlandırıldı!',
copied: 'Başarıyla kopyalandı!',
// zip
zipError: 'Arşiv yaratılırken hata oluştu!',
// acl
aclError: 'Erişim engellendi!',
},
};
export default tr;
/**
* zh_CN translate
* osindex - https://github.com/osindex
* @type Object
*/
/* eslint camelcase: 0 */
const zh_CN = {
btn: {
about: '关于',
back: '返回',
cancel: '取消',
clear: '清除',
copy: '复制',
cut: '剪切',
delete: '删除',
edit: '编辑',
forward: '前进',
folder: '创建目录',
file: '创建文件',
fullScreen: '全屏',
grid: '网格',
paste: '粘贴',
refresh: '刷新',
submit: '提交',
table: '表格',
upload: '上传',
uploadSelect: '选择文件',
hidden: ' 隐藏文件',
},
clipboard: {
actionType: '类型',
copy: '复制',
cut: '剪切',
none: '未选中文件',
title: '剪切板',
},
contextMenu: {
copy: '复制',
cut: '剪切',
delete: '删除',
download: '下载',
info: '选择:',
open: '打开',
paste: '粘贴',
properties: '属性',
rename: '重命名',
select: '选择',
view: '查看',
zip: '压缩',
unzip: '解压',
edit: '编辑',
audioPlay: '播放',
videoPlay: '播放',
},
info: {
directories: '目录:',
files: '文件:',
selected: '已选择:',
selectedSize: '已选择文件大小:',
size: '文件大小:',
},
manager: {
table: {
date: '日期',
folder: '目录',
name: '名称',
size: '大小',
type: '类型',
},
},
modal: {
about: {
developer: '开发者信息',
name: '文件管理页',
title: '关于',
version: '版本',
},
delete: {
noSelected: '暂无选中!',
title: '删除',
},
newFile: {
fieldName: '文件名',
fieldFeedback: '文件已存在!',
title: '创建文件',
},
newFolder: {
fieldName: '目录名',
fieldFeedback: '目录已存在!',
title: '创建目录',
},
preview: {
title: '预览',
},
properties: {
disk: '模块',
modified: '时间',
name: '名称',
path: '路径',
size: '大小',
title: '属性',
type: '类型',
url: '网址',
access: '授权',
access_0: '禁止访问',
access_1: '只读',
access_2: '读写',
},
rename: {
directoryExist: '目录存在',
fieldName: '输入名称',
fieldFeedback: '名称不可用',
fileExist: '文件存在',
title: '重命名',
},
status: {
noErrors: '暂无错误!',
title: '状态',
},
upload: {
ifExist: '如果文件存在:',
noSelected: '暂无选中!',
overwrite: '覆盖',
selected: '已选择:',
size: '大小:',
skip: '忽略',
title: '上传文件',
},
editor: {
title: '编辑',
},
audioPlayer: {
title: '播放音频',
},
videoPlayer: {
title: '播放视频',
},
zip: {
title: '归档文件',
fieldName: '归档名称',
fieldFeedback: '文件存在!',
},
unzip: {
title: '解压',
fieldName: '目录名称',
fieldRadioName: '解压到:',
fieldRadio1: '当前目录',
fieldRadio2: '输入目录',
fieldFeedback: '目录存在!',
warning: '注意!如果文件存在将会被覆盖!',
},
cropper: {
title: '裁剪',
apply: '应用',
reset: '重置',
save: '保存',
},
},
notifications: {
cutToClipboard: '剪切到粘贴板!',
copyToClipboard: '复制到粘贴板!',
},
// todo - need to translate
response: {
noConfig: 'Config not found!',
notFound: 'Not found!',
diskNotFound: 'Disk not found!',
pathNotFound: 'Path not found!',
diskSelected: 'Disk selected!',
// files
fileExist: 'File already exists!',
fileCreated: 'File created!',
fileUpdated: 'File updated!',
fileNotFound: 'File not found!',
// directories
dirExist: 'Directory already exists!',
dirCreated: 'Directory created!',
dirNotFound: 'Directory not found',
// actions
uploaded: 'All files uploaded!',
notAllUploaded: 'Some files weren\'t uploaded!',
delNotFound: 'Some items weren\'t founded!',
deleted: 'Deleted!',
renamed: 'Renamed!',
copied: 'Copied successfully!',
// zip
zipError: 'Error creating archive!',
// acl
aclError: 'Access denied!',
},
};
export default zh_CN;
/**
* zh_TW translate
* @type Object
*/
/* eslint camelcase: 0 */
const zh_TW = {
btn: {
about: '關於',
back: '返回',
cancel: '取消',
clear: '清除',
copy: '複製',
cut: '剪下',
delete: '刪除',
edit: '編輯',
forward: '前進',
folder: '新增目錄',
file: '新增文件',
fullScreen: '全螢幕',
grid: '網格',
paste: '貼上',
refresh: '重新整理',
submit: '送出',
table: '表格',
upload: '上傳',
uploadSelect: '選擇文件',
hidden: ' 隱藏文件',
},
clipboard: {
actionType: '類型',
copy: '複製',
cut: '剪下',
none: '未選取',
title: '剪貼簿',
},
contextMenu: {
copy: '複製',
cut: '剪下',
delete: '刪除',
download: '下載',
info: '選擇:',
open: '打開',
paste: '貼上',
properties: '屬性',
rename: '重新命名',
select: '選擇',
view: '查看',
zip: '壓縮',
unzip: '解壓縮',
edit: '編輯',
audioPlay: '播放',
videoPlay: '播放',
},
info: {
directories: '目錄:',
files: '文件:',
selected: '已選擇:',
selectedSize: '已選擇文件大小:',
size: '文件大小:',
},
manager: {
table: {
date: '日期',
folder: '目錄',
name: '名稱',
size: '大小',
type: '類型',
},
},
modal: {
about: {
developer: '開發者資訊',
name: '文件管理頁',
title: '關於',
version: '版本',
},
delete: {
noSelected: '暫無選中!',
title: '刪除',
},
newFile: {
fieldName: '文件名',
fieldFeedback: '文件已存在!',
title: '新增文件',
},
newFolder: {
fieldName: '目錄名',
fieldFeedback: '目錄已存在!',
title: '新增目錄',
},
preview: {
title: '預覽',
},
properties: {
disk: '磁碟',
modified: '時間',
name: '名稱',
path: '路徑',
size: '大小',
title: '屬性',
type: '類型',
url: '網址',
access: '授權',
access_0: '禁止訪問',
access_1: '唯獨',
access_2: '讀寫',
},
rename: {
directoryExist: '目錄存在',
fieldName: '輸入名稱',
fieldFeedback: '名稱不可用',
fileExist: '文件存在',
title: '重命名',
},
status: {
noErrors: '暫無錯誤!',
title: '狀態',
},
upload: {
ifExist: '如果文件存在:',
noSelected: '暫無選中!',
overwrite: '覆蓋',
selected: '已選擇:',
size: '大小:',
skip: '忽略',
title: '上傳文件',
},
editor: {
title: '編輯',
},
audioPlayer: {
title: '播放音樂',
},
videoPlayer: {
title: '播放影片',
},
zip: {
title: '壓縮文件',
fieldName: '壓縮名稱',
fieldFeedback: '文件存在!',
},
unzip: {
title: '解壓縮',
fieldName: '目錄名稱',
fieldRadioName: '解壓到:',
fieldRadio1: '當前目錄',
fieldRadio2: '輸入目錄',
fieldFeedback: '目錄存在!',
warning: '注意!如果文件存在將會被覆蓋!',
},
cropper: {
title: '裁剪',
apply: '套用',
reset: '重設',
save: '儲存',
},
},
notifications: {
cutToClipboard: '剪下到剪貼簿!',
copyToClipboard: '複製到剪貼簿!',
},
response: {
noConfig: '找不到設定檔!',
notFound: '找不到項目!',
diskNotFound: '找不到磁碟!',
pathNotFound: '找不到路徑!',
diskSelected: '磁碟已選取!',
// files
fileExist: '文件已存在!',
fileCreated: '文件已建立!',
fileUpdated: '文件已更新!',
fileNotFound: '找不到文件!',
// directories
dirExist: '目錄已存在!',
dirCreated: '目錄已存在!',
dirNotFound: '找不到目錄',
// actions
uploaded: '全部文件已上傳完畢!',
notAllUploaded: '部分文件未上傳!',
delNotFound: '部分項目未被找到!',
deleted: '已刪除!',
renamed: '已重新命名!',
copied: '已複製完成!',
// zip
zipError: '壓縮檔建立失敗!',
// acl
aclError: '存取拒絕!',
},
};
export default zh_TW;
// store modules
import tree from './file-manager/tree/store';
import modal from './file-manager/modal/store';
import settings from './file-manager/settings/store';
import manager from './file-manager/manager/store';
import messages from './file-manager/messages/store';
// main store
import state from './file-manager/state';
import mutations from './file-manager/mutations';
import getters from './file-manager/getters';
import actions from './file-manager/actions';
export default {
namespaced: true,
modules: {
settings,
left: manager,
right: manager,
tree,
modal,
messages,
},
state,
mutations,
actions,
getters,
};
/* eslint-disable max-len,prefer-destructuring,object-curly-newline */
import GET from '../../utils/get';
import POST from '../../utils/post';
export default {
/**
* Get initiation data from server
* @param state
* @param commit
* @param getters
* @param dispatch
*/
initializeApp({ state, commit, getters, dispatch }) {
GET.initialize().then((response) => {
if (response.data.result.status === 'success') {
commit('settings/initSettings', response.data.config);
commit('setDisks', response.data.config.disks);
let leftDisk = response.data.config.leftDisk
? response.data.config.leftDisk
: getters.diskList[0];
let rightDisk = response.data.config.rightDisk
? response.data.config.rightDisk
: getters.diskList[0];
// paths
let leftPath = response.data.config.leftPath;
let rightPath = response.data.config.rightPath;
// find disk and path settings in the URL
if (window.location.search) {
const params = new URLSearchParams(window.location.search);
if (params.get('leftDisk')) {
leftDisk = params.get('leftDisk');
}
if (params.get('rightDisk')) {
rightDisk = params.get('rightDisk');
}
if (params.get('leftPath')) {
leftPath = params.get('leftPath');
}
if (params.get('rightPath')) {
rightPath = params.get('rightPath');
}
}
commit('left/setDisk', leftDisk);
// if leftPath not null
if (leftPath) {
commit('left/setSelectedDirectory', leftPath);
commit('left/addToHistory', leftPath);
}
dispatch('getLoadContent', {
manager: 'left',
disk: leftDisk,
path: leftPath,
});
// if selected left and right managers
if (state.settings.windowsConfig === 3) {
commit('right/setDisk', rightDisk);
// if rightPath not null
if (rightPath) {
commit('right/setSelectedDirectory', rightPath);
commit('right/addToHistory', rightPath);
}
dispatch('getLoadContent', {
manager: 'right',
disk: rightDisk,
path: rightPath,
});
} else if (state.settings.windowsConfig === 2) {
// if selected left manager and directories tree
// init directories tree
dispatch('tree/initTree', leftDisk).then(() => {
if (leftPath) {
// reopen folders if path not null
dispatch('tree/reopenPath', leftPath);
}
});
}
}
});
},
/**
* Download files and folders to the selected file manager
* @param context
* @param manager
* @param disk
* @param path
*/
getLoadContent(context, { manager, disk, path }) {
GET.content(disk, path).then((response) => {
if (response.data.result.status === 'success') {
context.commit(`${manager}/setDirectoryContent`, response.data);
}
});
},
/**
* Select disk
* @param state
* @param commit
* @param dispatch
* @param disk
* @param manager
*/
selectDisk({ state, commit, dispatch }, { disk, manager }) {
GET.selectDisk(disk).then((response) => {
// if disk exist => change disk
if (response.data.result.status === 'success') {
// set disk name
commit(`${manager}/setDisk`, disk);
// reset history
commit(`${manager}/resetHistory`);
// reinitialize tree if directories tree is shown
if (state.settings.windowsConfig === 2) {
dispatch('tree/initTree', disk);
}
// download content for root path
dispatch(`${manager}/selectDirectory`, { path: null, history: false });
}
});
},
/**
* Create new file
* @param getters
* @param dispatch
* @param fileName
* @returns {Promise}
*/
createFile({ getters, dispatch }, fileName) {
// directory for new file
const selectedDirectory = getters.selectedDirectory;
// create new file, server side
return POST.createFile(getters.selectedDisk, selectedDirectory, fileName)
.then((response) => {
// update file list
dispatch('updateContent', {
response,
oldDir: selectedDirectory,
commitName: 'addNewFile',
type: 'file',
});
return response;
});
},
/**
* Get file content
* @param context
* @param disk
* @param path
* @returns {*}
*/
getFile(context, { disk, path }) {
return GET.getFile(disk, path);
},
/**
* Update file
* @param getters
* @param dispatch
* @param formData
* @returns {PromiseLike | Promise}
*/
updateFile({ getters, dispatch }, formData) {
return POST.updateFile(formData).then((response) => {
// update file list
dispatch('updateContent', {
response,
oldDir: getters.selectedDirectory,
commitName: 'updateFile',
type: 'file',
});
return response;
});
},
/**
* Create new directory
* @param getters
* @param dispatch
* @param name
* @returns {*|PromiseLike<T | never>|Promise<T | never>}
*/
createDirectory({ getters, dispatch }, name) {
// directory for new folder
const selectedDirectory = getters.selectedDirectory;
// create new directory, server side
return POST.createDirectory({
disk: getters.selectedDisk,
path: selectedDirectory,
name,
}).then((response) => {
// update file list
dispatch('updateContent', {
response,
oldDir: selectedDirectory,
commitName: 'addNewDirectory',
type: 'directory',
});
return response;
});
},
/**
* Upload file or files
* @param getters
* @param commit
* @param dispatch
* @param files
* @param overwrite
* @returns {Promise}
*/
upload({ getters, commit, dispatch }, { files, overwrite }) {
// directory where files will be uploaded
const selectedDirectory = getters.selectedDirectory;
// create new form data
const data = new FormData();
data.append('disk', getters.selectedDisk);
data.append('path', selectedDirectory || '');
data.append('overwrite', overwrite);
// add file or files
for (let i = 0; i < files.length; i += 1) {
data.append('files[]', files[i]);
}
// axios config - progress bar
const config = {
onUploadProgress(progressEvent) {
const progress = Math.round((progressEvent.loaded * 100) / progressEvent.total);
commit('messages/setProgress', progress);
},
};
// upload files
return POST.upload(data, config).then((response) => {
// clear progress
commit('messages/clearProgress');
// if files uploaded successfully
if (
response.data.result.status === 'success'
&& selectedDirectory === getters.selectedDirectory
) {
// refresh content
dispatch('refreshManagers');
}
return response;
}).catch(() => {
// clear progress
commit('messages/clearProgress');
});
},
/**
* Delete selected files and folders
* @param state
* @param getters
* @param dispatch
* @param items
* @returns {*|PromiseLike<T | never>|Promise<T | never>}
*/
delete({ state, getters, dispatch }, items) {
return POST.delete({
disk: getters.selectedDisk,
items,
}).then((response) => {
// if all items deleted successfully
if (response.data.result.status === 'success') {
// refresh content
dispatch('refreshManagers');
// delete directories from tree
if (state.settings.windowsConfig === 2) {
const onlyDir = items.filter((item) => item.type === 'dir');
dispatch('tree/deleteFromTree', onlyDir);
}
}
return response;
});
},
/**
* Paste files and folders
* @param state
* @param commit
* @param getters
* @param dispatch
*/
paste({ state, commit, getters, dispatch }) {
POST.paste({
disk: getters.selectedDisk,
path: getters.selectedDirectory,
clipboard: state.clipboard,
}).then((response) => {
// if the action was successful
if (response.data.result.status === 'success') {
// refresh content
dispatch('refreshAll');
// if action - cut - clear clipboard
if (state.clipboard.type === 'cut') {
commit('resetClipboard');
}
}
});
},
/**
* Rename file or folder
* @param getters
* @param dispatch
* @param type
* @param newName
* @param oldName
* @returns {Promise}
*/
rename({ getters, dispatch }, { type, newName, oldName }) {
return POST.rename({
disk: getters.selectedDisk,
newName,
oldName,
type,
}).then((response) => {
// refresh content
if (type === 'dir') {
dispatch('refreshAll');
} else {
dispatch('refreshManagers');
}
return response;
});
},
/**
* Get file url
* @param store
* @param disk
* @param path
* @returns {Promise}
*/
url(store, { disk, path }) {
return GET.url(disk, path);
},
/**
* Zip files and folders
* @param state
* @param getters
* @param dispatch
* @param name
* @returns {*|PromiseLike<T | never>|Promise<T | never>}
*/
zip({ state, getters, dispatch }, name) {
const selectedDirectory = getters.selectedDirectory;
return POST.zip({
disk: getters.selectedDisk,
path: selectedDirectory,
name,
elements: state[state.activeManager].selected,
}).then((response) => {
// if zipped successfully
if (response.data.result.status === 'success'
&& selectedDirectory === getters.selectedDirectory
) {
// refresh content
dispatch('refreshManagers');
}
return response;
});
},
/**
* Unzip selected archive
* @param getters
* @param dispatch
* @param folder
* @returns {*|PromiseLike<T | never>|Promise<T | never>}
*/
unzip({ getters, dispatch }, folder) {
const selectedDirectory = getters.selectedDirectory;
return POST.unzip({
disk: getters.selectedDisk,
path: getters.selectedItems[0].path,
folder,
}).then((response) => {
// if unzipped successfully
if (response.data.result.status === 'success'
&& selectedDirectory === getters.selectedDirectory
) {
// refresh
dispatch('refreshAll');
}
return response;
});
},
/**
* Add selected items to clipboard
* @param state
* @param commit
* @param getters
* @param type
*/
toClipboard({ state, commit, getters }, type) {
// if files are selected
if (getters[`${state.activeManager}/selectedCount`]) {
commit('setClipboard', {
type,
disk: state[state.activeManager].selectedDisk,
directories: state[state.activeManager].selected.directories.slice(0),
files: state[state.activeManager].selected.files.slice(0),
});
}
},
/**
* Refresh content in the manager/s
* @param dispatch
* @param state
* @returns {*}
*/
refreshManagers({ dispatch, state }) {
// select what needs to be an updated
if (state.settings.windowsConfig === 3) {
return Promise.all([
// left manager
dispatch('left/refreshDirectory'),
// right manager
dispatch('right/refreshDirectory'),
]);
}
// only left manager
return dispatch('left/refreshDirectory');
},
/**
* Refresh All
* @param state
* @param getters
* @param dispatch
* @returns {*}
*/
refreshAll({ state, getters, dispatch }) {
if (state.settings.windowsConfig === 2) {
// refresh tree
return dispatch('tree/initTree', state.left.selectedDisk).then(() => Promise.all([
// reopen folders if need
dispatch('tree/reopenPath', getters.selectedDirectory),
// refresh manager/s
dispatch('refreshManagers'),
]));
}
// refresh manager/s
return dispatch('refreshManagers');
},
/**
* Repeat sorting
* @param state
* @param dispatch
* @param manager
*/
repeatSort({ state, dispatch }, manager) {
dispatch(`${manager}/sortBy`, {
field: state[manager].sort.field,
direction: state[manager].sort.direction,
});
},
/**
* Update content - files, folders after create or update
* @param state
* @param commit
* @param getters
* @param dispatch
* @param response
* @param oldDir
* @param commitName
* @param type
*/
updateContent({ state, commit, getters, dispatch }, { response, oldDir, commitName, type }) {
// if operation success
if (
response.data.result.status === 'success'
&& oldDir === getters.selectedDirectory
) {
// add/update file/folder in to the files/folders list
commit(`${state.activeManager}/${commitName}`, response.data[type]);
// repeat sort
dispatch('repeatSort', state.activeManager);
// if tree module is showing
if (type === 'directory' && state.settings.windowsConfig === 2) {
// update tree module
dispatch('tree/addToTree', {
parentPath: oldDir,
newDirectory: response.data.tree,
});
// if both managers show the same folder
} else if (
state.settings.windowsConfig === 3
&& state.left.selectedDirectory === state.right.selectedDirectory
&& state.left.selectedDisk === state.right.selectedDisk
) {
// add/update file/folder in to the files/folders list (inactive manager)
commit(`${getters.inactiveManager}/${commitName}`, response.data[type]);
// repeat sort
dispatch('repeatSort', getters.inactiveManager);
}
}
},
/**
* Reset application state
* @param state
* @param commit
*/
resetState({ state, commit }) {
// left manager
commit('left/setDisk', null);
commit('left/setSelectedDirectory', null);
commit('left/setDirectoryContent', { directories: [], files: [] });
commit('left/resetSelected');
commit('left/resetSortSettings');
commit('left/resetHistory');
commit('left/setView', 'table');
// modals
commit('modal/clearModal');
// messages
commit('messages/clearActionResult');
commit('messages/clearProgress');
commit('messages/clearLoading');
commit('messages/clearErrors');
if (state.settings.windowsConfig === 3) {
// right manager
commit('right/setDisk', null);
commit('right/setSelectedDirectory', null);
commit('right/setDirectoryContent', { directories: [], files: [] });
commit('right/resetSelected');
commit('right/resetSortSettings');
commit('right/resetHistory');
commit('right/setView', 'table');
} else if (state.settings.windowsConfig === 2) {
// tree
commit('tree/cleanTree');
commit('tree/clearTempArray');
}
commit('resetState');
},
/**
* Open PDF
* @param context
* @param disk
* @param path
*/
openPDF(context, { disk, path }) {
const win = window.open();
GET.getFileArrayBuffer(disk, path).then((response) => {
const blob = new Blob([response.data], { type: 'application/pdf' });
win.document.write(`<iframe src="${URL.createObjectURL(blob)}" allowfullscreen height="100%" width="100%"></iframe>`);
});
},
};
export default {
/**
* Get a list of disks
* @param state
* @returns {string[]}
*/
diskList(state) {
return Object.keys(state.disks);
},
/**
* Selected disk for active manager
* @param state
* @returns {selectedDisk|null|*|computed.selectedDisk}
*/
selectedDisk(state) {
return state[state.activeManager].selectedDisk;
},
/**
* Selected directory for active manager
* @param state
* @returns {selectedDirectory|computed.selectedDirectory|string|*}
*/
selectedDirectory(state) {
return state[state.activeManager].selectedDirectory;
},
/**
* List of selected files and folders for the active manager
* @param state
* @param getters
* @returns {*}
*/
selectedItems(state, getters) {
return getters[`${state.activeManager}/selectedList`];
},
/**
* Inactive manager name
* @param state
* @returns {string}
*/
inactiveManager(state) {
return state.activeManager === 'left' ? 'right' : 'left';
},
};
/* eslint-disable object-curly-newline */
import GET from '../../../utils/get';
export default {
/**
* Load files and folders for the selected directory
* @param state
* @param commit
* @param dispatch
* @param rootState
* @param path
* @param history
* @returns {Promise}
*/
selectDirectory({ state, commit, dispatch, rootState }, { path, history }) {
// reset content
commit('setDirectoryContent', { directories: [], files: [] });
// get content for the selected directory
return GET.content(state.selectedDisk, path).then((response) => {
if (response.data.result.status === 'success') {
commit('resetSelected');
commit('resetSortSettings');
commit('setDirectoryContent', response.data);
commit('setSelectedDirectory', path);
if (history) commit('addToHistory', path);
// if directories tree is shown, not main directory and directory have subdirectories
if (
rootState.fm.settings.windowsConfig === 2
&& path
&& response.data.directories.length
) {
dispatch('fm/tree/showSubdirectories', path, { root: true });
}
}
});
},
/**
* Refresh content in the selected directory
* @param state
* @param commit
* @param dispatch
*/
refreshDirectory({ state, commit, dispatch }) {
GET.content(state.selectedDisk, state.selectedDirectory).then((response) => {
commit('resetSelected');
commit('resetSortSettings');
commit('resetHistory');
// add to history selected directory
if (state.selectedDirectory) commit('addToHistory', state.selectedDirectory);
if (response.data.result.status === 'success') {
commit('setDirectoryContent', response.data);
} else if (response.data.result.status === 'danger') {
// If directory not found try to load main directory
commit('setSelectedDirectory', null);
dispatch('refreshDirectory');
}
});
},
/**
* History Back
* @param state
* @param commit
* @param dispatch
*/
historyBack({ state, commit, dispatch }) {
dispatch('selectDirectory', {
path: state.history[state.historyPointer - 1],
history: false,
});
commit('pointerBack');
},
/**
* History Forward
* @param state
* @param commit
* @param dispatch
*/
historyForward({ state, commit, dispatch }) {
dispatch('selectDirectory', {
path: state.history[state.historyPointer + 1],
history: false,
});
commit('pointerForward');
},
/**
* Sort data by field
* @param context
* @param field
* @param direction
*/
sortBy({ state, commit }, { field, direction }) {
if (state.sort.field === field && !direction) {
commit('setSortDirection', state.sort.direction === 'up' ? 'down' : 'up');
} else if (direction) {
commit('setSortDirection', direction);
commit('setSortField', field);
} else {
commit('setSortDirection', 'up');
commit('setSortField', field);
}
// sort by field type
switch (field) {
case 'name':
commit('sortByName');
break;
case 'size':
commit('sortBySize');
break;
case 'type':
commit('sortByType');
break;
case 'date':
commit('sortByDate');
break;
default:
break;
}
},
};
export default {
/**
* Files list(filtered)
* @param state
* @param getters
* @param rootState
*/
files(state, getters, rootState) {
if (rootState.fm.settings.hiddenFiles) {
return state.files;
}
return state.files.filter((item) => item.basename.match(new RegExp('^([^.]).*', 'i')));
},
/**
* Directories list(filtered)
* @param state
* @param getters
* @param rootState
* @returns {*}
*/
directories(state, getters, rootState) {
if (rootState.fm.settings.hiddenFiles) {
return state.directories;
}
return state.directories.filter((item) => item.basename.match(new RegExp('^([^.]).*', 'i')));
},
/**
* Files counter
* @param state
* @param getters
* @returns {*}
*/
filesCount(state, getters) {
return getters.files.length;
},
/**
* Directories counter
* @param state
* @param getters
* @returns {*}
*/
directoriesCount(state, getters) {
return getters.directories.length;
},
/**
* Files size - bytes
* @param state
* @param getters
* @returns {*}
*/
filesSize(state, getters) {
if (getters.files.length) {
return getters.files.reduce((previous, current) => previous + Number(current.size), 0);
}
return 0;
},
/**
* Count selected files and folders
* @param state
* @param getters
* @returns {number}
*/
selectedCount(state, getters) {
return getters.selectedList.length;
},
/**
* Selected files size
* @param state
* @returns {number}
*/
selectedFilesSize(state) {
const selectedFiles = state.files.filter((file) => state.selected.files.includes(file.path));
if (selectedFiles.length) {
return selectedFiles.reduce((previous, current) => previous + Number(current.size), 0);
}
return 0;
},
/**
* Selected files and folders
* @param state
*/
selectedList(state) {
const selectedDirectories = state.directories.filter((directory) => state.selected.directories.includes(directory.path));
const selectedFiles = state.files.filter((file) => state.selected.files.includes(file.path));
return selectedDirectories.concat(selectedFiles);
},
/**
* Breadcrumb
* @param state
* @returns {*}
*/
breadcrumb(state) {
if (state.selectedDirectory) {
return state.selectedDirectory.split('/');
}
return null;
},
/**
* Compare directories name
* @param state
*/
directoryExist: (state) => (basename) => state.directories.some((el) => el.basename === basename),
/**
* Compare files name
* @param state
*/
fileExist: (state) => (basename) => state.files.some((el) => el.basename === basename),
};
export default {
/**
* Set selected disk
* @param state
* @param disk
*/
setDisk(state, disk) {
state.selectedDisk = disk;
},
/**
* Set directories and files in selected directory
* @param state
* @param data
*/
setDirectoryContent(state, data) {
state.directories = data.directories;
state.files = data.files;
},
/**
* Set selected directory
* @param state
* @param directory
*/
setSelectedDirectory(state, directory) {
state.selectedDirectory = directory;
},
/**
* Set selected items
* @param state
* @param type (directories, files)
* @param path
*/
setSelected(state, { type, path }) {
state.selected[type].push(path);
},
/**
* Remove item from array
* @param state
* @param arrayIndex
*/
removeSelected(state, { type, path }) {
const itemIndex = state.selected[type].indexOf(path);
if (itemIndex !== -1) state.selected[type].splice(itemIndex, 1);
},
/**
* Change selected item
* @param state
* @param type
* @param path
*/
changeSelected(state, { type, path }) {
state.selected.directories = [];
state.selected.files = [];
state.selected[type].push(path);
},
/**
* Reset selected items array
* @param state
*/
resetSelected(state) {
state.selected.directories = [];
state.selected.files = [];
},
/**
* Add new file
* @param state
* @param newFile
*/
addNewFile(state, newFile) {
state.files.push(newFile);
},
/**
* Update file
* @param state
* @param file
*/
updateFile(state, file) {
const itemIndex = state.files.findIndex((el) => el.basename === file.basename);
if (itemIndex !== -1) state.files[itemIndex] = file;
},
/**
* Add new directory
* @param state
* @param newDirectory
*/
addNewDirectory(state, newDirectory) {
state.directories.push(newDirectory);
},
/**
* Change history pointer (back)
* @param state
*/
pointerBack(state) {
state.historyPointer -= 1;
},
/**
* Change history pointer (forward)
* @param state
*/
pointerForward(state) {
state.historyPointer += 1;
},
/**
* Add to history
* @param state
* @param path
*/
addToHistory(state, path) {
if (state.historyPointer < state.history.length - 1) {
// erase next elements in the history
state.history.splice(state.historyPointer + 1, Number.MAX_VALUE);
}
// add new path
state.history.push(path);
// change history pointer
state.historyPointer += 1;
},
/**
* Reset history
* @param state
*/
resetHistory(state) {
state.history = [null];
state.historyPointer = 0;
},
/**
* Set view type
* Grid or Table
* @param state
* @param type
*/
setView(state, type) {
state.viewType = type;
},
/**
* Set sort settings - field name
* @param state
* @param field
*/
setSortField(state, field) {
state.sort.field = field;
},
/**
* Set sort settings - direction
* @param state
* @param direction
*/
setSortDirection(state, direction) {
state.sort.direction = direction;
},
/**
* Reset sort settings
* @param state
*/
resetSortSettings(state) {
state.sort.field = 'name';
state.sort.direction = 'up';
},
/**
* Sort table by name field
* @param state
*/
sortByName(state) {
if (state.sort.direction === 'up') {
state.directories.sort((a, b) => a.basename.localeCompare(b.basename));
state.files.sort((a, b) => a.basename.localeCompare(b.basename));
} else {
state.directories.sort((a, b) => b.basename.localeCompare(a.basename));
state.files.sort((a, b) => b.basename.localeCompare(a.basename));
}
},
/**
* Sort by file size
* @param state
*/
sortBySize(state) {
state.directories.sort((a, b) => a.basename.localeCompare(b.basename));
if (state.sort.direction === 'up') {
state.files.sort((a, b) => a.size - b.size);
} else {
state.files.sort((a, b) => b.size - a.size);
}
},
/**
* Sort by file extension
* @param state
*/
sortByType(state) {
state.directories.sort((a, b) => a.basename.localeCompare(b.basename));
if (state.sort.direction === 'up') {
state.files.sort((a, b) => a.extension.localeCompare(b.extension));
} else {
state.files.sort((a, b) => b.extension.localeCompare(a.extension));
}
},
/**
* Sort by date
* @param state
*/
sortByDate(state) {
if (state.sort.direction === 'up') {
state.directories.sort((a, b) => a.timestamp - b.timestamp);
state.files.sort((a, b) => a.timestamp - b.timestamp);
} else {
state.directories.sort((a, b) => b.timestamp - a.timestamp);
state.files.sort((a, b) => b.timestamp - a.timestamp);
}
},
};
import mutations from './mutations';
import getters from './getters';
import actions from './actions';
export default {
namespaced: true,
state() {
return {
// selected disk
selectedDisk: null,
// selected directory
selectedDirectory: null,
// Directories in the selected directory
directories: [],
// files in the selected directory
files: [],
// selected files and folders
selected: {
directories: [],
files: [],
},
// sorting settings
sort: {
field: 'name',
direction: 'up',
},
// history
history: [null],
// history pointer
historyPointer: 0,
// view type - table or grid - (default - table)
viewType: 'table',
};
},
mutations,
getters,
actions,
};
export default {
/**
* Set the result of the action
* when the message exists
* @param state
* @param status
* @param message
*/
setActionResult(state, { status, message }) {
state.actionResult.status = status;
state.actionResult.message = message;
},
/**
* Clear action result
* @param state
*/
clearActionResult(state) {
state.actionResult.status = null;
state.actionResult.message = null;
},
/**
* Progress Bar (%) - upload..
* @param state
* @param progress
*/
setProgress(state, progress) {
state.actionProgress = progress;
},
/**
* Clear progress
* @param state
*/
clearProgress(state) {
state.actionProgress = 0;
},
/**
* Add new action
* @param state
*/
addLoading(state) {
state.loading += 1;
},
/**
* Action finish
* @param state
*/
subtractLoading(state) {
state.loading -= 1;
},
/**
* Clear
* @param state
*/
clearLoading(state) {
state.loading = 0;
},
/**
* Set error message
* @param state
* @param error
*/
setError(state, error) {
state.errors.push(error);
},
/**
* Clear errors
* @param state
*/
clearErrors(state) {
state.errors = [];
},
};
import mutations from './mutations';
export default {
namespaced: true,
state() {
return {
// last action result
actionResult: {
status: null,
message: null,
},
// completing state
actionProgress: 0,
// loading spinner
loading: 0,
// application error messages
errors: [],
};
},
mutations,
};
export default {
/**
* Modal window state
* @param state
* @param show
* @param modalName
*/
setModalState(state, { show, modalName }) {
state.showModal = show;
state.modalName = modalName;
},
/**
* Clear modal
* @param state
*/
clearModal(state) {
state.showModal = false;
state.modalName = null;
},
/**
* Main modal block - set height
* @param state
* @param height
*/
setModalBlockHeight(state, height) {
state.modalBlockHeight = height;
},
};
import mutations from './mutations';
export default {
namespaced: true,
state() {
return {
// modal window
showModal: false,
// modal name
modalName: null,
// main modal block height
modalBlockHeight: 0,
};
},
mutations,
};
/* eslint-disable object-curly-newline */
export default {
/**
* Set disks
* @param state
* @param disks
*/
setDisks(state, disks) {
state.disks = disks;
},
/**
* Set clipboard
* @param state
* @param type
* @param disk
* @param directories
* @param files
*/
setClipboard(state, { type, disk, directories, files }) {
state.clipboard.type = type;
state.clipboard.disk = disk;
state.clipboard.directories = directories;
state.clipboard.files = files;
},
/**
* Truncate clipboard
* @param state
* @param type
* @param path
*/
truncateClipboard(state, { type, path }) {
const itemIndex = state.clipboard[type].indexOf(path);
if (itemIndex !== -1) state.clipboard[type].splice(itemIndex, 1);
if (!state.clipboard.directories.length && !state.clipboard.files.length) {
state.clipboard.type = null;
}
},
/**
* Reset clipboard
* @param state
*/
resetClipboard(state) {
state.clipboard.type = null;
state.clipboard.disk = null;
state.clipboard.directories = [];
state.clipboard.files = [];
},
/**
* Select manager (when shown 2 file manager windows)
* @param state
* @param managerName
*/
setActiveManager(state, managerName) {
state.activeManager = managerName;
},
/**
* Set file callback
* @param state
* @param callback
*/
setFileCallBack(state, callback) {
state.fileCallback = callback;
},
/**
* Screen mode toggle - ON/OFF full screen
* @param state
*/
screenToggle(state) {
state.fullScreen = !state.fullScreen;
},
/**
* Reset state
* @param state
*/
resetState(state) {
state.activeManager = 'left';
state.clipboard = {
type: null,
disk: null,
directories: [],
files: [],
};
state.disks = [];
state.fileCallback = null;
state.fullScreen = false;
},
};
export default {
/**
* Base URL
* @param state
* @returns {default.baseUrl|(function(*))|string|*|string|null}
*/
baseUrl(state) {
return state.baseUrl;
},
/**
* Headers
* @param state
* @return {*}
*/
headers(state) {
return state.headers;
},
/**
* Headers has Authorization
* @param state
* @return {boolean}
*/
authHeader(state) {
return Object.prototype.hasOwnProperty.call(state.headers, 'Authorization');
},
};
import Vue from 'vue';
export default {
/**
* Set config
* @param state
* @param data
*/
manualSettings(state, data) {
// overwrite headers - Axios
if (Object.prototype.hasOwnProperty.call(data, 'headers')) {
state.headers = data.headers;
}
// base url - axios
if (Object.prototype.hasOwnProperty.call(data, 'baseUrl')) {
state.baseUrl = data.baseUrl;
}
// windows config
if (Object.prototype.hasOwnProperty.call(data, 'windowsConfig')) {
state.windowsConfig = data.windowsConfig;
}
// language
if (Object.prototype.hasOwnProperty.call(data, 'lang')) {
state.lang = data.lang;
}
// add new translation
if (Object.prototype.hasOwnProperty.call(data, 'translation')) {
Vue.set(state.translations, data.translation.name, Object.freeze(data.translation.content));
}
},
/**
* Initiate Axios baseUrl and headers
* @param state
*/
initAxiosSettings(state) {
// initiate base url, if not set manually
if (!state.baseUrl) {
if (process.env.VUE_APP_LFM_AXIOS_BASE_URL) {
// vue .env
state.baseUrl = process.env.VUE_APP_LFM_AXIOS_BASE_URL;
} else if (process.env.MIX_LFM_BASE_URL) {
// laravel .env
state.baseUrl = process.env.MIX_LFM_BASE_URL;
} else {
let baseUrl = `${window.location.protocol}//${window.location.hostname}`;
if (window.location.port.length) {
baseUrl += `:${window.location.port}/file-manager/`;
} else {
baseUrl += '/file-manager/';
}
state.baseUrl = baseUrl;
}
}
// initiate headers, if not set manually
if (Object.keys(state.headers).length === 0) {
// off laravel csrf-token if need
if (process.env.VUE_APP_LFM_CSRF_TOKEN === 'OFF'
|| process.env.MIX_LFM_CSRF_TOKEN === 'OFF'
) {
state.headers = { 'X-Requested-With': 'XMLHttpRequest' };
} else {
// Laravel CSRF token
const token = document.head.querySelector('meta[name="csrf-token"]');
if (!token) {
state.headers = {
'X-Requested-With': 'XMLHttpRequest',
};
// eslint-disable-next-line
console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
} else {
state.headers = {
'X-Requested-With': 'XMLHttpRequest',
'X-CSRF-TOKEN': token.content,
};
}
}
}
},
/**
* Initialize App settings from server
* @param state
* @param data
*/
initSettings(state, data) {
if (!state.lang) state.lang = data.lang;
if (!state.windowsConfig) state.windowsConfig = data.windowsConfig;
state.acl = data.acl;
state.hiddenFiles = data.hiddenFiles;
},
/**
* Set Hide or Show hidden files
* @param state
*/
toggleHiddenFiles(state) {
state.hiddenFiles = !state.hiddenFiles;
},
};
import mutations from './mutations';
import getters from './getters';
// languages
import ru from '../../../locales/lang/ru';
import en from '../../../locales/lang/en';
import ar from '../../../locales/lang/ar';
import sr from '../../../locales/lang/sr';
import cs from '../../../locales/lang/cs';
import de from '../../../locales/lang/de';
import es from '../../../locales/lang/es';
import nl from '../../../locales/lang/nl';
/* eslint camelcase: 0 */
import zh_CN from '../../../locales/lang/zh_CN';
import fa from '../../../locales/lang/fa';
import it from '../../../locales/lang/it';
import tr from '../../../locales/lang/tr';
import fr from '../../../locales/lang/fr';
import pt_BR from '../../../locales/lang/pt_BR';
import zh_TW from '../../../locales/lang/zh_TW';
import pl from '../../../locales/lang/pl';
export default {
namespaced: true,
state() {
return {
// ACL
acl: null,
// App version
version: '2.5.4',
// axios headers
headers: {},
// axios default URL
baseUrl: null,
/**
* File manager windows configuration
* 1 - only one file manager window
* 2 - one file manager window with directories tree module
* 3 - two file manager windows
*/
windowsConfig: null,
// App language
lang: null,
// Translations (/src/lang)
translations: {
ru: Object.freeze(ru),
en: Object.freeze(en),
ar: Object.freeze(ar),
sr: Object.freeze(sr),
cs: Object.freeze(cs),
de: Object.freeze(de),
es: Object.freeze(es),
nl: Object.freeze(nl),
'zh-CN': Object.freeze(zh_CN),
fa: Object.freeze(fa),
it: Object.freeze(it),
tr: Object.freeze(tr),
fr: Object.freeze(fr),
'pt-BR': Object.freeze(pt_BR),
'zh-TW': Object.freeze(zh_TW),
pl: Object.freeze(pl),
},
// show or hide hidden files
hiddenFiles: false,
// Context menu items
contextMenu: [
[
{
name: 'open',
icon: 'far fa-folder-open',
},
{
name: 'audioPlay',
icon: 'fas fa-play',
},
{
name: 'videoPlay',
icon: 'fas fa-play',
},
{
name: 'view',
icon: 'fas fa-eye',
},
{
name: 'edit',
icon: 'fas fa-file-signature',
},
{
name: 'select',
icon: 'fas fa-check',
},
{
name: 'download',
icon: 'fas fa-download',
},
], [
{
name: 'copy',
icon: 'far fa-copy',
},
{
name: 'cut',
icon: 'fas fa-cut',
},
{
name: 'rename',
icon: 'far fa-edit',
},
{
name: 'paste',
icon: 'far fa-clipboard',
},
{
name: 'zip',
icon: 'far fa-file-archive',
},
{
name: 'unzip',
icon: 'far fa-file-archive',
},
], [
{
name: 'delete',
icon: 'far fa-trash-alt text-danger',
},
], [
{
name: 'properties',
icon: 'far fa-list-alt',
},
],
],
// Image extensions for view and preview
imageExtensions: ['png', 'jpg', 'jpeg', 'gif'],
// Image extensions for cropping
cropExtensions: ['png', 'jpg', 'jpeg'],
// audio extensions for play
audioExtensions: ['ogg', 'mp3', 'aac', 'wav'],
// video extensions for play
videoExtensions: ['webm', 'mp4'],
// File extensions for code editor
textExtensions: {
sh: 'text/x-sh',
// styles
css: 'text/css',
less: 'text/x-less',
sass: 'text/x-sass',
scss: 'text/x-scss',
html: 'text/html',
// js
js: 'text/javascript',
ts: 'text/typescript',
vue: 'text/x-vue',
// text
htaccess: 'text/plain',
env: 'text/plain',
txt: 'text/plain',
log: 'text/plain',
ini: 'text/x-ini',
xml: 'application/xml',
md: 'text/x-markdown',
// c-like
java: 'text/x-java',
c: 'text/x-csrc',
cpp: 'text/x-c++src',
cs: 'text/x-csharp',
scl: 'text/x-scala',
php: 'application/x-httpd-php',
// DB
sql: 'text/x-sql',
// other
pl: 'text/x-perl',
py: 'text/x-python',
lua: 'text/x-lua',
swift: 'text/x-swift',
rb: 'text/x-ruby',
go: 'text/x-go',
yaml: 'text/x-yaml',
json: 'application/json',
},
};
},
mutations,
getters,
};
export default {
/**
* Active manager
* left or right
* default: left
*/
activeManager: 'left',
/**
* Clipboard
* Operation type - copy || cut
*/
clipboard: {
type: null,
disk: null,
directories: [],
files: [],
},
// available disks
disks: [],
// file callback for ckeditor, ...
fileCallback: null,
// full screen mode
fullScreen: false,
};
import GET from '../../../utils/get';
export default {
/**
* Initialize directories tree
* @param state
* @param commit
* @param disk
* @returns {Promise}
*/
initTree({ state, commit }, disk) {
return GET.tree(disk, null).then((response) => {
// if the action was successful
if (response.data.result.status === 'success') {
// clean the tree, if need
if (state.directories) commit('cleanTree');
// initialize directories tree
commit('addDirectories', {
parentId: 0,
directories: response.data.directories,
});
}
});
},
/**
* Add new directory to the tree
* @param state
* @param commit
* @param getters
* @param parentPath
* @param newDirectory
*/
addToTree({ state, commit, getters }, { parentPath, newDirectory }) {
// If this directory is not the root directory
if (parentPath) {
// find parent directory index
const parentDirectoryIndex = getters.findDirectoryIndex(parentPath);
if (parentDirectoryIndex !== -1) {
// add a new directory
commit('addDirectories', {
directories: newDirectory,
parentId: state.directories[parentDirectoryIndex].id,
});
// update parent directory property
commit('updateDirectoryProps', {
index: parentDirectoryIndex,
props: {
hasSubdirectories: true,
showSubdirectories: true,
subdirectoriesLoaded: true,
},
});
} else {
commit('fm/messages/setError', { message: 'Directory not found' }, { root: true });
}
} else {
// add a new directory to the root of the disk
commit('addDirectories', {
directories: newDirectory,
parentId: 0,
});
}
},
/**
* Delete directories and subdirectories from tree
* @param state
* @param commit
* @param getters
* @param dispatch
* @param directories
*/
deleteFromTree({
state, commit, getters, dispatch,
}, directories) {
directories.forEach((item) => {
// find this directory in the tree
const directoryIndex = getters.findDirectoryIndex(item.path);
if (directoryIndex !== -1) {
// add directory index to array for deleting
commit('addToTempArray', directoryIndex);
// if directory has subdirectories
if (state.directories[directoryIndex].props.hasSubdirectories) {
// find subDirectories
dispatch('subDirsFinder', state.directories[directoryIndex].id);
}
}
});
// filter directories
const temp = state.directories.filter((item, index) => {
if (state.tempIndexArray.indexOf(index) === -1) {
return item;
}
return false;
});
// replace directories
commit('replaceDirectories', temp);
// clear temp array
commit('clearTempArray');
},
/**
* Find subdirectories
* @param state
* @param commit
* @param dispatch
* @param parentId
*/
subDirsFinder({ state, commit, dispatch }, parentId) {
// find sub directories
state.directories.forEach((item, index) => {
if (item.parentId === parentId) {
// add directory index to array
commit('addToTempArray', index);
// if directory has subdirectories
if (item.props.hasSubdirectories) {
// find subDirectories
dispatch('subDirsFinder', item.id);
}
}
});
},
/**
* Get subDirectories from server
* @param commit
* @param rootGetters
* @param path
* @param parentId
* @param parentIndex
* @returns {Promise}
*/
getSubdirectories({ commit, rootGetters }, { path, parentId, parentIndex }) {
return GET.tree(rootGetters['fm/selectedDisk'], path).then((response) => {
// if the action was successful
if (response.data.result.status === 'success') {
// add directories
commit('addDirectories', {
parentId,
directories: response.data.directories,
});
// update properties at parent directory
commit('updateDirectoryProps', {
index: parentIndex,
props: {
subdirectoriesLoaded: true,
},
});
}
});
},
/**
* Show subdirectories
* @param state
* @param commit
* @param getters
* @param dispatch
* @param path
* @returns {*}
*/
showSubdirectories({
state, commit, getters, dispatch,
}, path) {
const promise = Promise.resolve();
// find parent directory index
const parentDirectoryIndex = getters.findDirectoryIndex(path);
if (parentDirectoryIndex !== -1) {
// Are the subdirectories loaded?
if (state.directories[parentDirectoryIndex].props.subdirectoriesLoaded) {
// update directory properties
commit('updateDirectoryProps', {
index: parentDirectoryIndex,
props: {
showSubdirectories: true,
},
});
} else {
// load subdirectories
return dispatch('getSubdirectories', {
path: state.directories[parentDirectoryIndex].path,
parentId: state.directories[parentDirectoryIndex].id,
parentIndex: parentDirectoryIndex,
}).then(() => {
// update properties in the parent directory
commit('updateDirectoryProps', {
index: parentDirectoryIndex,
props: {
showSubdirectories: true,
},
});
});
}
} else {
commit('fm/messages/setError', { message: 'Directory not found' }, { root: true });
}
return promise;
},
/**
* Hide subdirectories
* @param commit
* @param getters
* @param path
*/
hideSubdirectories({ commit, getters }, path) {
// find parent directory index
const parentDirectoryIndex = getters.findDirectoryIndex(path);
if (parentDirectoryIndex !== -1) {
// hide subdirectories
commit('updateDirectoryProps', {
index: parentDirectoryIndex,
props: {
showSubdirectories: false,
},
});
} else {
commit('fm/messages/setError', { message: 'Directory not found' }, { root: true });
}
},
/**
* Reopen tree directories by selected path
* @param dispatch
* @param path
* @returns {Promise<void>}
*/
reopenPath({ dispatch }, path) {
let promises = Promise.resolve();
if (path) {
const splitPath = path.split('/');
for (let i = 0; splitPath.length > i; i += 1) {
promises = promises.then(() => dispatch(
'showSubdirectories',
splitPath.slice(0, i + 1).join('/'),
));
}
return promises;
}
return promises;
},
};
export default {
/**
* Find directory index in the tree
* @param state
* @returns {function(*): (number | *)}
*/
findDirectoryIndex: (state) => (path) => state.directories.findIndex((el) => el.path === path),
/**
* Filtered directories list
* @param state
* @param getters
* @param rootState
* @returns {*}
*/
directories(state, getters, rootState) {
if (rootState.fm.settings.hiddenFiles) {
return state.directories;
}
return state.directories.filter((item) => item.basename.match(new RegExp('^([^.]).*', 'i')));
},
};
/* eslint-disable no-param-reassign,no-restricted-syntax */
export default {
/**
* Clean the directories tree
* @param state
*/
cleanTree(state) {
state.directories = [];
state.counter = 1;
},
/**
* Add directories to the tree
* @param state
* @param directories
* @param parentId
*/
addDirectories(state, { directories, parentId }) {
directories.forEach((directory) => {
// add properties to dir
directory.id = state.counter;
directory.parentId = parentId;
directory.props.subdirectoriesLoaded = false;
directory.props.showSubdirectories = false;
state.counter += 1;
state.directories.push(directory);
});
},
/**
* Replace directories
* @param state
* @param directories
*/
replaceDirectories(state, directories) {
state.directories = directories;
},
/**
* Update directory properties
* @param state
* @param index
* @param props
*/
updateDirectoryProps(state, { index, props }) {
for (const property in props) {
if (Object.prototype.hasOwnProperty.call(props, property)) {
state.directories[index].props[property] = props[property];
}
}
},
/**
* Add to temp index array
* @param state
* @param index
*/
addToTempArray(state, index) {
state.tempIndexArray.push(index);
},
/**
* Clear temp index array
* @param state
*/
clearTempArray(state) {
state.tempIndexArray = [];
},
};
import mutations from './mutations';
import getters from './getters';
import actions from './actions';
export default {
namespaced: true,
state() {
return {
/**
* directories.id (int), el id
* directories.basename (string), folder name
* directories.dirname (string) directory name
* directories.path (string), path to directory
* directories.props (object), directory properties
* directories.props.hasSubdirectories (boolean), has child directories,
* directories.props.subdirectoriesLoaded (boolean), child directories loaded
* directories.props.showSubdirectories (boolean), show or hide subdirectories branch
* directories.parentId (int), parent id
*/
directories: [],
// directories id counter
counter: 1,
// directories array for deleting(indexes)
tempIndexArray: [],
};
},
mutations,
getters,
actions,
};
import Vue from 'vue' import Vue from 'vue'
import Vuex from 'vuex' import Vuex from 'vuex'
import fm from './file-manager'
import global from './modules/global' import global from './modules/global'
import globalNav from './modules/global-nav' import globalNav from './modules/global-nav'
import frontendOpenapi from './modules/frontend-openapi' import frontendOpenapi from './modules/frontend-openapi'
...@@ -15,6 +16,7 @@ export default new Vuex.Store({ ...@@ -15,6 +16,7 @@ export default new Vuex.Store({
openapi: frontendOpenapi openapi: frontendOpenapi
} }
}, },
fm: fm,
global: { global: {
namespaced: true, namespaced: true,
...global, ...global,
...@@ -22,5 +24,5 @@ export default new Vuex.Store({ ...@@ -22,5 +24,5 @@ export default new Vuex.Store({
nav: globalNav nav: globalNav
} }
} }
} },
}) })
...@@ -40,7 +40,6 @@ const mutations = { ...@@ -40,7 +40,6 @@ const mutations = {
pageSize: config.results pageSize: config.results
} }
} }
// console.log(state.users.pagination)
} }
} }
......
import axios from 'axios';
const HTTP = axios.create();
export default {
/**
* Get configuration data from server
* @returns {*}
*/
initialize() {
return HTTP.get('initialize');
},
/**
* Get directories for the tree (upper level)
* @param disk
* @param path
* @returns {*}
*/
tree(disk, path) {
return HTTP.get('tree', { params: { disk, path } });
},
/**
* Select disk
* @param disk
* @returns {*}
*/
selectDisk(disk) {
return HTTP.get('select-disk', { params: { disk } });
},
/**
* Get content (files and folders)
* @param disk
* @param path
* @returns {*}
*/
content(disk, path) {
return HTTP.get('content', { params: { disk, path } });
},
/**
* Item properties
*/
/* properties(disk, path) {
return HTTP.get('properties', { params: { disk, path } });
}, */
/**
* URL
* @param disk
* @param path
* @returns {*}
*/
url(disk, path) {
return HTTP.get('url', { params: { disk, path } });
},
/**
* Get file to editing or showing
* @param disk
* @param path
* @returns {*}
*/
getFile(disk, path) {
return HTTP.get('download', { params: { disk, path } });
},
/**
* Get file - ArrayBuffer
* @param disk
* @param path
* @returns {*}
*/
getFileArrayBuffer(disk, path) {
return HTTP.get('download', {
responseType: 'arraybuffer',
params: { disk, path },
});
},
/**
* Image thumbnail
* @param disk
* @param path
* @returns {*}
*/
thumbnail(disk, path) {
return HTTP.get('thumbnails', {
responseType: 'arraybuffer',
params: { disk, path },
});
},
/**
* Image preview
* @param disk
* @param path
* @return {*}
*/
preview(disk, path) {
return HTTP.get('preview', {
responseType: 'arraybuffer',
params: { disk, path },
});
},
/**
* Download file
* @param disk
* @param path
* @return {*}
*/
download(disk, path) {
return HTTP.get('download', {
responseType: 'arraybuffer',
params: { disk, path },
});
},
};
export default {
methods: {
/**
* Bytes to KB, MB, ..
* @param bytes
* @returns {string}
*/
bytesToHuman(bytes) {
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
if (bytes === 0) return '0 Bytes';
const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)), 10);
if (i === 0) return `${bytes} ${sizes[i]}`;
return `${(bytes / (1024 ** i)).toFixed(1)} ${sizes[i]}`;
},
/**
* Timestamp to date
* @param timestamp
* @returns {string}
*/
timestampToDate(timestamp) {
// if date not defined
if (timestamp === undefined) return '-';
const date = new Date(timestamp * 1000);
return date.toLocaleString(this.$store.state.fm.settings.lang);
},
/**
* Mime type to icon
* @param mime
* @returns {*}
*/
mimeToIcon(mime) {
// mime types
const mimeTypes = {
// image
'image/gif': 'fa-file-image',
'image/png': 'fa-file-image',
'image/jpeg': 'fa-file-image',
'image/bmp': 'fa-file-image',
'image/webp': 'fa-file-image',
'image/tiff': 'fa-file-image',
'image/svg+xml': 'fa-file-image',
// text
'text/plain': 'fa-file-alt',
// code
'text/javascript': 'fa-file-code',
'application/json': 'fa-file-code',
'text/markdown': 'fa-file-code',
'text/html': 'fa-file-code',
'text/css': 'fa-file-code',
// audio
'audio/midi': 'fa-file-audio',
'audio/mpeg': 'fa-file-audio',
'audio/webm': 'fa-file-audio',
'audio/ogg': 'fa-file-audio',
'audio/wav': 'fa-file-audio',
'audio/aac': 'fa-file-audio',
'audio/x-wav': 'fa-file-audio',
'audio/mp4': 'fa-file-audio',
// video
'video/webm': 'fa-file-video',
'video/ogg': 'fa-file-video',
'video/mpeg': 'fa-file-video',
'video/3gpp': 'fa-file-video',
'video/x-flv': 'fa-file-video',
'video/mp4': 'fa-file-video',
'video/quicktime': 'fa-file-video',
'video/x-msvideo': 'fa-file-video',
'video/vnd.dlna.mpeg-tts': 'fa-file-video',
// archive
'application/x-bzip': 'fa-file-archive',
'application/x-bzip2': 'fa-file-archive',
'application/x-tar': 'fa-file-archive',
'application/gzip': 'fa-file-archive',
'application/zip': 'fa-file-archive',
'application/x-7z-compressed': 'fa-file-archive',
'application/x-rar-compressed': 'fa-file-archive',
// application
'application/pdf': 'fa-file-pdf',
'application/rtf': 'fa-file-word',
'application/msword': 'fa-file-word',
'application/vnd.ms-word': 'fa-file-word',
'application/vnd.ms-excel': 'fa-file-excel',
'application/vnd.ms-powerpoint': 'fa-file-powerpoint',
'application/vnd.oasis.opendocument.text': 'fa-file-word',
'application/vnd.oasis.opendocument.spreadsheet': 'fa-file-excel',
'application/vnd.oasis.opendocument.presentation': 'fa-file-powerpoint',
'application/vnd.openxmlformats-officedocument.wordprocessingml': 'fa-file-word',
'application/vnd.openxmlformats-officedocument.spreadsheetml': 'fa-file-excel',
'application/vnd.openxmlformats-officedocument.presentationml': 'fa-file-powerpoint',
};
if (mimeTypes[mime] !== undefined) {
return mimeTypes[mime];
}
// file blank
return 'fa-file';
},
/**
* File extension to icon (font awesome)
* @returns {*}
* @param extension
*/
extensionToIcon(extension) {
// files extensions
const extensionTypes = {
// images
gif: 'fa-file-image',
png: 'fa-file-image',
jpeg: 'fa-file-image',
jpg: 'fa-file-image',
bmp: 'fa-file-image',
psd: 'fa-file-image',
svg: 'fa-file-image',
ico: 'fa-file-image',
ai: 'fa-file-image',
tif: 'fa-file-image',
tiff: 'fa-file-image',
// text
txt: 'fa-file-alt',
json: 'fa-file-alt',
log: 'fa-file-alt',
ini: 'fa-file-alt',
xml: 'fa-file-alt',
md: 'fa-file-alt',
env: 'fa-file-alt',
// code
js: 'fa-file-code',
php: 'fa-file-code',
css: 'fa-file-code',
cpp: 'fa-file-code',
class: 'fa-file-code',
h: 'fa-file-code',
java: 'fa-file-code',
sh: 'fa-file-code',
swift: 'fa-file-code',
// audio
aif: 'fa-file-audio',
cda: 'fa-file-audio',
mid: 'fa-file-audio',
mp3: 'fa-file-audio',
mpa: 'fa-file-audio',
ogg: 'fa-file-audio',
wav: 'fa-file-audio',
wma: 'fa-file-audio',
// video
wmv: 'fa-file-video',
avi: 'fa-file-video',
mpeg: 'fa-file-video',
mpg: 'fa-file-video',
flv: 'fa-file-video',
mp4: 'fa-file-video',
mkv: 'fa-file-video',
mov: 'fa-file-video',
ts: 'fa-file-video',
'3gpp': 'fa-file-video',
// archive
zip: 'fa-file-archive',
arj: 'fa-file-archive',
deb: 'fa-file-archive',
pkg: 'fa-file-archive',
rar: 'fa-file-archive',
rpm: 'fa-file-archive',
'7z': 'fa-file-archive',
'tar.gz': 'fa-file-archive',
// application
pdf: 'fa-file-pdf',
rtf: 'fa-file-word',
doc: 'fa-file-word',
docx: 'fa-file-word',
odt: 'fa-file-word',
xlr: 'fa-file-excel',
xls: 'fa-file-excel',
xlsx: 'fa-file-excel',
ppt: 'fa-file-powerpoint',
pptx: 'fa-file-powerpoint',
pptm: 'fa-file-powerpoint',
xps: 'fa-file-powerpoint',
potx: 'fa-file-powerpoint',
};
if (extension && extensionTypes[extension.toLowerCase()] !== undefined) {
return extensionTypes[extension.toLowerCase()];
}
// blank file
return 'fa-file';
},
},
};
import axios from 'axios';
const HTTP = axios.create();
export default {
/**
* Create new file
* @param disk
* @param path
* @param name
* @returns {AxiosPromise<any>}
*/
createFile(disk, path, name) {
return HTTP.post('create-file', { disk, path, name });
},
/**
* Update file
* @param formData
* @returns {*}
*/
updateFile(formData) {
return HTTP.post('update-file', formData);
},
/**
* Create new directory
* @param data
* @returns {*}
*/
createDirectory(data) {
return HTTP.post('create-directory', data);
},
/**
* Upload file
* @param data
* @param config
* @returns {AxiosPromise<any>}
*/
upload(data, config) {
return HTTP.post('upload', data, config);
},
/**
* Delete selected items
* @param data
* @returns {*}
*/
delete(data) {
return HTTP.post('delete', data);
},
/**
* Rename file or folder
* @param data
* @returns {*}
*/
rename(data) {
return HTTP.post('rename', data);
},
/**
* Copy / Cut files and folders
* @param data
* @returns {*}
*/
paste(data) {
return HTTP.post('paste', data);
},
/**
* Zip
* @param data
* @returns {*}
*/
zip(data) {
return HTTP.post('zip', data);
},
/**
* Unzip
* @returns {*}
* @param data
*/
unzip(data) {
return HTTP.post('unzip', data);
},
};
export default {
computed: {
/**
* Selected translate
* @returns {*}
*/
lang() {
// If selected translations exists
if (Object.prototype.hasOwnProperty.call(
this.$store.state.fm.settings.translations,
this.$store.state.fm.settings.lang,
)) {
return this.$store.state.fm.settings.translations[
this.$store.state.fm.settings.lang
];
}
// default translate - en
return this.$store.state.fm.settings.translations.en;
},
},
};
<template>
<div
class="fm d-flex flex-column"
v-bind:class="{ 'fm-full-screen': fullScreen }"
>
<navbar />
<div class="fm-body">
<notification />
<context-menu />
<modal v-if="showModal" />
<template v-if="windowsConfig === 1">
<left-manager class="col" manager="left" />
</template>
<template v-else-if="windowsConfig === 2">
<folder-tree class="col-4 col-md-3" />
<left-manager class="col-8 col-md-9" manager="left" />
</template>
<template v-else-if="windowsConfig === 3">
<left-manager
class="col-12 col-sm-6"
manager="left"
v-on:click.native="selectManager('left')"
v-on:contextmenu.native="selectManager('left')"
>
</left-manager>
<right-manager
class="col-12 col-sm-6"
manager="right"
v-on:click.native="selectManager('right')"
v-on:contextmenu.native="selectManager('right')"
>
</right-manager>
</template>
</div>
<info-block />
</div>
</template>
<script>
/* eslint-disable import/no-duplicates, no-param-reassign */
import { mapState } from "vuex";
// Axios
import axios from 'axios';
const HTTP = axios.create();
import EventBus from "@/utils/eventBus";
// Components
import Navbar from "./components/blocks/Navbar.vue";
import FolderTree from "./components/tree/FolderTree.vue";
import LeftManager from "./components/manager/Manager.vue";
import RightManager from "./components/manager/Manager.vue";
import Modal from "./components/modals/Modal.vue";
import InfoBlock from "./components/blocks/InfoBlock.vue";
import ContextMenu from "./components/blocks/ContextMenu.vue";
import Notification from "./components/blocks/Notification.vue";
// Mixins
import translate from "@/utils/translate";
export default {
name: "FileManager",
mixins: [translate],
components: {
Navbar,
FolderTree,
LeftManager,
RightManager,
Modal,
InfoBlock,
ContextMenu,
Notification,
},
props: {
/**
* LFM manual settings
*/
settings: {
type: Object,
default() {
return {};
},
},
},
data() {
return {
interceptorIndex: {
request: null,
response: null,
},
};
},
created() {
// manual settings
this.$store.commit("fm/settings/manualSettings", this.settings);
// initiate Axios
this.$store.commit("fm/settings/initAxiosSettings");
this.requestInterceptor();
this.responseInterceptor();
// initialize app settings
this.$store.dispatch("fm/initializeApp");
/**
* todo Keyboard event
*/
/*
window.addEventListener('keyup', (event) => {
event.preventDefault();
event.stopPropagation();
EventBus.$emit('keyMonitor', event);
});
*/
},
destroyed() {
// reset state
this.$store.dispatch("fm/resetState");
// delete events
EventBus.$off(["contextMenu", "addNotification"]);
// eject interceptors
HTTP.interceptors.request.eject(this.interceptorIndex.request);
HTTP.interceptors.response.eject(this.interceptorIndex.response);
},
computed: {
...mapState("fm", {
windowsConfig: (state) => state.settings.windowsConfig,
activeManager: (state) => state.settings.activeManager,
showModal: (state) => state.modal.showModal,
fullScreen: (state) => state.settings.fullScreen,
}),
},
methods: {
/**
* Add axios request interceptor
*/
requestInterceptor() {
this.interceptorIndex.request = HTTP.interceptors.request.use(
(config) => {
// overwrite base url and headers
config.baseURL = this.$store.getters["fm/settings/baseUrl"];
config.headers = this.$store.getters["fm/settings/headers"];
// loading spinner +
this.$store.commit("fm/messages/addLoading");
return config;
},
(error) => {
// loading spinner -
this.$store.commit("fm/messages/subtractLoading");
return Promise.reject(error);
}
);
},
/**
* Add axios response interceptor
*/
responseInterceptor() {
this.interceptorIndex.response = HTTP.interceptors.response.use(
(response) => {
// loading spinner -
this.$store.commit("fm/messages/subtractLoading");
// create notification, if find message text
if (Object.prototype.hasOwnProperty.call(response.data, "result")) {
if (response.data.result.message) {
const message = {
status: response.data.result.status,
message: Object.prototype.hasOwnProperty.call(
this.lang.response,
response.data.result.message
)
? this.lang.response[response.data.result.message]
: response.data.result.message,
};
// show notification
EventBus.$emit("addNotification", message);
// set action result
this.$store.commit("fm/messages/setActionResult", message);
}
}
return response;
},
(error) => {
// loading spinner -
this.$store.commit("fm/messages/subtractLoading");
const errorMessage = {
status: 0,
message: "",
};
const errorNotificationMessage = {
status: "error",
message: "",
};
// add message
if (error.response) {
errorMessage.status = error.response.status;
if (error.response.data.message) {
const trMessage = Object.prototype.hasOwnProperty.call(
this.lang.response,
error.response.data.message
)
? this.lang.response[error.response.data.message]
: error.response.data.message;
errorMessage.message = trMessage;
errorNotificationMessage.message = trMessage;
} else {
errorMessage.message = error.response.statusText;
errorNotificationMessage.message = error.response.statusText;
}
} else if (error.request) {
errorMessage.status = error.request.status;
errorMessage.message = error.request.statusText || "Network error";
errorNotificationMessage.message =
error.request.statusText || "Network error";
} else {
errorMessage.message = error.message;
errorNotificationMessage.message = error.message;
}
// set error message
this.$store.commit("fm/messages/setError", errorMessage);
// show notification
EventBus.$emit("addNotification", errorNotificationMessage);
return Promise.reject(error);
}
);
},
/**
* Select manager (when shown 2 file manager windows)
* @param managerName
*/
selectManager(managerName) {
if (this.activeManager !== managerName) {
this.$store.commit("fm/setActiveManager", managerName);
}
},
},
};
</script>
<style lang="scss">
@import "~plyr/src/sass/plyr.scss";
.fm {
position: relative;
height: 100%;
padding: 1rem 1rem 0;
background-color: white;
&:-moz-full-screen {
background-color: white;
}
&:-webkit-full-screen {
background-color: white;
}
&:fullscreen {
background-color: white;
}
.fm-body {
display: flex;
height: 100%;
margin-right: -15px;
margin-left: -15px;
position: relative;
padding-top: 1rem;
padding-bottom: 1rem;
border-top: 1px solid #6d757d;
border-bottom: 1px solid #6d757d;
}
.unselectable {
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
}
.fm-error {
color: white;
background-color: #dc3545;
border-color: #dc3545;
}
.fm-danger {
color: #dc3545;
background-color: white;
border-color: #dc3545;
}
.fm-warning {
color: #ffc107;
background-color: white;
border-color: #ffc107;
}
.fm-success {
color: #28a745;
background-color: white;
border-color: #28a745;
}
.fm-info {
color: #17a2b8;
background-color: white;
border-color: #17a2b8;
}
.fm.fm-full-screen {
width: 100%;
height: 100%;
padding-bottom: 0;
}
</style>
<template>
<div
ref="contextMenu"
v-if="menuVisible"
v-bind:style="menuStyle"
v-on:blur="closeMenu"
class="fm-context-menu"
tabindex="-1"
>
<ul
v-for="(group, index) in menu"
v-bind:key="`g-${index}`"
class="list-unstyled"
>
<li
v-for="(item, index) in group"
v-bind:key="`i-${index}`"
v-on:click="menuAction(item.name)"
>
<template v-if="showMenuItem(item.name)">
<i class="fa-fw" v-bind:class="item.icon" />
{{ lang.contextMenu[item.name] }}
</template>
</li>
</ul>
</div>
</template>
<script>
/* eslint-disable no-param-reassign */
import EventBus from "@/utils/eventBus";
import translate from "@/utils/translate";
import contextMenu from "./mixins/contextMenu";
import contextMenuRules from "./mixins/contextMenuRules";
import contextMenuActions from "./mixins/contextMenuActions";
export default {
name: "ContextMenu",
mixins: [translate, contextMenu, contextMenuRules, contextMenuActions],
data() {
return {
menuVisible: false,
menuStyle: {
top: 0,
left: 0,
},
};
},
mounted() {
/**
* Listen events
* 'contextMenu'
*/
EventBus.$on("contextMenu", (event) => this.showMenu(event));
},
computed: {
/**
* Context menu items
* @returns {*}
*/
menu() {
return this.$store.state.fm.settings.contextMenu;
},
},
methods: {
/**
* Show context menu
* @param event
*/
showMenu(event) {
if (this.selectedItems) {
this.menuVisible = true;
// focus on menu
this.$nextTick(() => {
this.$refs.contextMenu.focus();
// set menu params
this.setMenu(event.pageY, event.pageX);
});
}
},
/**
* Set context menu coordinates
* @param top
* @param left
*/
setMenu(top, left) {
// get parent el (.fm-body)
const el = this.$refs.contextMenu.parentNode;
// get parent el size
const elSize = el.getBoundingClientRect();
// actual coordinates of the block
const elY = window.pageYOffset + elSize.top;
const elX = window.pageXOffset + elSize.left;
// calculate the preliminary coordinates
let menuY = top - elY;
let menuX = left - elX;
// calculate max X and Y coordinates
const maxY =
elY + (el.offsetHeight - this.$refs.contextMenu.offsetHeight - 25);
const maxX =
elX + (el.offsetWidth - this.$refs.contextMenu.offsetWidth - 25);
if (top > maxY) menuY = maxY - elY;
if (left > maxX) menuX = maxX - elX;
// set coordinates
this.menuStyle.top = `${menuY}px`;
this.menuStyle.left = `${menuX}px`;
},
/**
* Close context menu
*/
closeMenu() {
this.menuVisible = false;
},
/**
* Show context menu item
* @param name
* @returns {*}
*/
showMenuItem(name) {
if (Object.prototype.hasOwnProperty.call(this, `${name}Rule`)) {
return this[`${name}Rule`]();
}
return false;
},
/**
* Call actions when clicking the context menu
* @param name
*/
menuAction(name) {
if (Object.prototype.hasOwnProperty.call(this, `${name}Action`)) {
this[`${name}Action`]();
}
// close context menu
this.closeMenu();
},
},
};
</script>
<style lang="scss">
.fm-context-menu {
position: absolute;
z-index: 9997;
background-color: white;
box-shadow: 3px 2px 5px gray;
border-radius: 5px;
&:focus {
outline: none;
}
.list-unstyled {
margin-bottom: 0;
border-bottom: 1px solid rgba(0, 0, 0, 0.125);
}
ul > li {
padding: 0.4rem 1rem;
}
ul > li:not(.disabled) {
cursor: pointer;
&:hover {
background-color: #f8f9fa;
}
i {
padding-right: 2rem;
}
}
}
</style>
<template>
<div class="justify-content-between fm-info-block">
<div class="col-auto">
<span v-show="selectedCount">
{{ `${lang.info.selected} ${selectedCount}` }}
{{ `${lang.info.selectedSize} ${selectedFilesSize}` }}
</span>
<span v-show="!selectedCount">
{{ `${lang.info.directories} ${directoriesCount}` }}
{{ `${lang.info.files} ${filesCount}` }}
{{ `${lang.info.size} ${filesSize}`}}
</span>
</div>
<div class="col-4">
<!-- Progress Bar -->
<div class="progress" v-show="progressBar">
<div class="progress-bar progress-bar-striped bg-info" role="progressbar"
v-bind:aria-valuenow="progressBar"
aria-valuemin="0"
aria-valuemax="100"
v-bind:style="{width: progressBar + '%' }">
{{ progressBar }}%
</div>
</div>
</div>
<div class="col-auto text-right">
<span v-show="loadingSpinner">
<i class="fas fa-spinner fa-pulse"/>
</span>
<span v-show="clipboardType"
v-on:click="showModal('Clipboard')"
v-bind:title="[ lang.clipboard.title + ' - ' + lang.clipboard[clipboardType] ]">
<i class="far fa-clipboard"/>
</span>
<span v-on:click="showModal('Status')"
v-bind:class="[hasErrors ? 'text-danger' : 'text-success']"
v-bind:title="lang.modal.status.title">
<i class="fas fa-info-circle"/>
</span>
</div>
</div>
</template>
<script>
import translate from '@/utils/translate';
import helper from '@/utils/helper';
export default {
name: 'InfoBlock',
mixins: [translate, helper],
computed: {
/**
* Active manager
* @returns {default.computed.activeManager|(function())|string|activeManager}
*/
activeManager() {
return this.$store.state.fm.activeManager;
},
/**
* Progress bar value - %
* @returns {number}
*/
progressBar() {
return this.$store.state.fm.messages.actionProgress;
},
/**
* App has errors
* @returns {boolean}
*/
hasErrors() {
return !!this.$store.state.fm.messages.errors.length;
},
/**
* Files count in selected directory
* @returns {*}
*/
filesCount() {
return this.$store.getters[`fm/${this.activeManager}/filesCount`];
},
/**
* Directories count in selected directory
* @returns {*}
*/
directoriesCount() {
return this.$store.getters[`fm/${this.activeManager}/directoriesCount`];
},
/**
* Files size in selected directory
* @returns {*|string}
*/
filesSize() {
return this.bytesToHuman(this.$store.getters[`fm/${this.activeManager}/filesSize`]);
},
/**
* Count files and folders
* @returns {*}
*/
selectedCount() {
return this.$store.getters[`fm/${this.activeManager}/selectedCount`];
},
/**
* Calculate selected files size
* @returns {*|string}
*/
selectedFilesSize() {
return this.bytesToHuman(this.$store.getters[`fm/${this.activeManager}/selectedFilesSize`]);
},
/**
* Clipboard - action type
* @returns {null}
*/
clipboardType() {
return this.$store.state.fm.clipboard.type;
},
/**
* Spinner
* @returns {number}
*/
loadingSpinner() {
return this.$store.state.fm.messages.loading;
},
},
methods: {
/**
* Show modal window
* @param modalName
*/
showModal(modalName) {
this.$store.commit('fm/modal/setModalState', {
modalName,
show: true,
});
},
},
};
</script>
<style lang="scss">
.fm-info-block {
display: flex;
margin-right: -15px;
margin-left: -15px;
padding-top: 0.2rem;
padding-bottom: 0.4rem;
border-bottom: 1px solid #6d757d;
.progress {
margin-top: 0.3rem;
}
.text-right > span {
padding-left: 0.5rem;
cursor: pointer;
}
}
</style>
<template>
<div class="fm-navbar mb-3">
<div class="row justify-content-between">
<div class="col-auto">
<div class="btn-group" role="group">
<button type="button" class="btn btn-secondary"
v-bind:disabled="backDisabled"
v-bind:title="lang.btn.back"
v-on:click="historyBack()">
<i class="fas fa-step-backward"/>
</button>
<button type="button" class="btn btn-secondary"
v-bind:disabled="forwardDisabled"
v-bind:title="lang.btn.forward"
v-on:click="historyForward()">
<i class="fas fa-step-forward"/>
</button>
<button type="button" class="btn btn-secondary"
v-on:click="refreshAll()"
v-bind:title="lang.btn.refresh">
<i class="fas fa-sync-alt"/>
</button>
</div>
<div class="btn-group" role="group">
<button type="button" class="btn btn-secondary"
v-on:click="showModal('NewFile')"
v-bind:title="lang.btn.file">
<i class="far fa-file"/>
</button>
<button type="button" class="btn btn-secondary"
v-on:click="showModal('NewFolder')"
v-bind:title="lang.btn.folder">
<i class="far fa-folder"/>
</button>
<button type="button" class="btn btn-secondary"
disabled
v-if="uploading"
v-bind:title="lang.btn.upload">
<i class="fas fa-upload"/>
</button>
<button type="button" class="btn btn-secondary"
v-else
v-on:click="showModal('Upload')"
v-bind:title="lang.btn.upload">
<i class="fas fa-upload"/>
</button>
<button type="button" class="btn btn-secondary"
v-bind:disabled="!isAnyItemSelected"
v-on:click="showModal('Delete')"
v-bind:title="lang.btn.delete">
<i class="fas fa-trash-alt"/>
</button>
</div>
<div class="btn-group" role="group">
<button type="button" class="btn btn-secondary"
v-bind:disabled="!isAnyItemSelected"
v-bind:title="lang.btn.copy"
v-on:click="toClipboard('copy')">
<i class="fas fa-copy"/>
</button>
<button type="button" class="btn btn-secondary"
v-bind:disabled="!isAnyItemSelected"
v-bind:title="lang.btn.cut"
v-on:click="toClipboard('cut')">
<i class="fas fa-cut"/>
</button>
<button type="button" class="btn btn-secondary"
v-bind:disabled="!clipboardType"
v-bind:title="lang.btn.paste"
v-on:click="paste">
<i class="fas fa-paste"/>
</button>
</div>
<div class="btn-group" role="group">
<button type="button" class="btn btn-secondary"
v-bind:title="lang.btn.hidden"
v-on:click="toggleHidden">
<i class="fas" v-bind:class="[hiddenFiles ? 'fa-eye': 'fa-eye-slash']"/>
</button>
</div>
</div>
<div class="col-auto text-right">
<div class="btn-group" role="group">
<button type="button" class="btn btn-secondary"
v-bind:class="[viewType === 'table' ? 'active' : '']"
v-on:click="selectView('table')"
v-bind:title="lang.btn.table">
<i class="fas fa-th-list"/>
</button>
<button role="button" class="btn btn-secondary"
v-bind:class="[viewType === 'grid' ? 'active' : '']"
v-on:click="selectView('grid')"
v-bind:title="lang.btn.grid">
<i class="fas fa-th"/>
</button>
</div>
<div class="btn-group" role="group">
<button type="button" class="btn btn-secondary"
v-bind:title="lang.btn.fullScreen"
v-bind:class="{ active: fullScreen }"
v-on:click="screenToggle">
<i class="fas fa-expand-arrows-alt"/>
</button>
</div>
<div class="btn-group" role="group">
<button type="button" class="btn btn-secondary"
v-bind:title="lang.btn.about"
v-on:click="showModal('About')">
<i class="fas fa-question"/>
</button>
</div>
</div>
</div>
</div>
</template>
<script>
import translate from '@/utils/translate';
import EventBus from '@/utils/eventBus';
export default {
mixins: [translate],
computed: {
/**
* Active manager name
* @returns {default.computed.activeManager|(function())|string|activeManager}
*/
activeManager() {
return this.$store.state.fm.activeManager;
},
/**
* Back button state
* @returns {boolean}
*/
backDisabled() {
return !this.$store.state.fm[this.activeManager].historyPointer;
},
/**
* Forward button state
* @returns {boolean}
*/
forwardDisabled() {
return this.$store.state.fm[this.activeManager].historyPointer
=== this.$store.state.fm[this.activeManager].history.length - 1;
},
/**
* Is any files or directories selected?
* @returns {boolean}
*/
isAnyItemSelected() {
return this.$store.state.fm[this.activeManager].selected.files.length > 0
|| this.$store.state.fm[this.activeManager].selected.directories.length > 0;
},
/**
* Manager view type - grid or table
* @returns {default.computed.viewType|(function())|string}
*/
viewType() {
return this.$store.state.fm[this.activeManager].viewType;
},
/**
* Upload files
* @returns {boolean}
*/
uploading() {
return this.$store.state.fm.messages.actionProgress > 0;
},
/**
* Clipboard - action type
* @returns {null}
*/
clipboardType() {
return this.$store.state.fm.clipboard.type;
},
/**
* Full screen status
* @returns {default.computed.fullScreen|(function())|boolean|fullScreen|*|string}
*/
fullScreen() {
return this.$store.state.fm.fullScreen;
},
/**
* Show or Hide hidden files
* @returns {boolean}
*/
hiddenFiles() {
return this.$store.state.fm.settings.hiddenFiles;
},
},
methods: {
/**
* Refresh file manager
*/
refreshAll() {
this.$store.dispatch('fm/refreshAll');
},
/**
* History back
*/
historyBack() {
this.$store.dispatch(`fm/${this.activeManager}/historyBack`);
},
/**
* History forward
*/
historyForward() {
this.$store.dispatch(`fm/${this.activeManager}/historyForward`);
},
/**
* Copy
* @param type
*/
toClipboard(type) {
this.$store.dispatch('fm/toClipboard', type);
// show notification
if (type === 'cut') {
EventBus.$emit('addNotification', {
status: 'success',
message: this.lang.notifications.cutToClipboard,
});
} else if (type === 'copy') {
EventBus.$emit('addNotification', {
status: 'success',
message: this.lang.notifications.copyToClipboard,
});
}
},
/**
* Paste
*/
paste() {
this.$store.dispatch('fm/paste');
},
/**
* Set Hide or Show hidden files
*/
toggleHidden() {
this.$store.commit('fm/settings/toggleHiddenFiles');
},
/**
* Show modal window
* @param modalName
*/
showModal(modalName) {
// show selected modal
this.$store.commit('fm/modal/setModalState', {
modalName,
show: true,
});
},
/**
* Select view type
* @param type
*/
selectView(type) {
if (this.viewType !== type) this.$store.commit(`fm/${this.activeManager}/setView`, type);
},
/**
* Full screen toggle
*/
screenToggle() {
const fm = document.getElementsByClassName('fm')[0];
if (!this.fullScreen) {
if (fm.requestFullscreen) {
fm.requestFullscreen();
} else if (fm.mozRequestFullScreen) {
fm.mozRequestFullScreen();
} else if (fm.webkitRequestFullscreen) {
fm.webkitRequestFullscreen();
} else if (fm.msRequestFullscreen) {
fm.msRequestFullscreen();
}
} else if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
}
this.$store.commit('fm/screenToggle');
},
},
};
</script>
<style lang="scss">
.fm-navbar {
.btn-group {
margin-right: 0.4rem;
}
}
</style>
<template>
<div class="fm-notification">
<transition-group name="notify">
<div class="fm-notification-item" role="alert"
v-for="(notification, index) in notifications"
v-bind:class="`fm-${notification.status}`"
v-bind:key="`notify-${index}`">
{{ notification.message }}
</div>
</transition-group>
</div>
</template>
<script>
import EventBus from '@/utils/eventBus';
export default {
name: 'notification',
data() {
return {
notifications: [],
};
},
mounted() {
/**
* Listen 'addNotification' events
*/
EventBus.$on('addNotification', ({ status, message }) => this.addNotification(status, message));
},
methods: {
/**
* Show new notification
* @param status
* @param message
*/
addNotification(status, message) {
this.notifications.push({
status, message,
});
// timeout for closing
setTimeout(() => {
this.notifications.shift();
}, 3000);
},
},
};
</script>
<style lang="scss">
.fm-notification {
position: absolute;
right: 1rem;
bottom: 0;
z-index: 9999;
width: 350px;
display: block;
transition: opacity .4s ease;
overflow: auto;
.fm-notification-item {
padding: .75rem 1.25rem;
margin-bottom: 1rem;
border: 1px solid;
border-radius: .25rem;
}
.notify-enter-active {
transition: all .3s ease;
}
.notify-leave-active {
transition: all .8s ease;
}
.notify-enter, .notify-leave-to {
opacity: 0;
}
}
</style>
export default {
computed: {
/**
* Selected disk
* @returns {*}
*/
selectedDisk() {
return this.$store.getters['fm/selectedDisk'];
},
/**
* Selected items
* @returns {*}
*/
selectedItems() {
return this.$store.getters['fm/selectedItems'];
},
/**
* Driver for selected disk
* @returns {*}
*/
selectedDiskDriver() {
return this.$store.state.fm.disks[this.selectedDisk].driver;
},
/**
* Multi selection
* @returns {boolean}
*/
multiSelect() {
return this.$store.getters['fm/selectedItems'].length > 1;
},
/**
* First item type - dir or file
* @returns {*}
*/
firstItemType() {
return this.$store.getters['fm/selectedItems'][0].type;
},
},
methods: {
/**
* Can we show this item?
* @param extension
* @returns {boolean}
*/
canView(extension) {
// extension not found
if (!extension) return false;
return this.$store.state.fm.settings.imageExtensions.includes(extension.toLowerCase());
},
/**
* Can we edit this file in the code editor?
* @param extension
* @returns {boolean}
*/
canEdit(extension) {
// extension not found
if (!extension) return false;
return Object.keys(this.$store.state.fm.settings.textExtensions)
.includes(extension.toLowerCase());
},
/**
* Can we play this audio file?
* @param extension
* @returns {boolean}
*/
canAudioPlay(extension) {
// extension not found
if (!extension) return false;
return this.$store.state.fm.settings.audioExtensions.includes(extension.toLowerCase());
},
/**
* Can we play this video file?
* @param extension
* @returns {boolean}
*/
canVideoPlay(extension) {
// extension not found
if (!extension) return false;
return this.$store.state.fm.settings.videoExtensions.includes(extension.toLowerCase());
},
/**
* Zip archive or not
* @param extension
* @returns {boolean}
*/
isZip(extension) {
// extension not found
if (!extension) return false;
return extension.toLowerCase() === 'zip';
},
},
};
import HTTP from '@/utils/get';
/**
* Context menu actions
* {name}Action
*/
export default {
methods: {
/**
* Open folder
*/
openAction() {
// select directory
this.$store.dispatch(`fm/${this.$store.state.fm.activeManager}/selectDirectory`, {
path: this.selectedItems[0].path,
history: true,
});
},
/**
* Play music or video
*/
audioPlayAction() {
// show player modal
this.$store.commit('fm/modal/setModalState', {
modalName: 'AudioPlayer',
show: true,
});
},
/**
* Play music or video
*/
videoPlayAction() {
// show player modal
this.$store.commit('fm/modal/setModalState', {
modalName: 'VideoPlayer',
show: true,
});
},
/**
* View file
*/
viewAction() {
// show image
this.$store.commit('fm/modal/setModalState', {
modalName: 'Preview',
show: true,
});
},
/**
* Edit file
*/
editAction() {
// show text file
this.$store.commit('fm/modal/setModalState', {
modalName: 'TextEdit',
show: true,
});
},
/**
* Select file
*/
selectAction() {
// file callback
this.$store.dispatch('fm/url', {
disk: this.selectedDisk,
path: this.selectedItems[0].path,
}).then((response) => {
if (response.data.result.status === 'success') {
this.$store.state.fm.fileCallback(response.data.url);
}
});
},
/**
* Download file
*/
downloadAction() {
const tempLink = document.createElement('a');
tempLink.style.display = 'none';
tempLink.setAttribute('download', this.selectedItems[0].basename);
// download file with authorization
if (this.$store.getters['fm/settings/authHeader']) {
HTTP.download(this.selectedDisk, this.selectedItems[0].path).then((response) => {
tempLink.href = window.URL.createObjectURL(new Blob([response.data]));
document.body.appendChild(tempLink);
tempLink.click();
document.body.removeChild(tempLink);
});
} else {
tempLink.href = `${this.$store.getters['fm/settings/baseUrl']}download?disk=${this.selectedDisk}&path=${encodeURIComponent(this.selectedItems[0].path)}`;
document.body.appendChild(tempLink);
tempLink.click();
document.body.removeChild(tempLink);
}
},
/**
* Copy selected items
*/
copyAction() {
// add selected items to the clipboard
this.$store.dispatch('fm/toClipboard', 'copy');
},
/**
* Cut selected items
*/
cutAction() {
// add selected items to the clipboard
this.$store.dispatch('fm/toClipboard', 'cut');
},
/**
* Rename selected item
*/
renameAction() {
// show modal - rename
this.$store.commit('fm/modal/setModalState', {
modalName: 'Rename',
show: true,
});
},
/**
* Paste copied or cut items
*/
pasteAction() {
// paste items in the selected folder
this.$store.dispatch('fm/paste');
},
/**
* Zip selected files
*/
zipAction() {
// show modal - Zip
this.$store.commit('fm/modal/setModalState', {
modalName: 'Zip',
show: true,
});
},
/**
* Unzip selected archive
*/
unzipAction() {
// show modal - Unzip
this.$store.commit('fm/modal/setModalState', {
modalName: 'Unzip',
show: true,
});
},
/**
* Delete selected items
*/
deleteAction() {
// show modal - delete
this.$store.commit('fm/modal/setModalState', {
modalName: 'Delete',
show: true,
});
},
/**
* Show properties for selected items
*/
propertiesAction() {
// show modal - properties
this.$store.commit('fm/modal/setModalState', {
modalName: 'Properties',
show: true,
});
},
},
};
/**
* Rules for context menu items (show/hide)
* {name}Rule
*/
export default {
methods: {
/**
* Open - menu item status - show or hide
* @returns {boolean}
*/
openRule() {
return !this.multiSelect && this.firstItemType === 'dir';
},
/**
* Play audio - menu item status - show or hide
* @returns {boolean}
*/
audioPlayRule() {
return this.selectedItems.every((elem) => elem.type === 'file')
&& this.selectedItems.every((elem) => this.canAudioPlay(elem.extension));
},
/**
* Play video - menu item status - show or hide
* @returns {boolean}
*/
videoPlayRule() {
return !this.multiSelect && this.canVideoPlay(this.selectedItems[0].extension);
},
/**
* View - menu item status - show or hide
* @returns {boolean|*}
*/
viewRule() {
return !this.multiSelect
&& this.firstItemType === 'file'
&& this.canView(this.selectedItems[0].extension);
},
/**
* Edit - menu item status - show or hide
* @returns {boolean|*}
*/
editRule() {
return !this.multiSelect
&& this.firstItemType === 'file'
&& this.canEdit(this.selectedItems[0].extension);
},
/**
* Select - menu item status - show or hide
* @returns {boolean|null}
*/
selectRule() {
return !this.multiSelect && this.firstItemType === 'file'
&& this.$store.state.fm.fileCallback;
},
/**
* Download - menu item status - show or hide
* @returns {boolean}
*/
downloadRule() {
return !this.multiSelect && this.firstItemType === 'file';
},
/**
* Copy - menu item status - show or hide
* @returns {boolean}
*/
copyRule() {
return true;
},
/**
* Cut - menu item status - show or hide
* @returns {boolean}
*/
cutRule() {
return true;
},
/**
* Rename - menu item status - show or hide
* @returns {boolean}
*/
renameRule() {
return !this.multiSelect;
},
/**
* Paste - menu item status - show or hide
* @returns {boolean}
*/
pasteRule() {
return !!this.$store.state.fm.clipboard.type;
},
/**
* Zip - menu item status - show or hide
* @returns {boolean}
*/
zipRule() {
return this.selectedDiskDriver === 'local';
},
/**
* Unzip - menu item status - show or hide
* @returns {boolean}
*/
unzipRule() {
return this.selectedDiskDriver === 'local'
&& !this.multiSelect
&& this.firstItemType === 'file'
&& this.isZip(this.selectedItems[0].extension);
},
/**
* Delete - menu item status - show or hide
* @returns {boolean}
*/
deleteRule() {
return true;
},
/**
* Properties - menu item status - show or hide
* @returns {boolean}
*/
propertiesRule() {
return !this.multiSelect;
},
},
};
<template>
<div class="fm-breadcrumb">
<nav aria-label="breadcrumb">
<ol class="breadcrumb"
v-bind:class="[manager === activeManager ? 'active-manager' : 'bg-light']">
<li class="breadcrumb-item" v-on:click="selectMainDirectory">
<span class="badge badge-secondary">
<i class="far fa-hdd"/>
</span>
</li>
<li class="breadcrumb-item text-truncate"
v-for="(item, index) in breadcrumb"
v-bind:key="index"
v-bind:class="[breadcrumb.length === index + 1 ? 'active' : '']"
v-on:click="selectDirectory(index)">
<span>{{ item }}</span>
</li>
</ol>
</nav>
</div>
</template>
<script>
export default {
name: 'Breadcrumb',
props: {
manager: { type: String, required: true },
},
computed: {
/**
* Active manager name
* @returns {default.computed.activeManager|(function())|string|activeManager}
*/
activeManager() {
return this.$store.state.fm.activeManager;
},
/**
* Selected Disk for this manager
* @returns {default.computed.selectedDisk|(function())|default.selectedDisk|null}
*/
selectedDisk() {
return this.$store.state.fm[this.manager].selectedDisk;
},
/**
* Selected directory for this manager
* @returns {default.computed.selectedDirectory|(function())|default.selectedDirectory|null}
*/
selectedDirectory() {
return this.$store.state.fm[this.manager].selectedDirectory;
},
/**
* Breadcrumb
* @returns {*}
*/
breadcrumb() {
return this.$store.getters[`fm/${this.manager}/breadcrumb`];
},
},
methods: {
/**
* Load selected directory
* @param index
*/
selectDirectory(index) {
const path = this.breadcrumb.slice(0, index + 1).join('/');
// only if this path not selected
if (path !== this.selectedDirectory) {
// load directory
this.$store.dispatch(`fm/${this.manager}/selectDirectory`, { path, history: true });
}
},
/**
* Select main directory
*/
selectMainDirectory() {
if (this.selectedDirectory) {
this.$store.dispatch(`fm/${this.manager}/selectDirectory`, { path: null, history: true });
}
},
},
};
</script>
<style lang="scss">
.fm-breadcrumb {
.breadcrumb {
flex-wrap: nowrap;
padding: 0.2rem 0.3rem;
margin-bottom: 0.5rem;
&.active-manager {
background-color: #c2e5eb;
}
.breadcrumb-item:not(.active):hover {
cursor: pointer;
font-weight: normal;
color: #6d757d;
}
}
}
</style>
<template>
<div class="fm-disk-list">
<ul class="list-inline">
<li class="list-inline-item" v-for="(disk, index) in disks" v-bind:key="index">
<span class="badge"
v-on:click="selectDisk(disk)"
v-bind:class="[disk === selectedDisk ? 'badge-secondary' : 'badge-light']">
<i class="fa-fw far fa-hdd"/> {{ disk }}
</span>
</li>
</ul>
</div>
</template>
<script>
export default {
name: 'DiskList',
props: {
// manager name - left or right
manager: { type: String, required: true },
},
computed: {
/**
* Disk list
* @returns {Array}
*/
disks() {
return this.$store.getters['fm/diskList'];
},
/**
* Selected Disk for this manager
* @returns {default.computed.selectedDisk|(function())|default.selectedDisk|null}
*/
selectedDisk() {
return this.$store.state.fm[this.manager].selectedDisk;
},
},
methods: {
/**
* Select disk
* @param disk
*/
selectDisk(disk) {
if (this.selectedDisk !== disk) {
this.$store.dispatch('fm/selectDisk', {
disk,
manager: this.manager,
});
}
},
},
};
</script>
<style lang="scss">
.fm-disk-list {
ul.list-inline {
margin-bottom: 0.5rem;
}
.badge.badge-light {
cursor: pointer;
}
}
</style>
<template>
<div class="fm-grid">
<div class="d-flex align-content-start flex-wrap">
<div v-if="!isRootPath" v-on:click="levelUp" class="fm-grid-item text-center" >
<div class="fm-item-icon">
<i class="fas fa-level-up-alt fa-5x pb-2"/>
</div>
<div class="fm-item-info"><strong>..</strong></div>
</div>
<div class="fm-grid-item text-center unselectable"
v-for="(directory, index) in directories"
v-bind:key="`d-${index}`"
v-bind:title="directory.basename"
v-bind:class="{'active': checkSelect('directories', directory.path)}"
v-on:click="selectItem('directories', directory.path, $event)"
v-on:dblclick.stop="selectDirectory(directory.path)"
v-on:contextmenu.prevent="contextMenu(directory, $event)">
<div class="fm-item-icon">
<i class="fa-5x pb-2"
v-bind:class="(acl && directory.acl === 0) ? 'fas fa-unlock-alt' : 'far fa-folder'"/>
</div>
<div class="fm-item-info">{{ directory.basename }}</div>
</div>
<div class="fm-grid-item text-center unselectable"
v-for="(file, index) in files"
v-bind:key="`f-${index}`"
v-bind:title="file.basename"
v-bind:class="{'active': checkSelect('files', file.path)}"
v-on:click="selectItem('files', file.path, $event)"
v-on:dblclick="selectAction(file.path, file.extension)"
v-on:contextmenu.prevent="contextMenu(file, $event)">
<div class="fm-item-icon">
<i v-if="acl && file.acl === 0" class="fas fa-unlock-alt fa-5x pb-2"/>
<thumbnail v-else-if="thisImage(file.extension)"
v-bind:disk="disk"
v-bind:file="file">
</thumbnail>
<i v-else class="far fa-5x pb-2"
v-bind:class="extensionToIcon(file.extension)"/>
</div>
<div class="fm-item-info">
{{ `${file.filename}.${file.extension}` }}
<br>
{{ bytesToHuman(file.size) }}
</div>
</div>
</div>
</div>
</template>
<script>
import translate from '@/utils/translate';
import helper from '@/utils/helper';
import managerHelper from './mixins/manager';
import Thumbnail from './Thumbnail.vue';
export default {
name: 'grid-view',
components: { Thumbnail },
mixins: [translate, helper, managerHelper],
data() {
return {
disk: '',
};
},
props: {
manager: { type: String, required: true },
},
mounted() {
this.disk = this.selectedDisk;
},
beforeUpdate() {
// if disk changed
if (this.disk !== this.selectedDisk) {
this.disk = this.selectedDisk;
}
},
computed: {
/**
* Image extensions list
* @returns {*}
*/
imageExtensions() {
return this.$store.state.fm.settings.imageExtensions;
},
},
methods: {
/**
* Check file extension (image or no)
* @param extension
* @returns {boolean}
*/
thisImage(extension) {
// extension not found
if (!extension) return false;
return this.imageExtensions.includes(extension.toLowerCase());
},
},
};
</script>
<style lang="scss">
.fm-grid {
padding-top: 1rem;
.fm-grid-item {
position: relative;
width: 125px;
padding: 0.4rem;
margin-bottom: 1rem;
margin-right: 1rem;
border-radius: 5px;
&.active {
background-color: #c2e5eb;
box-shadow: 3px 2px 5px gray;
}
&:not(.active):hover {
background-color: #f8f9fa;
box-shadow: 3px 2px 5px gray;
}
.fm-item-icon{
cursor: pointer;
}
.fm-item-icon > i,
.fm-item-icon > figure > i {
color: #6d757d;
}
.fm-item-info {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
</style>
<template>
<div class="fm-content d-flex flex-column">
<disk-list v-bind:manager="manager"/>
<breadcrumb v-bind:manager="manager"/>
<div class="fm-content-body">
<table-view v-if="viewType === 'table'" v-bind:manager="manager"/>
<grid-view v-else v-bind:manager="manager"/>
</div>
</div>
</template>
<script>
// Components
import DiskList from './DiskList.vue';
import Breadcrumb from './Breadcrumb.vue';
import TableView from './TableView.vue';
import GridView from './GridView.vue';
export default {
name: 'Manager',
components: {
DiskList,
Breadcrumb,
TableView,
GridView,
},
props: {
manager: { type: String, required: true },
},
computed: {
/**
* view type - grid or table
* @returns {default.computed.viewType|(function())|string}
*/
viewType() {
return this.$store.state.fm[this.manager].viewType;
},
},
};
</script>
<style lang="scss">
.fm-content {
height: 100%;
padding-left: 1rem;
.fm-content-body {
overflow: auto;
}
}
</style>
<template>
<div class="fm-table">
<table class="table table-sm">
<thead>
<tr>
<th class="w-65" v-on:click="sortBy('name')">
{{ lang.manager.table.name }}
<template v-if="sortSettings.field === 'name'">
<i class="fas fa-sort-amount-down"
v-show="sortSettings.direction === 'down'"/>
<i class="fas fa-sort-amount-up"
v-show="sortSettings.direction === 'up'"/>
</template>
</th>
<th class="w-10" v-on:click="sortBy('size')">
{{ lang.manager.table.size }}
<template v-if="sortSettings.field === 'size'">
<i class="fas fa-sort-amount-down"
v-show="sortSettings.direction === 'down'"/>
<i class="fas fa-sort-amount-up"
v-show="sortSettings.direction === 'up'"/>
</template>
</th>
<th class="w-10" v-on:click="sortBy('type')">
{{ lang.manager.table.type }}
<template v-if="sortSettings.field === 'type'">
<i class="fas fa-sort-amount-down"
v-show="sortSettings.direction === 'down'"/>
<i class="fas fa-sort-amount-up"
v-show="sortSettings.direction === 'up'"/>
</template>
</th>
<th class="w-auto" v-on:click="sortBy('date')">
{{ lang.manager.table.date }}
<template v-if="sortSettings.field === 'date'">
<i class="fas fa-sort-amount-down"
v-show="sortSettings.direction === 'down'"/>
<i class="fas fa-sort-amount-up"
v-show="sortSettings.direction === 'up'"/>
</template>
</th>
</tr>
</thead>
<tbody>
<tr v-if="!isRootPath">
<td colspan="4" class="fm-content-item" v-on:click="levelUp">
<i class="fas fa-level-up-alt"/>
</td>
</tr>
<tr v-for="(directory, index) in directories"
v-bind:key="`d-${index}`"
v-bind:class="{'table-info': checkSelect('directories', directory.path)}"
v-on:click="selectItem('directories', directory.path, $event)"
v-on:contextmenu.prevent="contextMenu(directory, $event)">
<td class="fm-content-item unselectable"
v-bind:class="(acl && directory.acl === 0) ? 'text-hidden' : ''"
v-on:dblclick="selectDirectory(directory.path)">
<i class="far fa-folder"/> {{ directory.basename }}
</td>
<td/>
<td>{{ lang.manager.table.folder }}</td>
<td>
{{ timestampToDate(directory.timestamp) }}
</td>
</tr>
<tr v-for="(file, index) in files"
v-bind:key="`f-${index}`"
v-bind:class="{'table-info': checkSelect('files', file.path)}"
v-on:click="selectItem('files', file.path, $event)"
v-on:dblclick="selectAction(file.path, file.extension)"
v-on:contextmenu.prevent="contextMenu(file, $event)">
<td class="fm-content-item unselectable"
v-bind:class="(acl && file.acl === 0) ? 'text-hidden' : ''">
<i class="far" v-bind:class="extensionToIcon(file.extension)"/>
{{ file.filename ? file.filename : file.basename }}
</td>
<td>{{ bytesToHuman(file.size) }}</td>
<td>
{{ file.extension }}
</td>
<td>
{{ timestampToDate(file.timestamp) }}
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import translate from '@/utils/translate';
import helper from '@/utils/helper';
import managerHelper from './mixins/manager';
export default {
name: 'table-view',
mixins: [translate, helper, managerHelper],
props: {
manager: { type: String, required: true },
},
computed: {
/**
* Sort settings
* @returns {*}
*/
sortSettings() {
return this.$store.state.fm[this.manager].sort;
},
},
methods: {
/**
* Sort by field
* @param field
*/
sortBy(field) {
this.$store.dispatch(`fm/${this.manager}/sortBy`, { field, direction: null });
},
},
};
</script>
<style lang="scss">
.fm-table {
thead th{
background: white;
position: sticky;
top: 0;
z-index: 10;
cursor: pointer;
border-top: none;
&:hover {
background-color: #f8f9fa;
}
& > i {
padding-left: 0.5rem;
}
}
td {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
tr:hover {
background-color: #f8f9fa;
}
.w-10 {
width: 10%;
}
.w-65 {
width: 65%;
}
.fm-content-item {
cursor: pointer;
max-width: 1px;
}
.text-hidden {
color: #cdcdcd;
}
}
</style>
<template>
<figure class="fm-thumbnail">
<transition name="fade" mode="out-in">
<i v-if="!src" class="far fa-file-image fa-5x pb-2"/>
<img v-else
v-bind:src="src"
v-bind:alt="file.filename"
class="img-thumbnail">
</transition>
</figure>
</template>
<script>
import GET from '@/utils/get';
export default {
name: 'Thumbnail',
data() {
return {
src: '',
};
},
props: {
disk: {
type: String,
required: true,
},
file: {
type: Object,
required: true,
},
},
watch: {
'file.timestamp': 'loadImage',
},
mounted() {
if (window.IntersectionObserver) {
const observer = new IntersectionObserver(
(entries, obs) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
this.loadImage();
obs.unobserve(this.$el);
}
});
},
{
root: null,
threshold: '0.5',
},
);
// add observer for template
observer.observe(this.$el);
} else {
this.loadImage();
}
},
computed: {
/**
* Authorization required
* @return {*}
*/
auth() {
return this.$store.getters['fm/settings/authHeader'];
},
},
methods: {
/**
* Load image
*/
loadImage() {
// if authorization required
if (this.auth) {
GET.thumbnail(
this.disk,
this.file.path,
).then((response) => {
const mimeType = response.headers['content-type'].toLowerCase();
const imgBase64 = Buffer.from(response.data, 'binary').toString('base64');
this.src = `data:${mimeType};base64,${imgBase64}`;
});
} else {
this.src = `${this.$store.getters['fm/settings/baseUrl']}thumbnails?disk=${this.disk}&path=${encodeURIComponent(this.file.path)}&v=${this.file.timestamp}`;
}
},
},
};
</script>
<style lang="scss">
.fm-thumbnail {
display: flex;
justify-content: center;
align-items: center;
.img-thumbnail {
width: 88px;
height: 88px;
}
.fade-enter-active, .fade-leave-active {
transition: opacity .3s;
}
.fade-enter, .fade-leave-to {
opacity: 0;
}
}
</style>
// Event bus
import EventBus from '@/utils/eventBus';
export default {
computed: {
/**
* Selected disk for this manager
* @returns {default.computed.selectedDisk|(function())|default.selectedDisk|null}
*/
selectedDisk() {
return this.$store.state.fm[this.manager].selectedDisk;
},
/**
* Selected directory for this manager
* @returns {default.computed.selectedDirectory|(function())|default.selectedDirectory|null}
*/
selectedDirectory() {
return this.$store.state.fm[this.manager].selectedDirectory;
},
/**
* Files list for selected directory
* @returns {*}
*/
files() {
return this.$store.getters[`fm/${this.manager}/files`];
},
/**
* Directories list for selected directory
* @returns {*}
*/
directories() {
return this.$store.getters[`fm/${this.manager}/directories`];
},
/**
* Selected files and folders
* @returns {default.computed.selected|(function())|selected|{directories, files}|string|*|boolean}
*/
selected() {
return this.$store.state.fm[this.manager].selected;
},
/**
* ACL On/Off
*/
acl() {
return this.$store.state.fm.settings.acl;
},
/**
* Check if current path is at root level
* @return {boolean}
*/
isRootPath() {
return this.$store.state.fm[this.manager].selectedDirectory === null;
},
},
methods: {
/**
* Load selected directory and show files
* @param path
*/
selectDirectory(path) {
this.$store.dispatch(`fm/${this.manager}/selectDirectory`, { path, history: true });
},
/**
* Level up directory
*/
levelUp() {
// if this a not root directory
if (this.selectedDirectory) {
// calculate up directory path
const pathUp = this.selectedDirectory.split('/').slice(0, -1).join('/');
// load directory
this.$store.dispatch(`fm/${this.manager}/selectDirectory`, { path: pathUp || null, history: true });
}
},
/**
* Check item - selected
* @param type
* @param path
*/
checkSelect(type, path) {
return this.selected[type].includes(path);
},
/**
* Select items in list (files + folders)
* @param type
* @param path
* @param event
*/
selectItem(type, path, event) {
// search in selected array
const alreadySelected = this.selected[type].includes(path);
// if pressed Ctrl -> multi select
if (event.ctrlKey || event.metaKey) {
if (!alreadySelected) {
// add new selected item
this.$store.commit(`fm/${this.manager}/setSelected`, { type, path });
} else {
// remove selected item
this.$store.commit(`fm/${this.manager}/removeSelected`, { type, path });
}
}
// single select
if (!event.ctrlKey && !alreadySelected && !event.metaKey) {
this.$store.commit(`fm/${this.manager}/changeSelected`, { type, path });
}
},
/**
* Show context menu
* @param item
* @param event
*/
contextMenu(item, event) {
// el type
const type = item.type === 'dir' ? 'directories' : 'files';
// search in selected array
const alreadySelected = this.selected[type].includes(item.path);
// select this element
if (!alreadySelected) {
// select item
this.$store.commit(`fm/${this.manager}/changeSelected`, {
type,
path: item.path,
});
}
// create event
EventBus.$emit('contextMenu', event);
},
/**
* Select and Action
* @param path
* @param extension
*/
selectAction(path, extension) {
// if is set fileCallback
if (this.$store.state.fm.fileCallback) {
this.$store.dispatch('fm/url', {
disk: this.selectedDisk,
path,
}).then((response) => {
if (response.data.result.status === 'success') {
this.$store.state.fm.fileCallback(response.data.url);
}
});
return;
}
// if extension not defined
if (!extension) {
return;
}
// show, play..
if (this.$store.state.fm.settings.imageExtensions
.includes(extension.toLowerCase())) {
// show image
this.$store.commit('fm/modal/setModalState', {
modalName: 'Preview',
show: true,
});
} else if (Object.keys(this.$store.state.fm.settings.textExtensions)
.includes(extension.toLowerCase())) {
// show text file
this.$store.commit('fm/modal/setModalState', {
modalName: 'TextEdit',
show: true,
});
} else if (this.$store.state.fm.settings.audioExtensions
.includes(extension.toLowerCase())) {
// show player modal
this.$store.commit('fm/modal/setModalState', {
modalName: 'AudioPlayer',
show: true,
});
} else if (this.$store.state.fm.settings.videoExtensions
.includes(extension.toLowerCase())) {
// show player modal
this.$store.commit('fm/modal/setModalState', {
modalName: 'VideoPlayer',
show: true,
});
} else if (extension.toLowerCase() === 'pdf') {
// show pdf document
this.$store.dispatch('fm/openPDF', {
disk: this.selectedDisk,
path,
});
}
},
},
};
<template>
<transition name="fm-modal">
<div class="fm-modal" ref="fmModal" v-on:click="hideModal">
<div class="modal-dialog"
role="document"
v-bind:class="modalSize"
v-on:click.stop>
<component v-bind:is="modalName"/>
</div>
</div>
</transition>
</template>
<script>
import NewFile from './views/NewFile.vue';
import NewFolder from './views/NewFolder.vue';
import Upload from './views/Upload.vue';
import Delete from './views/Delete.vue';
import Clipboard from './views/Clipboard.vue';
import Status from './views/Status.vue';
import Rename from './views/Rename.vue';
import Properties from './views/Properties.vue';
import Preview from './views/Preview.vue';
import TextEdit from './views/TextEdit.vue';
import AudioPlayer from './views/AudioPlayer.vue';
import VideoPlayer from './views/VideoPlayer.vue';
import Zip from './views/Zip.vue';
import Unzip from './views/Unzip.vue';
import About from './views/About.vue';
export default {
name: 'Modal',
components: {
NewFile,
NewFolder,
Upload,
Delete,
Clipboard,
Status,
Rename,
Properties,
Preview,
TextEdit,
AudioPlayer,
VideoPlayer,
Zip,
Unzip,
About,
},
mounted() {
// set height
this.$store.commit('fm/modal/setModalBlockHeight', this.$refs.fmModal.offsetHeight);
},
computed: {
/**
* Selected modal name
* @returns {null|*}
*/
modalName() {
return this.$store.state.fm.modal.modalName;
},
/**
* Modal size style
* @returns {{'modal-lg': boolean, 'modal-sm': boolean}}
*/
modalSize() {
return {
'modal-xl': this.modalName === 'Preview' || this.modalName === 'TextEdit',
'modal-lg': this.modalName === 'VideoPlayer',
'modal-sm': false,
};
},
},
methods: {
/**
* Hide modal window
*/
hideModal() {
this.$store.commit('fm/modal/clearModal');
},
},
};
</script>
<style lang="scss">
.fm-modal {
position: absolute;
z-index: 9998;
top: 0;
bottom: 0;
left: 0;
right: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, .35);
display: block;
transition: opacity .4s ease;
overflow: auto;
.modal-xl {
max-width: 96%;
}
}
.fm-modal-enter-active, .fm-modal-leave-active {
transition: opacity .5s;
}
.fm-modal-enter, .fm-modal-leave-to {
opacity: 0;
}
</style>
<template>
<div class="fm-additions-cropper">
<div class="row" v-bind:style="{ 'max-height': maxHeight + 'px' }">
<div class="col-sm-9 cropper-block">
<img
v-bind:src="imgSrc"
ref="fmCropper"
v-bind:alt="selectedItem.basename"
/>
</div>
<div class="col-sm-3 pl-0">
<div class="cropper-preview"></div>
<div class="cropper-data">
<div class="input-group input-group-sm">
<span class="input-group-prepend">
<label class="input-group-text" for="dataX">X</label>
</span>
<input
v-model.number="x"
type="text"
class="form-control"
id="dataX"
/>
<span class="input-group-append">
<span class="input-group-text">px</span>
</span>
</div>
<div class="input-group input-group-sm">
<span class="input-group-prepend">
<label class="input-group-text" for="dataY">Y</label>
</span>
<input
v-model.number="y"
type="text"
class="form-control"
id="dataY"
/>
<span class="input-group-append">
<span class="input-group-text">px</span>
</span>
</div>
<div class="input-group input-group-sm">
<span class="input-group-prepend">
<label class="input-group-text" for="dataWidth">Width</label>
</span>
<input
v-model.number="width"
type="text"
class="form-control"
id="dataWidth"
/>
<span class="input-group-append">
<span class="input-group-text">px</span>
</span>
</div>
<div class="input-group input-group-sm">
<span class="input-group-prepend">
<label class="input-group-text" for="dataHeight">Height</label>
</span>
<input
v-model.number="height"
type="text"
class="form-control"
id="dataHeight"
/>
<span class="input-group-append">
<span class="input-group-text">px</span>
</span>
</div>
<div class="input-group input-group-sm">
<span class="input-group-prepend">
<label class="input-group-text" for="dataRotate">Rotate</label>
</span>
<input
v-model.number="rotate"
type="text"
class="form-control"
id="dataRotate"
/>
<span class="input-group-append">
<span class="input-group-text">deg</span>
</span>
</div>
<div class="input-group input-group-sm">
<span class="input-group-prepend">
<label class="input-group-text" for="dataScaleX">ScaleX</label>
</span>
<input
v-model.number="scaleX"
type="text"
class="form-control"
id="dataScaleX"
/>
</div>
<div class="input-group input-group-sm">
<span class="input-group-prepend">
<label class="input-group-text" for="dataScaleY">ScaleY</label>
</span>
<input
v-model.number="scaleY"
type="text"
class="form-control"
id="dataScaleY"
/>
</div>
<button
v-on:click="setData()"
v-bind:title="lang.modal.cropper.apply"
type="button"
class="btn btn-block btn-sm btn-info mb-2"
>
<i class="fas fa-check" />
</button>
</div>
</div>
</div>
<div class="d-flex justify-content-between">
<div>
<div class="btn-group mr-2" role="group" aria-label="Scale">
<button v-on:click="cropMove(-10, 0)" class="btn btn-info">
<i class="fas fa-arrow-left" />
</button>
<button v-on:click="cropMove(10, 0)" class="btn btn-info">
<i class="fas fa-arrow-right" />
</button>
<button v-on:click="cropMove(0, -10)" class="btn btn-info">
<i class="fas fa-arrow-up" />
</button>
<button v-on:click="cropMove(0, 10)" class="btn btn-info">
<i class="fas fa-arrow-down" />
</button>
</div>
<div class="btn-group mr-2" role="group" aria-label="Scale">
<button v-on:click="cropScaleX()" class="btn btn-info">
<i class="fas fa-arrows-alt-h" />
</button>
<button v-on:click="cropScaleY()" class="btn btn-info">
<i class="fas fa-arrows-alt-v" />
</button>
</div>
<div class="btn-group mr-2" role="group" aria-label="Rotate">
<button v-on:click="cropRotate(-45)" class="btn btn-info">
<i class="fas fa-undo" />
</button>
<button v-on:click="cropRotate(45)" class="btn btn-info">
<i class="fas fa-redo" />
</button>
</div>
<div class="btn-group mr-2" role="group" aria-label="Rotate">
<button v-on:click="cropZoom(0.1)" class="btn btn-info">
<i class="fas fa-search-plus" />
</button>
<button v-on:click="cropZoom(-0.1)" class="btn btn-info">
<i class="fas fa-search-minus" />
</button>
</div>
<button
v-on:click="cropReset()"
v-bind:title="lang.modal.cropper.reset"
class="btn btn-info mr-2"
>
<i class="fas fa-sync-alt" />
</button>
<button
v-on:click="cropSave()"
v-bind:title="lang.modal.cropper.save"
class="btn btn-danger mr-2"
>
<i class="far fa-save" />
</button>
</div>
<span class="d-block">
<button v-on:click="$emit('closeCropper')" class="btn btn-light">
{{ lang.btn.back }}
</button>
</span>
</div>
</div>
</template>
<script>
import Cropper from "cropperjs";
import translate from "@/utils/translate";
export default {
name: "Cropper",
mixins: [translate],
props: {
imgSrc: { required: true },
maxHeight: { type: Number, required: true },
},
data() {
return {
cropper: {},
height: 0,
width: 0,
x: 0,
y: 0,
rotate: 0,
scaleX: 1,
scaleY: 1,
};
},
mounted() {
// set cropper instance
this.cropper = new Cropper(this.$refs.fmCropper, {
preview: ".cropper-preview",
crop: (e) => {
this.x = Math.round(e.detail.x);
this.y = Math.round(e.detail.y);
this.height = Math.round(e.detail.height);
this.width = Math.round(e.detail.width);
this.rotate =
typeof e.detail.rotate !== "undefined" ? e.detail.rotate : "";
this.scaleX =
typeof e.detail.scaleX !== "undefined" ? e.detail.scaleX : "";
this.scaleY =
typeof e.detail.scaleY !== "undefined" ? e.detail.scaleY : "";
},
});
},
beforeDestroy() {
this.cropper.destroy();
},
computed: {
/**
* Selected file
* @returns {*}
*/
selectedItem() {
return this.$store.getters["fm/selectedItems"][0];
},
},
methods: {
/**
* Move
* @param x
* @param y
*/
cropMove(x, y) {
this.cropper.move(x, y);
},
/**
* Scale - mirroring Y
*/
cropScaleY() {
this.cropper.scale(1, this.cropper.getData().scaleY === 1 ? -1 : 1);
},
/**
* Scale - mirroring X
*/
cropScaleX() {
this.cropper.scale(this.cropper.getData().scaleX === 1 ? -1 : 1, 1);
},
/**
* Rotate
* @param grade
*/
cropRotate(grade) {
this.cropper.rotate(grade);
},
/**
* Zoom
* @param ratio
*/
cropZoom(ratio) {
this.cropper.zoom(ratio);
},
/**
* Reset
*/
cropReset() {
this.cropper.reset();
},
/**
* Set data from form
*/
setData() {
this.cropper.setData({
x: this.x,
y: this.y,
width: this.width,
height: this.height,
rotate: this.rotate,
scaleX: this.scaleX,
scaleY: this.scaleY,
});
},
/**
* Save cropped image
*/
cropSave() {
this.cropper.getCroppedCanvas().toBlob(
(blob) => {
const formData = new FormData();
// add disk name
formData.append("disk", this.$store.getters["fm/selectedDisk"]);
// add path
formData.append("path", this.selectedItem.dirname);
// new image
formData.append("file", blob, this.selectedItem.basename);
this.$store.dispatch("fm/updateFile", formData).then((response) => {
// if file updated successfully
if (response.data.result.status === "success") {
// close cropper
this.$emit("closeCropper");
}
});
},
this.selectedItem.extension !== "jpg"
? `image/${this.selectedItem.extension}`
: "image/jpeg"
);
},
},
};
</script>
<style lang="scss">
@import "~cropperjs/dist/cropper.css";
.fm-additions-cropper {
overflow: hidden;
& > .row {
flex-wrap: nowrap;
}
.cropper-block {
overflow: hidden;
img {
max-width: 100%;
}
}
.col-sm-3 {
overflow: auto;
&::-webkit-scrollbar {
display: none;
}
}
.cropper-preview {
margin-bottom: 1rem;
overflow: hidden;
height: 200px;
img {
max-width: 100%;
}
}
.cropper-data {
padding-left: 1rem;
padding-right: 1rem;
& > .input-group {
margin-bottom: 0.5rem;
}
.input-group-prepend .input-group-text {
min-width: 4rem;
}
.input-group-append .input-group-text {
min-width: 3rem;
}
}
& > .d-flex {
padding: 1rem;
border-top: 1px solid #e9ecef;
}
}
</style>
<template>
<div class="fm-additions-file-list">
<div
class="d-flex justify-content-between"
v-for="(item, index) in selectedItems"
v-bind:key="index"
>
<div class="w-75 text-truncate">
<span v-if="item.type === 'dir'">
<i class="far fa-folder" />{{ item.basename }}
</span>
<span v-else>
<i class="far" v-bind:class="extensionToIcon(item.extension)" />
{{ item.basename }}
</span>
</div>
<div class="text-right" v-if="item.type === 'file'">
{{ bytesToHuman(item.size) }}
</div>
</div>
</div>
</template>
<script>
import helper from "@/utils/helper";
export default {
name: "SelectedFileList",
mixins: [helper],
computed: {
/**
* Selected files and folders
* @returns {*}
*/
selectedItems() {
return this.$store.getters["fm/selectedItems"];
},
},
};
</script>
<style lang="scss">
.fm-additions-file-list {
.far {
padding-right: 0.5rem;
}
}
</style>
export default {
directives: {
/**
* AutoFocus for inputs
*/
focus: {
inserted(el) {
el.focus();
},
},
},
computed: {
/**
* Active manager
* @returns {default.computed.activeManager|(function())|string|activeManager}
*/
activeManager() {
return this.$store.state.fm.activeManager;
},
},
methods: {
/**
* Hide modal window
*/
hideModal() {
this.$store.commit('fm/modal/setModalState', {
modalName: null,
show: false,
});
},
},
};
<template>
<div class="modal-content fm-modal-about">
<div class="modal-header">
<h5 class="modal-title">{{ lang.modal.about.title }}</h5>
<button type="button" class="close" aria-label="Close" v-on:click="hideModal">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<strong>{{ lang.modal.about.name }}</strong>
<hr>
<dl class="row">
<dt class="col-3">{{ lang.modal.about.version }}:</dt>
<dd class="col-9">{{ version }}</dd>
<dt class="col-3">{{ lang.modal.about.developer }}:</dt>
<dd class="col-9">Aleksandr Manekin (alexusmai@gmail.com)</dd>
<dt class="col-3">GitHub:</dt>
<dd class="col-9">
<a href="https://github.com/alexusmai/laravel-file-manager" target="_blank">
alexusmai/laravel-file-manager
</a>
<br>
<a href="https://github.com/alexusmai/vue-laravel-file-manager" target="_blank">
alexusmai/vue-laravel-file-manager
</a>
</dd>
</dl>
</div>
</div>
</template>
<script>
import modal from '../mixins/modal';
import translate from '@/utils/translate';
export default {
name: 'About',
mixins: [modal, translate],
computed: {
/**
* App version
* @returns {*}
*/
version() {
return this.$store.state.fm.settings.version;
},
},
};
</script>
<template>
<div class="modal-content fm-modal-audio-player">
<div class="modal-header">
<h5 class="modal-title">
{{ lang.modal.audioPlayer.title }}
</h5>
<button type="button" class="close" aria-label="Close" v-on:click="hideModal">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<audio ref="fmAudio" controls/>
<hr>
<div class="d-flex justify-content-between py-2 px-2"
v-bind:class="playingIndex === index ? 'bg-light' : ''"
v-for="(item, index) in audioFiles"
v-bind:key="index">
<div class="w-75 text-truncate">
<span class="text-muted pr-2">{{ index }}.</span>
{{ item.basename }}
</div>
<template v-if="playingIndex === index">
<div v-if="status === 'playing'">
<i v-on:click="togglePlay()" class="fas fa-play active"/>
</div>
<div v-else>
<i v-on:click="togglePlay()" class="fas fa-pause"/>
</div>
</template>
<template v-else>
<div>
<i v-on:click="selectTrack(index)" class="fas fa-play"/>
</div>
</template>
</div>
</div>
</div>
</template>
<script>
import Plyr from 'plyr';
import modal from '../mixins/modal';
import translate from '@/utils/translate';
export default {
name: 'Player',
mixins: [modal, translate],
data() {
return {
player: {},
playingIndex: 0,
status: 'paused',
};
},
mounted() {
// initiate player
this.player = new Plyr(this.$refs.fmAudio, {
speed: {
selected: 1,
options: [0.5, 1, 1.5],
},
});
// select first item in the list
this.setSource(this.playingIndex);
// add event listeners
this.player.on('play', () => {
this.status = 'playing';
});
this.player.on('pause', () => {
this.status = 'paused';
});
this.player.on('ended', () => {
if (this.audioFiles.length > this.playingIndex + 1) {
// play next track
this.selectTrack(this.playingIndex + 1);
}
});
},
beforeDestroy() {
// destroy player
this.player.destroy();
},
computed: {
/**
* Selected disk
* @returns {*}
*/
selectedDisk() {
return this.$store.getters['fm/selectedDisk'];
},
/**
* Audio files list
* @returns {*}
*/
audioFiles() {
return this.$store.getters['fm/selectedItems'];
},
},
methods: {
/**
* Select another audio track
* @param index
*/
selectTrack(index) {
if (this.player.playing) {
// stop playing
this.player.stop();
}
// load new source
this.setSource(index);
// start play
this.player.play();
this.playingIndex = index;
},
/**
* Set source to audio player
* @param index
*/
setSource(index) {
this.player.source = {
type: 'audio',
title: this.audioFiles[index].filename,
sources: [{
src: `${this.$store.getters['fm/settings/baseUrl']}stream-file?disk=${this.selectedDisk}&path=${encodeURIComponent(this.audioFiles[index].path)}`,
type: `audio/${this.audioFiles[index].extension}`,
}],
};
},
/**
* Play/Pause
*/
togglePlay() {
this.player.togglePlay();
},
},
};
</script>
<style lang="scss">
.fm-modal-audio-player {
.fas.fa-play {
color: gray;
opacity: 0.1;
cursor: pointer;
&:hover {
opacity: 0.5;
}
&.active {
opacity: 1;
color: deepskyblue;
}
}
.fas.fa-pause {
color: gray;
opacity: 0.5;
cursor: pointer;
}
}
</style>
<template>
<div class="modal-content fm-modal-clipboard">
<div class="modal-header">
<h5 class="modal-title">{{ lang.clipboard.title }}</h5>
<button type="button" class="close" aria-label="Close" v-on:click="hideModal">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<template v-if="clipboard.type">
<div class="d-flex justify-content-between">
<div class="w-75 text-truncate">
<span>
<i class="far fa-hdd"/>{{ clipboard.disk }}
</span>
</div>
<div class="text-right text-muted">
<span v-bind:title="`${lang.clipboard.actionType} - ${lang.clipboard[clipboard.type]}`">
<i v-if="clipboard.type === 'copy'" class="fas fa-copy"/>
<i v-else class="fas fa-cut"/>
</span>
</div>
</div>
<hr>
<div class="d-flex justify-content-between"
v-for="(dir, index) in directories"
v-bind:key="`d-${index}`">
<div class="w-75 text-truncate">
<span>
<i class="far fa-folder"/>{{ dir.name }}
</span>
</div>
<div class="text-right">
<button type="button" class="close"
v-bind:title="lang.btn.delete"
v-on:click="deleteItem('directories', dir.path)">
<span aria-hidden="true">&times;</span>
</button>
</div>
</div>
<div class="d-flex justify-content-between"
v-for="(file, index) in files"
v-bind:key="`f-${index}`">
<div class="w-75 text-truncate">
<span>
<i class="far" v-bind:class="file.icon"/>{{ file.name }}
</span>
</div>
<div class="text-right">
<button type="button" class="close"
v-bind:title="lang.btn.delete"
v-on:click="deleteItem('files', file.path)">
<span aria-hidden="true">&times;</span>
</button>
</div>
</div>
</template>
<template v-else>
<span>{{ lang.clipboard.none }}</span>
</template>
</div>
<div class="modal-footer">
<button class="btn btn-danger"
v-bind:disabled="!clipboard.type"
v-on:click="resetClipboard">{{ lang.btn.clear }}
</button>
<button class="btn btn-light" v-on:click="hideModal">{{ lang.btn.cancel }}</button>
</div>
</div>
</template>
<script>
import modal from '../mixins/modal';
import translate from '@/utils/translate';
import helper from '@/utils/helper';
export default {
name: 'Clipboard',
mixins: [modal, translate, helper],
computed: {
/**
* Clipboard state
* @returns {*}
*/
clipboard() {
return this.$store.state.fm.clipboard;
},
/**
* Paths and names for directories
* @returns {{path: *, name: *}[]}
*/
directories() {
return this.$store.state.fm.clipboard.directories.map((item) => ({
path: item,
name: item.split('/').slice(-1)[0],
}));
},
/**
* File names, paths and icons
* @returns {{path: *, name: *, icon: *}[]}
*/
files() {
return this.$store.state.fm.clipboard.files.map((item) => {
const name = item.split('/').slice(-1)[0];
return {
path: item,
name,
icon: this.extensionToIcon(name.split('.').slice(-1)[0]),
};
});
},
},
methods: {
/**
* Delete item from clipboard
* @param type
* @param path
*/
deleteItem(type, path) {
this.$store.commit('fm/truncateClipboard', { type, path });
},
/**
* Reset clipboard
*/
resetClipboard() {
this.$store.commit('fm/resetClipboard');
},
},
};
</script>
<style lang="scss">
.fm-modal-clipboard {
.modal-body .far {
padding-right: 0.5rem;
}
}
</style>
<template>
<div class="modal-content fm-modal-delete">
<div class="modal-header">
<h5 class="modal-title">{{ lang.modal.delete.title }}</h5>
<button type="button" class="close" aria-label="Close" v-on:click="hideModal">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div v-if="selectedItems.length">
<selected-file-list/>
</div>
<div v-else>
<span class="text-danger">{{ lang.modal.delete.noSelected }}</span>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-danger" v-on:click="deleteItems">{{ lang.modal.delete.title }}
</button>
<button class="btn btn-light" v-on:click="hideModal">{{ lang.btn.cancel }}</button>
</div>
</div>
</template>
<script>
import SelectedFileList from '../additions/SelectedFileList.vue';
import modal from '../mixins/modal';
import translate from '@/utils/translate';
export default {
name: 'Delete',
mixins: [modal, translate],
components: { SelectedFileList },
computed: {
/**
* Files and folders for deleting
* @returns {*}
*/
selectedItems() {
return this.$store.getters['fm/selectedItems'];
},
},
methods: {
/**
* Delete selected directories and files
*/
deleteItems() {
// create items list for delete
const items = this.selectedItems.map((item) => ({
path: item.path,
type: item.type,
}));
this.$store.dispatch('fm/delete', items).then(() => {
// close modal window
this.hideModal();
});
},
},
};
</script>
<template>
<div class="modal-content fm-modal-folder">
<div class="modal-header">
<h5 class="modal-title">{{ lang.modal.newFile.title }}</h5>
<button type="button" class="close" aria-label="Close" v-on:click="hideModal">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<label for="fm-file-name">{{ lang.modal.newFile.fieldName }}</label>
<input type="text" class="form-control" id="fm-file-name"
v-focus
v-bind:class="{'is-invalid': fileExist}"
v-model="fileName"
v-on:keyup="validateFileName">
<div class="invalid-feedback" v-show="fileExist">
{{ lang.modal.newFile.fieldFeedback }}
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-info"
v-bind:disabled="!submitActive"
v-on:click="addFile">{{ lang.btn.submit }}
</button>
<button class="btn btn-light" v-on:click="hideModal">{{ lang.btn.cancel }}</button>
</div>
</div>
</template>
<script>
import modal from '../mixins/modal';
import translate from '@/utils/translate';
export default {
name: 'NewFile',
mixins: [modal, translate],
data() {
return {
// name for new file
fileName: '',
// file exist
fileExist: false,
};
},
computed: {
/**
* Submit button - active or no
* @returns {string|boolean}
*/
submitActive() {
return this.fileName && !this.fileExist;
},
},
methods: {
/**
* Check the file name if it exists or not.
*/
validateFileName() {
if (this.fileName) {
this.fileExist = this.$store.getters[`fm/${this.activeManager}/fileExist`](this.fileName);
} else {
this.fileExist = false;
}
},
/**
* Create new file
*/
addFile() {
this.$store.dispatch('fm/createFile', this.fileName).then((response) => {
// if new directory created successfully
if (response.data.result.status === 'success') {
// close modal window
this.hideModal();
}
});
},
},
};
</script>
<template>
<div class="modal-content fm-modal-folder">
<div class="modal-header">
<h5 class="modal-title">{{ lang.modal.newFolder.title }}</h5>
<button type="button" class="close" aria-label="Close" v-on:click="hideModal">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<label for="fm-folder-name">{{ lang.modal.newFolder.fieldName }}</label>
<input type="text" class="form-control" id="fm-folder-name"
v-focus
v-bind:class="{'is-invalid': directoryExist}"
v-model="directoryName"
v-on:keyup="validateDirName">
<div class="invalid-feedback" v-show="directoryExist">
{{ lang.modal.newFolder.fieldFeedback }}
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-info"
v-bind:disabled="!submitActive"
v-on:click="addFolder">{{ lang.btn.submit }}
</button>
<button class="btn btn-light" v-on:click="hideModal">{{ lang.btn.cancel }}</button>
</div>
</div>
</template>
<script>
import modal from '../mixins/modal';
import translate from '@/utils/translate';
export default {
name: 'NewFolder',
mixins: [modal, translate],
data() {
return {
// name for new directory
directoryName: '',
// directory exist
directoryExist: false,
};
},
computed: {
/**
* Submit button - active or no
* @returns {string|boolean}
*/
submitActive() {
return this.directoryName && !this.directoryExist;
},
},
methods: {
/**
* Check the folder name if it exists or not.
*/
validateDirName() {
if (this.directoryName) {
this.directoryExist = this.$store.getters[`fm/${this.activeManager}/directoryExist`](this.directoryName);
} else {
this.directoryExist = false;
}
},
/**
* Create new directory
*/
addFolder() {
this.$store.dispatch('fm/createDirectory', this.directoryName).then((response) => {
// if new directory created successfully
if (response.data.result.status === 'success') {
// close modal window
this.hideModal();
}
});
},
},
};
</script>
<template>
<div class="modal-content fm-modal-preview">
<div class="modal-header">
<h5 class="modal-title w-75 text-truncate">
{{ showCropperModule ? lang.modal.cropper.title : lang.modal.preview.title }}
<small class="text-muted pl-3">{{ selectedItem.basename }}</small>
</h5>
<button type="button" class="close" aria-label="Close" v-on:click="hideModal">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body text-center">
<template v-if="showCropperModule">
<cropper-module v-bind:imgSrc="imgSrc"
v-bind:maxHeight="maxHeight"
v-on:closeCropper="closeCropper"/>
</template>
<transition v-else name="fade" mode="out-in">
<i v-if="!imgSrc" class="fas fa-spinner fa-spin fa-5x p-5 text-muted"/>
<img v-else
v-bind:src="imgSrc"
v-bind:alt="selectedItem.basename"
v-bind:style="{'max-height': maxHeight+'px'}">
</transition>
</div>
<div v-if="showFooter" class="d-flex justify-content-between">
<span class="d-block">
<button class="btn btn-info"
v-bind:title="lang.modal.cropper.title" v-on:click="showCropperModule = true">
<i class="fas fa-crop-alt"/>
</button>
</span>
<span class="d-block">
<button class="btn btn-light" v-on:click="hideModal">{{ lang.btn.cancel }}</button>
</span>
</div>
</div>
</template>
<script>
import CropperModule from '../additions/Cropper.vue';
import modal from '../mixins/modal';
import translate from '@/utils/translate';
import helper from '@/utils/helper';
import GET from '@/utils/get';
export default {
name: 'Preview',
mixins: [modal, translate, helper],
components: { CropperModule },
data() {
return {
showCropperModule: false,
imgSrc: '',
};
},
created() {
this.loadImage();
},
computed: {
/**
* Authorization required
* @return {*}
*/
auth() {
return this.$store.getters['fm/settings/authHeader'];
},
/**
* Selected disk
* @returns {*}
*/
selectedDisk() {
return this.$store.getters['fm/selectedDisk'];
},
/**
* Selected file
* @returns {*}
*/
selectedItem() {
return this.$store.getters['fm/selectedItems'][0];
},
/**
* Show modal footer
* @return boolean
*/
showFooter() {
return this.canCrop(this.selectedItem.extension) && !this.showCropperModule;
},
/**
* Calculate the max height for image
* @returns {number}
*/
maxHeight() {
if (this.$store.state.fm.modal.modalBlockHeight) {
return this.$store.state.fm.modal.modalBlockHeight - 170;
}
return 300;
},
},
methods: {
/**
* Can we crop this image?
* @param extension
* @returns {boolean}
*/
canCrop(extension) {
return this.$store.state.fm.settings.cropExtensions.includes(extension.toLowerCase());
},
/**
* Close cropper
*/
closeCropper() {
this.showCropperModule = false;
this.loadImage();
},
/**
* Load image
*/
loadImage() {
// if authorization required
if (this.auth) {
GET.preview(
this.selectedDisk,
this.selectedItem.path,
).then((response) => {
const mimeType = response.headers['content-type'].toLowerCase();
const imgBase64 = Buffer.from(response.data, 'binary').toString('base64');
this.imgSrc = `data:${mimeType};base64,${imgBase64}`;
});
} else {
this.imgSrc = `${this.$store.getters['fm/settings/baseUrl']}preview?disk=${this.selectedDisk}&path=${encodeURIComponent(this.selectedItem.path)}&v=${this.selectedItem.timestamp}`;
}
},
},
};
</script>
<style lang="scss">
.fm-modal-preview {
.modal-body {
padding: 0;
img {
max-width: 100%;
}
}
& > .d-flex {
padding: 1rem;
border-top: 1px solid #e9ecef;
}
}
</style>
<template>
<div class="modal-content fm-modal-properties">
<div class="modal-header">
<h5 class="modal-title">{{ lang.modal.properties.title }}</h5>
<button type="button" class="close" aria-label="Close" v-on:click="hideModal">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-2">{{ lang.modal.properties.disk }}:</div>
<div class="col-9">{{ selectedDisk }}</div>
<div class="col-1 text-right">
<i v-on:click="copyToClipboard(selectedDisk)"
v-bind:title="lang.clipboard.copy"
class="far fa-copy"/>
</div>
</div>
<div class="row">
<div class="col-2">{{ lang.modal.properties.name }}:</div>
<div class="col-9">{{ selectedItem.basename }}</div>
<div class="col-1 text-right">
<i v-on:click="copyToClipboard(selectedItem.basename)"
v-bind:title="lang.clipboard.copy"
class="far fa-copy"/>
</div>
</div>
<div class="row">
<div class="col-2">{{ lang.modal.properties.path }}:</div>
<div class="col-9">{{ selectedItem.path }}</div>
<div class="col-1 text-right">
<i v-on:click="copyToClipboard(selectedItem.path)"
v-bind:title="lang.clipboard.copy"
class="far fa-copy"/>
</div>
</div>
<template v-if="selectedItem.type === 'file'">
<div class="row">
<div class="col-2">{{ lang.modal.properties.size }}:</div>
<div class="col-9">{{ bytesToHuman(selectedItem.size) }}</div>
<div class="col-1 text-right">
<i v-on:click="copyToClipboard(bytesToHuman(selectedItem.size))"
v-bind:title="lang.clipboard.copy"
class="far fa-copy"/>
</div>
</div>
<div class="row">
<div class="col-2">{{ lang.modal.properties.url }}:</div>
<div class="col-9">
<span v-if="url">{{ url }}</span>
<span v-else>
<button v-on:click="getUrl" type="button"
class="btn btn-sm btn-light">
<i class="fas fa-sm fa-link"/> Get URL
</button>
</span>
</div>
<div v-if="url" class="col-1 text-right">
<i v-on:click="copyToClipboard(url)"
v-bind:title="lang.clipboard.copy"
class="far fa-copy"/>
</div>
</div>
</template>
<template v-if="selectedItem.hasOwnProperty('timestamp')">
<div class="row">
<div class="col-2">{{ lang.modal.properties.modified }}:</div>
<div class="col-9">{{ timestampToDate(selectedItem.timestamp) }}</div>
<div class="col-1 text-right">
<i v-on:click="copyToClipboard(timestampToDate(selectedItem.timestamp))"
v-bind:title="lang.clipboard.copy"
class="far fa-copy"/>
</div>
</div>
</template>
<template v-if="selectedItem.hasOwnProperty('acl')">
<div class="row">
<div class="col-2">{{ lang.modal.properties.access }}:</div>
<div class="col-9">{{ lang.modal.properties['access_' + selectedItem.acl] }}</div>
</div>
</template>
</div>
</div>
</template>
<script>
import modal from '../mixins/modal';
import translate from '@/utils/translate';
import helper from '@/utils/helper';
import EventBus from '@/utils/eventBus';
export default {
name: 'Properties',
mixins: [modal, translate, helper],
data() {
return {
url: null,
};
},
computed: {
/**
* Selected disk
* @returns {*}
*/
selectedDisk() {
return this.$store.getters['fm/selectedDisk'];
},
/**
* Selected file
* @returns {*}
*/
selectedItem() {
return this.$store.getters['fm/selectedItems'][0];
},
},
methods: {
/**
* Get URL
*/
getUrl() {
this.$store.dispatch('fm/url', {
disk: this.selectedDisk,
path: this.selectedItem.path,
}).then((response) => {
if (response.data.result.status === 'success') {
this.url = response.data.url;
}
});
},
/**
* Copy text to clipboard
* @param text
*/
copyToClipboard(text) {
// create input
const copyInputHelper = document.createElement('input');
copyInputHelper.className = 'copyInputHelper';
document.body.appendChild(copyInputHelper);
// add text
copyInputHelper.value = text;
copyInputHelper.select();
// copy text to clipboard
document.execCommand('copy');
// clear
document.body.removeChild(copyInputHelper);
// Notification
EventBus.$emit('addNotification', {
status: 'success',
message: this.lang.notifications.copyToClipboard,
});
},
},
};
</script>
<style lang="scss">
.fm-modal-properties .modal-body{
.row {
margin-bottom: 0.3rem;
padding-top: 0.3rem;
padding-bottom: 0.3rem;
.fa-copy {
padding-top: 0.2rem;
display: none;
cursor: pointer;
}
&:hover {
background-color: #f8f9fa;
& .fa-copy {
display: block;
}
}
}
.col-2 {
font-weight: bold;
}
.col-9 {
word-wrap: break-word;
}
}
</style>
<template>
<div class="modal-content fm-modal-rename">
<div class="modal-header">
<h5 class="modal-title">{{ lang.modal.rename.title }}</h5>
<button type="button" class="close" aria-label="Close" v-on:click="hideModal">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<label for="fm-input-rename">{{ lang.modal.rename.fieldName }}</label>
<input type="text" class="form-control" id="fm-input-rename"
v-focus
v-bind:class="{'is-invalid': checkName}"
v-model="name"
v-on:keyup="validateName">
<div class="invalid-feedback" v-show="checkName">
{{ lang.modal.rename.fieldFeedback }}
{{ directoryExist ? ` - ${lang.modal.rename.directoryExist}` : ''}}
{{ fileExist ? ` - ${lang.modal.rename.fileExist}` : ''}}
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-info"
v-bind:disabled="submitDisable"
v-on:click="rename">{{ lang.btn.submit }}
</button>
<button class="btn btn-light" v-on:click="hideModal">{{ lang.btn.cancel }}</button>
</div>
</div>
</template>
<script>
import modal from '../mixins/modal';
import translate from '@/utils/translate';
export default {
name: 'Rename',
mixins: [modal, translate],
data() {
return {
name: '',
directoryExist: false,
fileExist: false,
};
},
computed: {
/**
* Selected item
* @returns {*}
*/
selectedItem() {
return this.$store.getters[`fm/${this.activeManager}/selectedList`][0];
},
/**
* Check new name
* @returns {boolean}
*/
checkName() {
return this.directoryExist || this.fileExist || !this.name;
},
/**
* Submit button disable
* @returns {*|boolean}
*/
submitDisable() {
return this.checkName || this.name === this.selectedItem.basename;
},
},
mounted() {
// initiate item name
this.name = this.selectedItem.basename;
},
methods: {
/**
* Validate item name
*/
validateName() {
if (this.name !== this.selectedItem.basename) {
// if item - folder
if (this.selectedItem.type === 'dir') {
// check folder name matches
this.directoryExist = this.$store.getters[`fm/${this.activeManager}/directoryExist`](this.name);
} else {
// check file name matches
this.fileExist = this.$store.getters[`fm/${this.activeManager}/fileExist`](this.name);
}
}
},
/**
* Rename item
*/
rename() {
// create new name with path
const newName = this.selectedItem.dirname
? `${this.selectedItem.dirname}/${this.name}`
: this.name;
this.$store.dispatch('fm/rename', {
type: this.selectedItem.type,
newName,
oldName: this.selectedItem.path,
}).then(() => {
// close modal window
this.hideModal();
});
},
},
};
</script>
<template>
<div class="modal-content fm-modal-errors">
<div class="modal-header">
<h5 class="modal-title">{{ lang.modal.status.title }}</h5>
<button type="button" class="close" aria-label="Close" v-on:click="hideModal">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div v-if="errors.length">
<ul class="list-unstyled">
<li v-for="(item, index) in errors" v-bind:key="index">
{{ item.status }} - {{ item.message }}
</li>
</ul>
</div>
<div v-else>
<span>{{ lang.modal.status.noErrors }}</span>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-danger"
v-bind:disabled="!errors.length"
v-on:click="clearErrors">{{ lang.btn.clear }}</button>
<button class="btn btn-light" v-on:click="hideModal">{{ lang.btn.cancel }}</button>
</div>
</div>
</template>
<script>
import modal from '../mixins/modal';
import translate from '@/utils/translate';
export default {
name: 'Status',
mixins: [modal, translate],
computed: {
/**
* Application errors
* @returns {default.computed.errors|(function())|Array|boolean}
*/
errors() {
return this.$store.state.fm.messages.errors;
},
},
methods: {
/**
* Clear all errors
*/
clearErrors() {
this.$store.commit('fm/messages/clearErrors');
},
},
};
</script>
<template>
<div class="modal-content fm-modal-text-edit">
<div class="modal-header">
<h5 class="modal-title w-75 text-truncate">
{{ lang.modal.editor.title }} <small class="text-muted pl-3">{{ selectedItem.basename }}</small>
</h5>
<button type="button" class="close" aria-label="Close" v-on:click="hideModal">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<codemirror ref="fmCodeEditor" v-model="code" :options="cmOptions"/>
</div>
<div class="modal-footer">
<button class="btn btn-info"
v-on:click="updateFile">{{ lang.btn.submit }}
</button>
<button class="btn btn-light" v-on:click="hideModal">{{ lang.btn.cancel }}</button>
</div>
</div>
</template>
<script>
import { codemirror } from 'vue-codemirror';
import 'codemirror/mode/shell/shell';
import 'codemirror/mode/css/css';
import 'codemirror/mode/sass/sass';
import 'codemirror/mode/htmlmixed/htmlmixed';
import 'codemirror/mode/javascript/javascript';
import 'codemirror/mode/vue/vue';
import 'codemirror/mode/markdown/markdown';
import 'codemirror/mode/xml/xml';
import 'codemirror/mode/clike/clike';
import 'codemirror/mode/php/php';
import 'codemirror/mode/sql/sql';
import 'codemirror/mode/lua/lua';
import 'codemirror/mode/perl/perl';
import 'codemirror/mode/python/python';
import 'codemirror/mode/swift/swift';
import 'codemirror/mode/ruby/ruby';
import 'codemirror/mode/go/go';
import 'codemirror/mode/yaml/yaml';
import 'codemirror/mode/properties/properties';
import modal from '../mixins/modal';
import translate from '@/utils/translate';
export default {
name: 'TextEdit',
mixins: [modal, translate],
components: { codemirror },
data() {
return {
code: '',
};
},
mounted() {
// get file for edit
this.$store.dispatch('fm/getFile', {
disk: this.selectedDisk,
path: this.selectedItem.path,
}).then((response) => {
// add code
if (this.selectedItem.extension === 'json') {
this.code = JSON.stringify(response.data, null, 4);
} else {
this.code = response.data;
}
// set size
this.$refs.fmCodeEditor.codemirror.setSize(null, this.editorHeight);
});
},
computed: {
/**
* Selected disk
* @returns {*}
*/
selectedDisk() {
return this.$store.getters['fm/selectedDisk'];
},
/**
* Selected file
* @returns {*}
*/
selectedItem() {
return this.$store.getters['fm/selectedItems'][0];
},
/**
* CodeMirror options
* @returns {{tabSize: number, mode: *, theme: string, lineNumbers: boolean, line: boolean}}
*/
cmOptions() {
return {
mode: this.$store.state.fm.settings.textExtensions[this.selectedItem.extension],
theme: 'blackboard',
lineNumbers: true,
line: true,
};
},
/**
* Calculate the height of the code editor
* @returns {number}
*/
editorHeight() {
if (this.$store.state.fm.modal.modalBlockHeight) {
return this.$store.state.fm.modal.modalBlockHeight - 200;
}
return 300;
},
},
methods: {
// Update file
updateFile() {
const formData = new FormData();
// add disk name
formData.append('disk', this.selectedDisk);
// add path
formData.append('path', this.selectedItem.dirname);
// add updated file
formData.append('file', new Blob([this.code]), this.selectedItem.basename);
this.$store.dispatch('fm/updateFile', formData).then((response) => {
// if file updated successfully
if (response.data.result.status === 'success') {
// close modal window
this.hideModal();
}
});
},
},
};
</script>
<style lang="scss">
@import '~codemirror/lib/codemirror.css';
@import '~codemirror/theme/blackboard.css';
.fm-modal-text-edit {
.modal-body {
padding: 0;
}
}
</style>
<template>
<div class="modal-content fm-modal-unzip">
<div class="modal-header">
<h5 class="modal-title">{{ lang.modal.unzip.title }}</h5>
<button type="button" class="close" aria-label="Close" v-on:click="hideModal">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="d-flex justify-content-between">
<div>
<strong>{{ lang.modal.unzip.fieldRadioName }}</strong>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input"
id="unzipRadio1"
type="radio"
name="uploadOptions"
value="0"
checked
v-model.number="createFolder">
<label class="form-check-label" for="unzipRadio1">
{{ lang.modal.unzip.fieldRadio1 }}
</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input"
id="unzipRadio2"
type="radio"
name="uploadOptions"
value="1"
checked
v-model.number="createFolder">
<label class="form-check-label" for="unzipRadio2">
{{ lang.modal.unzip.fieldRadio2 }}
</label>
</div>
</div>
<hr>
<div v-if="createFolder" class="form-group">
<label for="fm-folder-name">{{ lang.modal.unzip.fieldName }}</label>
<input type="text" class="form-control" id="fm-folder-name"
v-focus
v-bind:class="{'is-invalid': directoryExist}"
v-model="directoryName"
v-on:keyup="validateDirName">
<div class="invalid-feedback" v-show="directoryExist">
{{ lang.modal.unzip.fieldFeedback }}
</div>
</div>
<span v-else class="text-danger">{{ lang.modal.unzip.warning }}</span>
</div>
<div class="modal-footer">
<button class="btn btn-info"
v-bind:disabled="!submitActive"
v-on:click="unpackArchive">{{ lang.btn.submit }}
</button>
<button class="btn btn-light" v-on:click="hideModal">{{ lang.btn.cancel }}</button>
</div>
</div>
</template>
<script>
import modal from '../mixins/modal';
import translate from '@/utils/translate';
export default {
name: 'Unzip',
mixins: [modal, translate],
data() {
return {
createFolder: 0,
// name for new directory
directoryName: '',
// directory exist
directoryExist: false,
};
},
computed: {
/**
* Submit button - active or no
* @returns {string|boolean}
*/
submitActive() {
if (this.createFolder) {
return this.directoryName && !this.directoryExist;
}
return true;
},
},
methods: {
/**
* Check the folder name if it exists or not.
*/
validateDirName() {
if (this.directoryName) {
this.directoryExist = this.$store.getters[`fm/${this.activeManager}/directoryExist`](this.directoryName);
} else {
this.directoryExist = false;
}
},
/**
* Unpack selected archive
*/
unpackArchive() {
this.$store.dispatch('fm/unzip', this.createFolder ? this.directoryName : null).then(() => {
// close modal window
this.hideModal();
});
},
},
};
</script>
<template>
<div class="modal-content fm-modal-upload">
<div class="modal-header">
<h5 class="modal-title">{{ lang.modal.upload.title }}</h5>
<button type="button" class="close" aria-label="Close" v-on:click="hideModal">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="fm-btn-wrapper" v-show="!progressBar">
<button type="button" class="btn btn-secondary btn-block">
{{ lang.btn.uploadSelect }}
</button>
<input type="file" multiple name="myfile" v-on:change="selectFiles($event)">
</div>
<div class="fm-upload-list" v-if="countFiles">
<div class="d-flex justify-content-between"
v-for="(item, index) in newFiles"
v-bind:key="index">
<div class="w-75 text-truncate">
<i class="far" v-bind:class="mimeToIcon(item.type)"/>
{{ item.name }}
</div>
<div class="text-right">
{{ bytesToHuman(item.size) }}
</div>
</div>
<hr>
<div class="d-flex justify-content-between">
<div>
<strong>{{ lang.modal.upload.selected }}</strong>
{{ newFiles.length }}
</div>
<div class="text-right">
<strong>{{ lang.modal.upload.size }}</strong>
{{ allFilesSize }}
</div>
</div>
<hr>
<div class="d-flex justify-content-between">
<div>
<strong>{{ lang.modal.upload.ifExist }}</strong>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input"
id="uploadRadio1"
type="radio"
name="uploadOptions"
value="0"
checked
v-model="overwrite">
<label class="form-check-label" for="uploadRadio1">
{{ lang.modal.upload.skip }}
</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input"
id="uploadRadio2"
type="radio"
name="uploadOptions"
value="1"
checked
v-model="overwrite">
<label class="form-check-label" for="uploadRadio2">
{{ lang.modal.upload.overwrite }}
</label>
</div>
</div>
<hr>
</div>
<div v-else><p>{{ lang.modal.upload.noSelected }}</p></div>
<div class="fm-upload-info">
<!-- Progress Bar -->
<div class="progress" v-show="countFiles">
<div class="progress-bar progress-bar-striped bg-info" role="progressbar"
v-bind:aria-valuenow="progressBar"
aria-valuemin="0"
aria-valuemax="100"
v-bind:style="{width: progressBar + '%' }">
{{ progressBar }}%
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn"
v-bind:class="[countFiles ? 'btn-info' : 'btn-light']"
v-bind:disabled="!countFiles"
v-on:click="uploadFiles">{{ lang.btn.submit }}
</button>
<button class="btn btn-light" v-on:click="hideModal()">{{ lang.btn.cancel }}</button>
</div>
</div>
</template>
<script>
import modal from '../mixins/modal';
import translate from '@/utils/translate';
import helper from '@/utils/helper';
export default {
name: 'Upload',
mixins: [modal, translate, helper],
data() {
return {
// selected files
newFiles: [],
// overwrite if exists
overwrite: 0,
};
},
computed: {
/**
* Progress bar value - %
* @returns {number}
*/
progressBar() {
return this.$store.state.fm.messages.actionProgress;
},
/**
* Count of files selected for upload
* @returns {number}
*/
countFiles() {
return this.newFiles.length;
},
/**
* Calculate the size of all files
* @returns {*|string}
*/
allFilesSize() {
let size = 0;
for (let i = 0; i < this.newFiles.length; i += 1) {
size += this.newFiles[i].size;
}
return this.bytesToHuman(size);
},
},
methods: {
/**
* Select file or files
* @param event
*/
selectFiles(event) {
// files selected?
if (event.target.files.length === 0) {
// no file selected
this.newFiles = [];
} else {
// we have file or files
this.newFiles = event.target.files;
}
},
/**
* Upload new files
*/
uploadFiles() {
// if files exists
if (this.countFiles) {
// upload files
this.$store.dispatch('fm/upload', {
files: this.newFiles,
overwrite: this.overwrite,
}).then((response) => {
// if upload is successful
if (response.data.result.status === 'success') {
// close modal window
this.hideModal();
}
});
}
},
},
};
</script>
<style lang="scss">
.fm-modal-upload {
.fm-btn-wrapper {
position: relative;
overflow: hidden;
padding-bottom: 6px;
margin-bottom: 0.6rem;
}
.fm-btn-wrapper input[type=file] {
font-size: 100px;
position: absolute;
left: 0;
top: 0;
opacity: 0;
cursor: pointer;
}
.fm-upload-list .far {
padding-right: 0.5rem;
}
.fm-upload-list .form-check-inline {
margin-right: 0;
}
.fm-upload-info > .progress {
margin-bottom: 1rem;
}
}
</style>
<template>
<div class="modal-content fm-modal-video-player">
<div class="modal-header">
<h5 class="modal-title w-75 text-truncate">
{{ lang.modal.videoPlayer.title }} <small class="text-muted pl-3">{{ videoFile.basename }}</small>
</h5>
<button type="button" class="close" aria-label="Close" v-on:click="hideModal">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<video ref="fmVideo" controls/>
</div>
</div>
</template>
<script>
import Plyr from 'plyr';
import modal from '../mixins/modal';
import translate from '@/utils/translate';
export default {
name: 'Player',
mixins: [modal, translate],
data() {
return {
player: {},
};
},
mounted() {
// initiate video player
this.player = new Plyr(this.$refs.fmVideo);
// load source
this.player.source = {
type: 'video',
title: this.videoFile.filename,
sources: [{
src: `${this.$store.getters['fm/settings/baseUrl']}stream-file?disk=${this.selectedDisk}&path=${encodeURIComponent(this.videoFile.path)}`,
type: `audio/${this.videoFile.extension}`,
}],
};
},
beforeDestroy() {
this.player.destroy();
},
computed: {
/**
* Selected disk
* @returns {*}
*/
selectedDisk() {
return this.$store.getters['fm/selectedDisk'];
},
/**
* Video file
* @returns {*}
*/
videoFile() {
return this.$store.getters['fm/selectedItems'][0];
},
},
methods: {
},
};
</script>
<style lang="scss">
.fm-modal-video-player {
}
</style>
<template>
<div class="modal-content fm-modal-zip">
<div class="modal-header">
<h5 class="modal-title">{{ lang.modal.zip.title }}</h5>
<button type="button" class="close" aria-label="Close" v-on:click="hideModal">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<label for="fm-zip-name">{{ lang.modal.zip.fieldName }}</label>
<div class="input-group mb-3">
<input type="text" class="form-control" id="fm-zip-name"
v-focus
v-bind:class="{'is-invalid': archiveExist}"
v-model="archiveName"
v-on:keyup="validateArchiveName">
<div class="input-group-append">
<span class="input-group-text">.zip</span>
</div>
<div class="invalid-feedback" v-show="archiveExist">
{{ lang.modal.zip.fieldFeedback }}
</div>
</div>
<hr>
<selected-file-list/>
</div>
<div class="modal-footer">
<button class="btn btn-info"
v-bind:disabled="!submitActive"
v-on:click="createArchive">{{ lang.btn.submit }}
</button>
<button class="btn btn-light" v-on:click="hideModal">{{ lang.btn.cancel }}</button>
</div>
</div>
</template>
<script>
import SelectedFileList from '../additions/SelectedFileList.vue';
import modal from '../mixins/modal';
import translate from '@/utils/translate';
export default {
name: 'Zip',
mixins: [modal, translate],
components: { SelectedFileList },
data() {
return {
// name for new archive
archiveName: '',
// archive exist
archiveExist: false,
};
},
computed: {
/**
* Submit button - active or no
* @returns {string|boolean}
*/
submitActive() {
return this.archiveName && !this.archiveExist;
},
},
methods: {
/**
* Check the archive name if it exists or not.
*/
validateArchiveName() {
if (this.archiveName) {
this.archiveExist = this.$store.getters[`fm/${this.activeManager}/fileExist`](`${this.archiveName}.zip`);
} else {
this.archiveExist = false;
}
},
/**
* Create new archive
*/
createArchive() {
this.$store.dispatch('fm/zip', `${this.archiveName}.zip`).then(() => {
// close modal window
this.hideModal();
});
},
},
};
</script>
<template>
<ul class="list-unstyled fm-tree-branch">
<li v-for="(directory, index) in subDirectories" v-bind:key="index">
<p class="unselectable"
v-bind:class="{'selected': isDirectorySelected(directory.path)}"
v-on:click="selectDirectory(directory.path)">
<i class="far"
v-if="directory.props.hasSubdirectories"
v-on:click.stop="showSubdirectories(
directory.path,
directory.props.showSubdirectories
)"
v-bind:class="[arrowState(index)
? 'fa-minus-square'
: 'fa-plus-square'
]"/>
<i class="fas fa-minus fa-xs" v-else/>
{{ directory.basename }}
</p>
<transition name="fade-tree">
<branch v-show="arrowState(index)"
v-if="directory.props.hasSubdirectories"
v-bind:parent-id="directory.id">
</branch>
</transition>
</li>
</ul>
</template>
<script>
export default {
name: 'Branch',
props: {
parentId: { type: Number, required: true },
},
computed: {
/**
* Subdirectories for selected parent
* @returns {*}
*/
subDirectories() {
return this.$store.getters['fm/tree/directories'].filter((item) => item.parentId === this.parentId);
},
},
methods: {
/**
* Check, is this directory selected?
* @param path
* @returns {boolean}
*/
isDirectorySelected(path) {
return this.$store.state.fm.left.selectedDirectory === path;
},
/**
* Show subdirectories - arrow
* @returns {boolean}
* @param index
*/
arrowState(index) {
return this.subDirectories[index].props.showSubdirectories;
},
/**
* Show/Hide subdirectories
* @param path
* @param showState
*/
showSubdirectories(path, showState) {
if (showState) {
// hide
this.$store.dispatch('fm/tree/hideSubdirectories', path);
} else {
// show
this.$store.dispatch('fm/tree/showSubdirectories', path);
}
},
/**
* Load selected directory and show files
* @param path
*/
selectDirectory(path) {
// only if this path not selected
if (!this.isDirectorySelected(path)) {
this.$store.dispatch('fm/left/selectDirectory', { path, history: true });
}
},
},
};
</script>
<style lang="scss">
.fm-tree-branch {
display: table;
width: 100%;
padding-left: 1.4rem;
li > p{
margin-bottom: 0.1rem;
padding: 0.4rem 0.4rem;
white-space: nowrap;
cursor: pointer;
&:hover,
&.selected {
background-color: #f8f9fa;
}
}
.fas.fa-minus{
padding-left: 0.1rem;
padding-right: 0.6rem;
}
.far{
padding-right: 0.5rem;
}
}
.fade-tree-enter-active, .fade-tree-leave-active {
transition: all .3s ease;
}
.fade-tree-enter, .fade-tree-leave-to {
transform: translateX(20px);
opacity: 0;
}
</style>
<template>
<div class="fm-tree">
<div class="fm-tree-disk sticky-top">
<i class="far fa-hdd"/> {{ selectedDisk }}
</div>
<branch v-bind:parent-id="0"/>
</div>
</template>
<script>
import Branch from './Branch.vue';
export default {
name: 'FolderTree',
components: {
branch: Branch,
},
computed: {
/**
* Selected Disk
* @returns {*}
*/
selectedDisk() {
return this.$store.getters['fm/selectedDisk'];
},
},
};
</script>
<style lang="scss">
.fm-tree {
overflow: auto;
border-right: 1px solid #6d757d;
& > .fm-folders-tree {
padding-left: 0.2rem;
}
.fm-tree-disk {
padding: 0.2rem 0.3rem;
margin-bottom: 0.3rem;
background-color: white;
}
.fm-tree-disk > i {
padding-left: 0.2rem;
padding-right: 0.5rem;
}
}
</style>
import store from '@/store/file-manager';
import FileManager from './FileManager.vue';
/**
* Install
*
* @param Vue
* @param options
*/
export default function install(Vue, options = {}) {
if (!options.store) window.console.error('Please provide a store!!');
Vue.component('file-manager', FileManager);
options.store.registerModule('fm', store);
}
...@@ -337,7 +337,7 @@ export default { ...@@ -337,7 +337,7 @@ export default {
this.expandForm = !this.expandForm; this.expandForm = !this.expandForm;
}, },
onSelectChange(selectedRowKeys) { onSelectChange(selectedRowKeys) {
console.log("selectedRowKeys changed: ", selectedRowKeys); window.console.log("selectedRowKeys changed: ", selectedRowKeys);
this.selectedRowKeys = selectedRowKeys; this.selectedRowKeys = selectedRowKeys;
}, },
handleTableChange(pagination, filters, sorter) { handleTableChange(pagination, filters, sorter) {
......
...@@ -3,11 +3,6 @@ ...@@ -3,11 +3,6 @@
<div class="ai-login"> <div class="ai-login">
<a-form <a-form
@submit="handleSubmit" @submit="handleSubmit"
:autoFormCreate="
(form) => {
this.form = form;
}
"
> >
<a-tabs <a-tabs
:animated="false" :animated="false"
...@@ -88,7 +83,7 @@ ...@@ -88,7 +83,7 @@
<a-checkbox :checked="autoLogin" @change="onSwithAutoLogin"> <a-checkbox :checked="autoLogin" @change="onSwithAutoLogin">
自动登录 自动登录
</a-checkbox> </a-checkbox>
<a style="float: right" href="#"> 忘记密码 </a> <a style="float: right;color: #2ECCCD;" href="#"> 忘记密码 </a>
</div> </div>
<a-form-item> <a-form-item>
<a-button <a-button
...@@ -165,12 +160,14 @@ export default { ...@@ -165,12 +160,14 @@ export default {
} }
}, },
handleSubmit(e) { handleSubmit(e) {
window.console.log(e);
this.form.validateFields( this.form.validateFields(
this.active, this.active,
{ {
force: true, force: true,
}, },
(err, values) => { (err, values) => {
window.console.log(values);
if (!err) { if (!err) {
// console.log("Received values of form: ", values); // console.log("Received values of form: ", values);
this.$router.push({ path: "/" }); this.$router.push({ path: "/" });
......
...@@ -3,11 +3,6 @@ ...@@ -3,11 +3,6 @@
<h3>注册</h3> <h3>注册</h3>
<a-form <a-form
@submit="handleSubmit" @submit="handleSubmit"
:autoFormCreate="
(form) => {
this.form = form;
}
"
> >
<a-form-item <a-form-item
v-decorator="[ v-decorator="[
......
...@@ -72,8 +72,16 @@ ...@@ -72,8 +72,16 @@
width: 100%; width: 100%;
} }
.other {
a {
color: #2ECCCD;
}
}
.submit { .submit {
width: 100%; width: 100%;
margin-top: 24px; margin-top: 24px;
border-color: #2ECCCD;
background-color: #2ECCCD;
} }
} }
...@@ -20,13 +20,16 @@ ...@@ -20,13 +20,16 @@
display: block; display: block;
width: 100%; width: 100%;
} }
.submit { .submit {
width: 50%; width: 50%;
border-color: #2ECCCD;
background-color: #2ECCCD;
} }
.login { .login {
float: right; float: right;
color: #2ECCCD;
line-height: @btn-height-lg; line-height: @btn-height-lg;
} }
......
'use strict' "use strict";
// 基础配置文件 // 基础配置文件
const path = require('path') const path = require("path");
const webpack = require('webpack') const webpack = require("webpack");
// 拼接路径 // 拼接路径
function resolve(dir) { function resolve(dir) {
return path.join(__dirname, dir) return path.join(__dirname, dir);
} }
// 基础路径 注意发布之前要先修改这里 // 基础路径 注意发布之前要先修改这里
const BASE_URL = process.env.NODE_ENV === 'production' const BASE_URL = process.env.NODE_ENV === "production" ? "/frontend/" : "/";
? '/frontend/'
: '/'
module.exports = { module.exports = {
baseUrl: BASE_URL, // 根据你的实际情况更改这里 baseUrl: BASE_URL, // 根据你的实际情况更改这里
productionSourceMap: false, productionSourceMap: false,
devServer: { devServer: {
publicPath: BASE_URL // 和 baseUrl 保持一致 publicPath: BASE_URL, // 和 baseUrl 保持一致
// port: 8080,
// open: true,
// overlay: {
// warnings: false,
// errors: true,
// },
// proxy: {
// // change xxx-api/login => mock/login
// // detail: https://cli.vuejs.org/config/#devserver-proxy
// "/api/v1": {
// target: "http://127.0.0.1:5001/",
// changeOrigin: true,
// pathRewrite: {},
// },
// "/file-manager": {
// target: "https://file-manager.webmai.ru/",
// changeOrigin: true,
// pathRewrite: {},
// },
// "/uowap/": {
// target: "https://web-drcn.hispace.dbankcloud.cn/",
// changeOrigin: true,
// pathRewrite: {},
// },
// },
// after: require("./mock/mock-server.js"),
}, },
css: { css: {
loaderOptions: { loaderOptions: {
less: { less: {
modifyVars: { modifyVars: {
'ai-prefix': 'ai', "ai-prefix": "ai",
'primary-color': '#42b983' "primary-color": "#2ECCCD",
}, },
paths: [ paths: [resolve("node_modules"), resolve("src")],
resolve('node_modules'), javascriptEnabled: true,
resolve('src') },
], },
javascriptEnabled: true
}
}
}, },
configureWebpack: { configureWebpack: {
plugins: [ plugins: [
new webpack.ContextReplacementPlugin(/moment[\\/]locale$/, /^\.\/(zh-cn|en-us)$/), new webpack.ContextReplacementPlugin(
] /moment[\\/]locale$/,
/^\.\/(zh-cn|en-us)$/
),
],
}, },
chainWebpack: config => { chainWebpack: (config) => {
const svgRule = config.module.rule('svg') const svgRule = config.module.rule("svg");
svgRule.uses.clear() svgRule.uses.clear();
svgRule svgRule.include
.include .add(resolve("src/assets/svg-icons"))
.add(resolve('src/assets/svg-icons'))
.end() .end()
.use('svg-sprite-loader') .use("svg-sprite-loader")
.loader('svg-sprite-loader') .loader("svg-sprite-loader")
.options({ .options({
symbolId: 'ai-[name]' symbolId: "ai-[name]",
}) })
.end() .end();
// image exclude // image exclude
const imagesRule = config.module.rule('images') const imagesRule = config.module.rule("images");
imagesRule imagesRule
.test(/\.(png|jpe?g|gif|webp|svg)(\?.*)?$/) .test(/\.(png|jpe?g|gif|webp|svg)(\?.*)?$/)
.exclude .exclude.add(resolve("src/assets/svg-icons"))
.add(resolve('src/assets/svg-icons')) .end();
.end()
// 重新设置 alias // 重新设置 alias
config.resolve.alias config.resolve.alias.set("@", resolve("src"));
.set('@', resolve('src')) },
} };
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment