mirror of
https://github.com/drakkan/sftpgo.git
synced 2024-11-22 07:30:25 +00:00
5b8f283e03
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2653 lines
No EOL
112 KiB
HTML
2653 lines
No EOL
112 KiB
HTML
<!--
|
|
Copyright (C) 2023 Nicola Murino
|
|
|
|
This WebUI uses the KeenThemes Mega Bundle, a proprietary theme:
|
|
|
|
https://keenthemes.com/products/templates-mega-bundle
|
|
|
|
KeenThemes HTML/CSS/JS components are allowed for use only within the
|
|
SFTPGo product and restricted to be used in a resealable HTML template
|
|
that can compete with KeenThemes products anyhow.
|
|
|
|
This WebUI is allowed for use only within the SFTPGo product and
|
|
therefore cannot be used in derivative works/products without an
|
|
explicit grant from the SFTPGo Team (support@sftpgo.com).
|
|
-->
|
|
{{template "base" .}}
|
|
|
|
{{- define "page_body"}}
|
|
{{- template "errmsg" .Error}}
|
|
|
|
{{- $move_copy_msg := ""}}
|
|
{{- if and .CanRename .CanCopy}}
|
|
{{- $move_copy_msg = "fs.move_copy"}}
|
|
{{- else}}
|
|
{{- if .CanRename}}
|
|
{{- $move_copy_msg = "fs.move.msg"}}
|
|
{{- else}}
|
|
{{- if .CanCopy}}
|
|
{{- $move_copy_msg = "fs.copy.msg"}}
|
|
{{- end}}
|
|
{{- end}}
|
|
{{- end}}
|
|
|
|
<div class="card card-flush shadow-sm">
|
|
<div class="card-header pt-8">
|
|
<div class="card-title">
|
|
<div class="d-flex align-items-center position-relative my-1">
|
|
<i class="ki-solid ki-magnifier fs-1 position-absolute ms-6"></i>
|
|
<input name="search" data-i18n="[placeholder]general.search" type="text" data-kt-filemanager-table-filter="search" class="form-control rounded-1 w-250px ps-15" placeholder="Search Files & Folders" />
|
|
</div>
|
|
</div>
|
|
<div class="card-toolbar">
|
|
<div class="d-flex justify-content-end" data-kt-filemanager-table-toolbar="base">
|
|
{{- if .CanCreateDirs}}
|
|
<button id="id_create_dir_button" type="button" class="btn btn-flex btn-light-primary me-3">
|
|
<i class="ki-duotone ki-add-folder fs-2">
|
|
<span class="path1"></span>
|
|
<span class="path2"></span>
|
|
</i>
|
|
<span data-i18n="fs.new_folder">New Folder</span>
|
|
</button>
|
|
{{- end}}
|
|
{{- if .CanAddFiles}}
|
|
<button type="button" class="btn btn-flex btn-primary" data-bs-toggle="modal" data-bs-target="#modal_upload">
|
|
<i class="ki-duotone ki-folder-up fs-2">
|
|
<span class="path1"></span>
|
|
<span class="path2"></span>
|
|
</i>
|
|
<span data-i18n="fs.upload.text">Upload Files</span>
|
|
</button>
|
|
{{- end}}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="d-flex flex-stack">
|
|
<div class="badge badge-lg badge-light-primary" data-kt-filemanager-table-nav-bar="base">
|
|
<div class="d-flex align-items-center flex-wrap">
|
|
<i class="ki-duotone ki-home fs-1 text-primary me-3"></i>
|
|
<a data-i18n="fs.home" href="{{.FilesURL}}?path=%2F">Home</a>
|
|
{{- range .Paths}}
|
|
<i class="ki-duotone ki-right fs-2x text-primary mx-1"></i>
|
|
{{- if eq .Href ""}}
|
|
<span>{{.DirName}}</span>
|
|
{{- else}}
|
|
<a href="{{.Href}}">{{.DirName}}</a>
|
|
{{- end}}
|
|
{{- end}}
|
|
</div>
|
|
</div>
|
|
<div class="d-flex align-items-center d-none" data-kt-filemanager-table-toolbar="selected">
|
|
<div class="fw-bold me-5">
|
|
<span class="me-2" data-kt-filemanager-table-select="selected_count"></span>
|
|
</div>
|
|
<div class="form-check form-switch form-check-custom form-check-solid me-5" data-kt-filemanager-table-select="select_all_pages_container">
|
|
<input class="form-check-input" type="checkbox" id="id_select_all_pages" data-kt-filemanager-table-select="select_all_pages" />
|
|
<label data-i18n="fs.select_across_pages" class="form-check-label fw-semibold text-gray-900" for="id_select_all_pages">
|
|
Select across pages
|
|
</label>
|
|
</div>
|
|
{{- if or .CanDownload .CanDelete}}
|
|
<div>
|
|
<button type="button" class="btn btn-light-primary rotate" data-kt-menu-trigger="click" data-kt-menu-placement="bottom">
|
|
<span data-i18n="general.actions">Actions</span>
|
|
<i class="ki-duotone ki-down fs-3 rotate-180 ms-3 me-0"></i>
|
|
</button>
|
|
<div class="menu menu-sub menu-sub-dropdown menu-column menu-rounded menu-gray-800 menu-state-bg-light-primary fw-semibold w-auto min-w-200 mw-300px py-4" data-kt-menu="true">
|
|
{{- if .CanDownload}}
|
|
<div class="menu-item px-3">
|
|
<a data-i18n="fs.download" href="#" class="menu-link px-3 fs-6" data-kt-filemanager-table-select="download_selected">
|
|
Download
|
|
</a>
|
|
</div>
|
|
{{- end}}
|
|
{{- if not .ShareUploadBaseURL}}
|
|
{{- if or .CanRename .CanAddFiles}}
|
|
<div class="menu-item px-3">
|
|
<a data-i18n="{{$move_copy_msg}}" href="#" class="menu-link px-3 fs-6" data-kt-filemanager-table-select="move_or_copy_selected">
|
|
Move or copy
|
|
</a>
|
|
</div>
|
|
{{- end}}
|
|
{{- if .CanShare}}
|
|
<div class="menu-item px-3">
|
|
<a data-i18n="fs.share" href="#" class="menu-link px-3 fs-6" data-kt-filemanager-table-select="share_selected">
|
|
Share
|
|
</a>
|
|
</div>
|
|
{{- end}}
|
|
{{- end}}
|
|
{{- if .CanDelete}}
|
|
<div class="menu-item px-3">
|
|
<a data-i18n="general.delete" href="#" class="menu-link px-3 text-danger fs-6" data-kt-filemanager-table-select="delete_selected">
|
|
Delete
|
|
</a>
|
|
</div>
|
|
{{- end}}
|
|
</div>
|
|
</div>
|
|
{{- end}}
|
|
</div>
|
|
</div>
|
|
<div class="new_folder_divider py-2 d-none">
|
|
<hr>
|
|
</div>
|
|
<div id="file_manager_new_folder" class="d-flex align-items-center d-none">
|
|
<span>
|
|
<i class="ki-duotone ki-folder fs-2x text-primary me-4">
|
|
<span class="path1"></span>
|
|
<span class="path2"></span>
|
|
</i>
|
|
</span>
|
|
<input data-i18n="[placeholder]fs.create_folder_msg" id="file_manager_new_folder_input" type="text" name="new_folder_name" placeholder="Enter the new folder name" class="form-control mw-250px me-3" />
|
|
<button class="btn btn-icon btn-light-primary me-3" id="file_manager_add_folder">
|
|
<span class="indicator-label">
|
|
<i class="ki-duotone ki-check fs-1"></i>
|
|
</span>
|
|
<span class="indicator-progress">
|
|
<span class="spinner-border spinner-border-sm align-middle"></span>
|
|
</span>
|
|
</button>
|
|
<button class="btn btn-icon btn-light-danger" id="file_manager_cancel_folder">
|
|
<i class="ki-solid ki-cross fs-1"></i>
|
|
</button>
|
|
</div>
|
|
<div class="new_folder_divider py-2 d-none">
|
|
<hr>
|
|
</div>
|
|
<div id="upload_files_empty_container" class="d-none mt-10">
|
|
<form id="upload_files_empty_form" action="{{.FilesURL}}?path={{.CurrentDir}}" method="POST" enctype="multipart/form-data">
|
|
<div class="fv-row">
|
|
<div class="dropzone mh-350px overflow-auto visibility-auto" id="upload_files_empty">
|
|
<div class="dz-message needsclick align-items-center">
|
|
<i class="ki-duotone ki-file-up fs-3x text-primary">
|
|
<span class="path1"></span>
|
|
<span class="path2"></span>
|
|
</i>
|
|
<div class="ms-4">
|
|
<h3 data-i18n="fs.upload.message_empty" class="fs-5 fw-bold text-gray-900 mb-1"></h3>
|
|
<!-- <span class="fs-7 fw-semibold text-gray-500">Upload up to 30 files</span> -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
<div class="d-flex justify-content-end mt-5">
|
|
<button data-i18n="general.submit" type="button" id="upload_files_empty_button" class="btn btn-primary">Submit</button>
|
|
</div>
|
|
</div>
|
|
<div id="loader" class="align-items-center text-center my-10">
|
|
<span class="spinner-border w-15px h-15px text-muted align-middle me-2"></span>
|
|
<span data-i18n="general.loading" class="text-gray-700">Loading...</span>
|
|
</div>
|
|
<div id="file_manager_list_container" class="d-none">
|
|
<table id="file_manager_list" class="table align-middle table-row-dashed fs-6 gy-5">
|
|
<thead>
|
|
<tr class="text-start text-muted fw-bold fs-6 gs-0 text-gray-500">
|
|
<th class="w-10px pe-2">
|
|
<div class="form-check form-check-sm form-check-custom form-check-solid me-3">
|
|
<input id="select_checkbox" class="form-check-input" type="checkbox" />
|
|
</div>
|
|
</th>
|
|
<th></th>
|
|
<th data-i18n="general.name" class="min-w-250px">Name</th>
|
|
<th data-i18n="general.size" class="min-w-10px">Size</th>
|
|
<th data-i18n="general.last_modified" class="min-w-125px">Last Modified</th>
|
|
<th class="w-125px"></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="file_manager_list_body" class="text-gray-700 fw-semibold">
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{- end}}
|
|
|
|
{{- define "extra_css"}}
|
|
<link href="{{.StaticURL}}/assets/plugins/custom/datatables/datatables.bundle.css" rel="stylesheet" type="text/css"/>
|
|
<link href="{{.StaticURL}}/vendor/glightbox/glightbox.min.css" rel="stylesheet" type="text/css"/>
|
|
<style {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}}>
|
|
.gslide-description-bg {
|
|
background: var(--bs-app-bg-color) !important;
|
|
opacity: 0.9;
|
|
}
|
|
</style>
|
|
{{- end}}
|
|
|
|
{{- define "extra_js"}}
|
|
<script {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}} src="{{.StaticURL}}/assets/plugins/custom/datatables/datatables.bundle.js"></script>
|
|
<script {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}} src="{{.StaticURL}}/vendor/glightbox/glightbox.min.js"></script>
|
|
<script {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}} src="{{.StaticURL}}/vendor/pdfobject/pdfobject.min.js"></script>
|
|
<script type="text/javascript" {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}}>
|
|
//{{- $move_copy_msg := ""}}
|
|
//{{- if and .CanRename .CanCopy}}
|
|
//{{- $move_copy_msg = "fs.move_copy"}}
|
|
//{{- else}}
|
|
//{{- if .CanRename}}
|
|
//{{- $move_copy_msg = "fs.move.msg"}}
|
|
//{{- else}}
|
|
//{{- if .CanCopy}}
|
|
//{{- $move_copy_msg = "fs.copy.msg"}}
|
|
//{{- end}}
|
|
//{{- end}}
|
|
//{{- end}}
|
|
|
|
const dzPreviewTemplate = `<div class="d-flex align-items-center mb-2">
|
|
<span class="bullet bullet-dot bg-primary me-2"></span>
|
|
<div class="text-break text-wrap text-left"><span class="fs-5 fw-semibold" data-dz-name></span> (<span class="fs-5 fw-semibold" data-custom-size></span>)</div>
|
|
</div>
|
|
<div class="dz-error-message d-none" data-dz-errormessage></div>
|
|
<div class="dz-progress d-none"><span class="dz-upload" data-dz-uploadprogress></span></div>
|
|
`;
|
|
|
|
//{{- if not .ShareUploadBaseURL}}
|
|
const supportedEditExtensions = ["csv", "bat", "dyalog", "apl", "asc", "pgp", "sig", "asn", "asn1", "b", "bf",
|
|
"c", "h", "ino", "cpp", "c++", "cc", "cxx", "hpp", "h++", "hh", "hxx", "cob", "cpy", "cbl", "cs", "clj",
|
|
"cljc", "cljx", "cljs", "gss", "cmake", "cmake.in", "coffee", "cl", "lisp", "el", "cyp", "cypher",
|
|
"pyx", "pxd", "pxi", "cr", "css", "cql", "d", "dart", "diff", "patch", "dtd", "dylan", "dyl", "intr",
|
|
"ecl", "edn", "e", "elm", "ejs", "erb", "erl", "sql", "factor", "forth", "fth", "4th", "f", "for", "f77",
|
|
"f90", "f95", "fsharp", "s", "go", "groovy", "gradle", "haml", "hs", "lhs", "hx", "hxml", "aspx",
|
|
"html", "htm", "handlebars", "hbs", "pro", "jade", "pug", "java", "jsp", "js", "json", "map", "jsonld",
|
|
"jsx", "j2", "jinja", "jinja2", "jl", "kt", "less", "ls", "lua", "markdown", "md", "mkd", "m", "nb", "wl",
|
|
"wls", "mo", "mps", "mbox", "nsh", "nsi", "nt", "nq", "m", "mm", "ml", "mli", "mll", "mly", "oz", "p",
|
|
"pas", "pl", "pm", "php", "php3", "php4", "php5", "php7", "phtml", "pig", "txt", "text", "conf", "def",
|
|
"list", "log", "pls", "ps1", "psd1", "psm1", "properties", "ini", "in", "proto", "BUILD", "bzl", "py",
|
|
"pyw", "pp", "q", "r", "rst", "spec", "rb", "rs", "sas", "sass", "scala", "scm", "ss", "scss", "sh",
|
|
"ksh", "bash", "siv", "sieve", "slim", "st", "tpl", "sml", "sig", "fun", "smackspec", "soy", "rq", "sparql",
|
|
"nut", "styl", "swift", "text", "ltx", "tex", "v", "sv", "svh", "tcl", "textile", "toml", "1", "2", "3", "4",
|
|
"5", "6", "7", "8", "9", "ttcn", "ttcn3", "ttcnpp", "cfg", "ttl", "ts", "tsx", "webidl", "vb", "vbs",
|
|
"vtl", "vhd", "vhdl", "vue", "xml", "xsl", "xsd", "svg", "xy", "xquery", "ys", "yaml", "yml", "z80",
|
|
"mscgen", "mscin", "msc", "xu", "msgenny", "wat", "wast", "env"];
|
|
const supportedEditFilenames = ["readme", "dockerfile", "pkgbuild"]
|
|
//{{- end}}
|
|
function keepAlive() {
|
|
//{{- if not .ShareUploadBaseURL}}
|
|
axios.get('{{.PingURL}}',{
|
|
timeout: 15000,
|
|
responseType: 'text'
|
|
}).catch(function (error){});
|
|
//{{- end}}
|
|
}
|
|
|
|
var taskStatusWaiter = function () {
|
|
var promiseResolve;
|
|
|
|
function getTaskStatus(taskID, numErrors) {
|
|
axios.get('{{.TasksURL}}'+"/"+encodeURIComponent(taskID),{
|
|
timeout: 15000,
|
|
headers: {
|
|
'X-CSRF-TOKEN': '{{.CSRFToken}}'
|
|
},
|
|
validateStatus: function (status) {
|
|
return status == 200;
|
|
}
|
|
}).then(function(response){
|
|
let status = response.data.status;
|
|
if (status == 0){
|
|
setTimeout(function() {
|
|
getTaskStatus(taskID, numErrors);
|
|
}, 2500);
|
|
} else {
|
|
promiseResolve({
|
|
status: status
|
|
});
|
|
}
|
|
}).catch(function(error){
|
|
numErrors++;
|
|
if (numErrors >= 3){
|
|
promiseResolve({
|
|
status: 0
|
|
});
|
|
return;
|
|
}
|
|
if (error && error.response && error.response.status == 404){
|
|
promiseResolve({
|
|
status: 404
|
|
});
|
|
return;
|
|
}
|
|
setTimeout(function() {
|
|
getTaskStatus(taskID, numErrors);
|
|
}, 2500);
|
|
});
|
|
}
|
|
|
|
return {
|
|
wait: function(params){
|
|
setTimeout(function() {
|
|
getTaskStatus(params.taskID, 0);
|
|
}, params.delay);
|
|
|
|
return new Promise(function(resolve, reject) {
|
|
promiseResolve = resolve;
|
|
});
|
|
}
|
|
}
|
|
}();
|
|
|
|
//{{- if not .ShareUploadBaseURL}}
|
|
var KTDatatablesFoldersExplorer = function () {
|
|
var dt;
|
|
var curDir;
|
|
|
|
var initDatatable = function (dirsURL) {
|
|
$('#errorModalMsg').addClass("d-none");
|
|
dt = $("#dirsbrowser_list").DataTable({
|
|
ajax: {
|
|
url: dirsURL,
|
|
dataSrc: "",
|
|
error: function ($xhr, textStatus, errorThrown) {
|
|
$(".dt-processing").hide();
|
|
let txt = "";
|
|
if ($xhr) {
|
|
let json = $xhr.responseJSON;
|
|
if (json) {
|
|
if (json.message) {
|
|
txt = json.message;
|
|
}
|
|
}
|
|
}
|
|
if (!txt){
|
|
txt = "fs.dir_list.err_generic";
|
|
}
|
|
setI18NData($('#errorModalTxt'), txt);
|
|
$('#errorModalMsg').removeClass("d-none");
|
|
}
|
|
},
|
|
deferRender: true,
|
|
processing: true,
|
|
stateSave: false,
|
|
columns: [
|
|
{
|
|
data: "meta"
|
|
},
|
|
{
|
|
data: "name",
|
|
render: function (data, type, row) {
|
|
if (type === 'display') {
|
|
data = escapeHTML(data);
|
|
return `<div class="d-flex align-items-center">
|
|
<i class="ki-duotone ki-folder fs-1 text-primary me-4">
|
|
<i class="path1"></i>
|
|
<i class="path2"></i>
|
|
</i>
|
|
<a href="#" class="text-gray-700 text-hover-primary" data-dirbrowser-table-row="open">${data}</a>
|
|
</div>`
|
|
}
|
|
return data;
|
|
}
|
|
}
|
|
],
|
|
lengthChange: true,
|
|
columnDefs: [
|
|
{
|
|
targets: 0,
|
|
visible: false,
|
|
searchable: false
|
|
},
|
|
{
|
|
targets: 1,
|
|
visible: true,
|
|
searchable: true
|
|
}
|
|
],
|
|
language: {
|
|
info: $.t('datatable.info'),
|
|
infoEmpty: $.t('datatable.info_empty'),
|
|
infoFiltered: $.t('datatable.info_filtered'),
|
|
loadingRecords: "",
|
|
processing: $.t('datatable.processing'),
|
|
zeroRecords: "",
|
|
emptyTable: $.t('fs.no_more_subfolders')
|
|
},
|
|
order: [1, 'asc']
|
|
});
|
|
|
|
dt.on('draw', function () {
|
|
let dirBrowserNav = document.getElementById("dirs_browser_nav");
|
|
clearChilds(dirBrowserNav);
|
|
let mainNavIcon = document.createElement("i");
|
|
mainNavIcon.classList.add("ki-duotone", "ki-home", "fs-1", "text-primary", "me-3");
|
|
let mainNavLink = document.createElement("a");
|
|
mainNavLink.textContent = $.t('fs.home');
|
|
mainNavLink.href = "#";
|
|
mainNavLink.addEventListener("click", function(e){
|
|
e.preventDefault();
|
|
onDirBrowserClick("%2F");
|
|
});
|
|
dirBrowserNav.appendChild(mainNavIcon);
|
|
dirBrowserNav.appendChild(mainNavLink);
|
|
|
|
let p = "/";
|
|
if (curDir && curDir != "%2F") {
|
|
p = decodeURIComponent(curDir.replace(/\+/g, '%20'));
|
|
const dirPaths = p.split("/");
|
|
let fullPath = "%2F";
|
|
for (idx in dirPaths) {
|
|
let dir = dirPaths[idx];
|
|
if (dir) {
|
|
if (fullPath.endsWith("%2F")){
|
|
fullPath += encodeURIComponent(dir);
|
|
} else {
|
|
fullPath += encodeURIComponent("/" + dir);
|
|
}
|
|
dir = escapeHTML(dir);
|
|
let navIcon = document.createElement("i");
|
|
navIcon.classList.add("ki-duotone", "ki-right", "fs-2x", "text-primary", "mx-1");
|
|
let navLink = document.createElement("a");
|
|
navLink.textContent = dir;
|
|
navLink.href = "#";
|
|
let pathCopy = fullPath
|
|
navLink.addEventListener("click", function(e){
|
|
e.preventDefault();
|
|
onDirBrowserClick(pathCopy);
|
|
});
|
|
dirBrowserNav.appendChild(navIcon);
|
|
dirBrowserNav.appendChild(navLink);
|
|
}
|
|
}
|
|
}
|
|
|
|
$('#move_copy_folder').val(p);
|
|
handleRowActions();
|
|
});
|
|
}
|
|
|
|
var handleCreateNewFolder = function() {
|
|
$('#dirsbrowser_add_folder').click(function(){
|
|
let errDivEl = $('#errorModalMsg');
|
|
let errTxtEl = $('#errorModalTxt');
|
|
let dirName = $("#dirsbrowser_new_folder_input").val();
|
|
let submitButton = document.querySelector('#dirsbrowser_add_folder');
|
|
let cancelButton = document.querySelector('#dirsbrowser_cancel_folder');
|
|
errDivEl.addClass("d-none");
|
|
if (!dirName){
|
|
setI18NData(errTxtEl, "fs.folder_name_required");
|
|
errDivEl.removeClass("d-none");
|
|
return;
|
|
}
|
|
if (dirName.includes("/")){
|
|
setI18NData(errTxtEl, "fs.invalid_name");
|
|
errDivEl.removeClass("d-none");
|
|
return;
|
|
}
|
|
let path = '{{.DirsURL}}?path='+ curDir + encodeURIComponent("/"+dirName);
|
|
submitButton.setAttribute('data-kt-indicator', 'on');
|
|
submitButton.disabled = true;
|
|
cancelButton.disabled = true;
|
|
|
|
axios.post(path, null, {
|
|
timeout: 15000,
|
|
headers: {
|
|
'X-CSRF-TOKEN': '{{.CSRFToken}}'
|
|
},
|
|
validateStatus: function (status) {
|
|
return status == 201;
|
|
}
|
|
}).then(function (response) {
|
|
dt.ajax.reload();
|
|
errDivEl.addClass("d-none");
|
|
submitButton.removeAttribute('data-kt-indicator');
|
|
submitButton.disabled = false;
|
|
cancelButton.disabled = false;
|
|
$('.dir_browser_folder_divider').addClass("d-none");
|
|
$('#dirsbrowser_new_folder').addClass("d-none");
|
|
}).catch(function (error) {
|
|
let errorMessage = "";
|
|
if (error && error.response) {
|
|
switch (error.response.status) {
|
|
case 403:
|
|
errorMessage = "fs.create_dir.err_403";
|
|
break;
|
|
case 429:
|
|
errorMessage = "fs.create_dir.err_429";
|
|
break;
|
|
}
|
|
}
|
|
if (!errorMessage){
|
|
errorMessage = "fs.create_dir.err_generic";
|
|
}
|
|
setI18NData(errTxtEl, errorMessage);
|
|
errDivEl.removeClass("d-none");
|
|
submitButton.removeAttribute('data-kt-indicator');
|
|
submitButton.disabled = false;
|
|
cancelButton.disabled = false;
|
|
});
|
|
});
|
|
}
|
|
|
|
function handleRowActions(){
|
|
const openLinks = document.querySelectorAll('[data-dirbrowser-table-row="open"]');
|
|
|
|
openLinks.forEach(d => {
|
|
let el = $(d);
|
|
el.off("click");
|
|
el.on("click", function(e){
|
|
e.preventDefault();
|
|
const parent = e.target.closest('tr');
|
|
onDirBrowserClick(dt.row(parent).data()['dir_path']);
|
|
});
|
|
});
|
|
}
|
|
|
|
return {
|
|
init: function (url, dirPath) {
|
|
curDir = dirPath;
|
|
if (dt) {
|
|
dt.ajax.url(url).load();
|
|
return;
|
|
}
|
|
initDatatable(url);
|
|
handleCreateNewFolder();
|
|
}
|
|
}
|
|
}();
|
|
//{{- end}}
|
|
</script>
|
|
|
|
<script type="text/javascript" {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}}>
|
|
var KTDatatablesServerSide = function () {
|
|
// Shared variables
|
|
var dt;
|
|
var lightbox;
|
|
|
|
|
|
// Private functions
|
|
var initDatatable = function () {
|
|
dt = $("#file_manager_list").DataTable({
|
|
ajax: {
|
|
url: "{{.DirsURL}}?path={{.CurrentDir}}",
|
|
dataSrc: "",
|
|
error: function ($xhr, textStatus, errorThrown) {
|
|
$(".dt-processing").hide();
|
|
$('#loader').addClass("d-none");
|
|
let txt = "";
|
|
if ($xhr) {
|
|
let json = $xhr.responseJSON;
|
|
if (json) {
|
|
if (json.message){
|
|
txt = json.message;
|
|
}
|
|
}
|
|
}
|
|
if (!txt){
|
|
txt = "fs.dir_list.err_generic";
|
|
}
|
|
setI18NData($('#errorTxt'), txt);
|
|
$('#errorMsg').removeClass("d-none");
|
|
}
|
|
},
|
|
deferRender: true,
|
|
processing: true,
|
|
lengthMenu: [ 10, 25, 50, 100, 250, 500 ],
|
|
select: {
|
|
style: 'multi',
|
|
selector: 'td:first-child input[type="checkbox"]',
|
|
className: 'row-selected'
|
|
},
|
|
stateSave: true,
|
|
stateDuration: 0,
|
|
stateSaveParams: function (settings, data) {
|
|
data.sftpgo_dir = '{{.CurrentDir}}';
|
|
},
|
|
stateLoadParams: function (settings, data) {
|
|
if (!data.sftpgo_dir || data.sftpgo_dir != '{{.CurrentDir}}'){
|
|
data.start = 0;
|
|
data.search.search = "";
|
|
}
|
|
if (data.search.search){
|
|
const filterSearch = document.querySelector('[data-kt-filemanager-table-filter="search"]');
|
|
filterSearch.value = data.search.search;
|
|
}
|
|
},
|
|
columns: [
|
|
{
|
|
data: "meta",
|
|
render: function (data, type) {
|
|
if (type == 'display'){
|
|
return `
|
|
<div class="form-check form-check-sm form-check-custom form-check-solid">
|
|
<input class="form-check-input" type="checkbox" />
|
|
</div>`;
|
|
}
|
|
return data;
|
|
}
|
|
},
|
|
{ data: "type" },
|
|
{
|
|
data: "name",
|
|
render: function (data, type, row) {
|
|
if (type === 'display') {
|
|
data = escapeHTML(data);
|
|
let icon_name = "ki-file";
|
|
|
|
if (row["type"] == "1") {
|
|
icon_name = "ki-folder";
|
|
} else if (row["size"] === "") {
|
|
icon_name = "ki-file-right"
|
|
}
|
|
|
|
return `<div class="d-flex align-items-center">
|
|
<i class="ki-duotone ${icon_name} fs-2x text-primary me-4">
|
|
<i class="path1"></i>
|
|
<i class="path2"></i>
|
|
</i>
|
|
<a href="${row['url']}" class="text-gray-800 text-hover-primary">${data}</a>
|
|
</div>`
|
|
}
|
|
return data;
|
|
}
|
|
},
|
|
{
|
|
data: "size",
|
|
render: function (data, type) {
|
|
if (type === 'display') {
|
|
if (data || data === 0){
|
|
return fileSizeIEC(data);
|
|
}
|
|
return "";
|
|
}
|
|
return data;
|
|
}
|
|
},
|
|
{
|
|
data: "last_modified",
|
|
render: function (data, type, row) {
|
|
if (type === 'display') {
|
|
if (data){
|
|
return $.t('general.datetime', {
|
|
val: new Date(data),
|
|
formatParams: {
|
|
val: { year: 'numeric', month: 'numeric', day: 'numeric', hour: 'numeric', minute: 'numeric' },
|
|
}
|
|
});
|
|
}
|
|
return ""
|
|
}
|
|
return data;
|
|
}
|
|
},
|
|
{
|
|
data: "edit_url",
|
|
className: 'text-end',
|
|
render: function (data, type, row) {
|
|
if (type === 'display') {
|
|
let previewDiv = "";
|
|
if (row["type"] == "2") {
|
|
let filename = escapeHTML(row["name"]);
|
|
let extension = filename.slice((filename.lastIndexOf(".") - 1 >>> 0) + 2).toLowerCase();
|
|
switch (extension) {
|
|
case "jpeg":
|
|
case "jpg":
|
|
case "png":
|
|
case "gif":
|
|
case "webp":
|
|
case "bmp":
|
|
case "svg":
|
|
let desc = escapeHTML(filename).replace(/"/g, '"');
|
|
previewDiv = `<div class="ms-2" data-kt-filemanger-table="view_item">
|
|
<a href="${row['url']}" data-gallery="gallery" data-glightbox="description: <span class="fs-5 fw-bold">${desc}</span>" class="btn btn-sm btn-icon btn-light btn-active-light-primary glightbox">
|
|
<i class="ki-duotone ki-eye fs-6 m-0">
|
|
<span class="path1"></span>
|
|
<span class="path2"></span>
|
|
<span class="path3"></span>
|
|
</i>
|
|
</a>
|
|
</div>`;
|
|
break;
|
|
case "mp4":
|
|
case "mov":
|
|
case "webm":
|
|
case "ogv":
|
|
case "ogg":
|
|
case "mp3":
|
|
case "wav":
|
|
previewDiv = `<div class="ms-2" data-kt-filemanger-table="view_item">
|
|
<a href="#" class="btn btn-sm btn-icon btn-light btn-active-light-primary" data-kt-filemanager-table-action="view_media">
|
|
<i class="ki-duotone ki-eye fs-6 m-0">
|
|
<span class="path1"></span>
|
|
<span class="path2"></span>
|
|
<span class="path3"></span>
|
|
</i>
|
|
</a>
|
|
</div>`;
|
|
break;
|
|
case "pdf":
|
|
if (PDFObject.supportsPDFs){
|
|
let view_url = row['url'];
|
|
view_url = view_url.replace('{{.FilesURL}}','{{.ViewPDFURL}}');
|
|
previewDiv = `<div class="ms-2" data-kt-filemanger-table="view_item">
|
|
<a href="${view_url}" target="_blank" rel="noopener noreferrer" class="btn btn-sm btn-icon btn-light btn-active-light-primary">
|
|
<i class="ki-duotone ki-eye fs-6 m-0">
|
|
<span class="path1"></span>
|
|
<span class="path2"></span>
|
|
<span class="path3"></span>
|
|
</i>
|
|
</a>
|
|
</div>`;
|
|
}
|
|
break;
|
|
default:
|
|
//{{- if not .ShareUploadBaseURL}}
|
|
if (data && (supportedEditExtensions.includes(extension) || supportedEditFilenames.includes(filename.toLowerCase()))){
|
|
previewDiv = `<div class="ms-2" data-kt-filemanger-table="view_item">
|
|
<a href="${data}" target="_blank" rel="noopener noreferrer" class="btn btn-sm btn-icon btn-light btn-active-light-primary">
|
|
<i class="ki-duotone ki-eye fs-6 m-0">
|
|
<span class="path1"></span>
|
|
<span class="path2"></span>
|
|
<span class="path3"></span>
|
|
</i>
|
|
</a>
|
|
</div>`;
|
|
}
|
|
//{{- end}}
|
|
}
|
|
}
|
|
let more = `{{- if not .ShareUploadBaseURL}}
|
|
{{- if or .CanRename .CanAddFiles .CanShare .CanDelete }}
|
|
<div class="ms-2">
|
|
<button type="button" class="btn btn-sm btn-icon btn-light btn-active-light-primary" data-kt-menu-trigger="click" data-kt-menu-placement="bottom-end">
|
|
<i class="ki-duotone ki-dots-square fs-5 m-0">
|
|
<span class="path1"></span>
|
|
<span class="path2"></span>
|
|
<span class="path3"></span>
|
|
<span class="path4"></span>
|
|
</i>
|
|
</button>
|
|
<div class="menu menu-sub menu-sub-dropdown menu-column menu-rounded menu-gray-700 menu-state-bg-light-primary fw-semibold fs-6 w-150px py-4" data-kt-menu="true">
|
|
{{- if .CanRename}}
|
|
<div class="menu-item px-3">
|
|
<a data-i18n="general.rename" href="#" class="menu-link px-3" data-kt-filemanager-table-action="rename">Rename</a>
|
|
</div>
|
|
{{- end}}
|
|
{{- if or .CanRename .CanCopy}}
|
|
<div class="menu-item px-3">
|
|
<a data-i18n="{{$move_copy_msg}}" href="#" class="menu-link px-3" data-kt-filemanager-table-action="move_or_copy">Move or copy</a>
|
|
</div>
|
|
{{- end}}
|
|
{{- if .CanShare}}
|
|
<div class="menu-item px-3">
|
|
<a data-i18n="fs.share" href="#" class="menu-link px-3" data-kt-filemanager-table-action="share">Share</a>
|
|
</div>
|
|
{{- end}}
|
|
{{- if .CanDelete}}
|
|
<div class="menu-item px-3">
|
|
<a data-i18n="general.delete" href="#" class="menu-link text-danger px-3" data-kt-filemanager-table-action="delete">Delete</a>
|
|
</div>
|
|
{{- end}}
|
|
</div>
|
|
</div>
|
|
{{- end}}
|
|
{{- end}}`;
|
|
return `<div class="d-flex justify-content-end">
|
|
${previewDiv}
|
|
${more}
|
|
</div>
|
|
`;
|
|
}
|
|
return "";
|
|
}
|
|
}
|
|
],
|
|
lengthChange: true,
|
|
columnDefs: [
|
|
{
|
|
targets: 0,
|
|
orderable: false,
|
|
searchable: false,
|
|
},
|
|
{
|
|
targets: 1,
|
|
visible: false,
|
|
searchable: false
|
|
},
|
|
{
|
|
targets: 2,
|
|
visible: true,
|
|
searchable: true
|
|
},
|
|
{
|
|
targets: [3,4],
|
|
searchable: false
|
|
},
|
|
{
|
|
targets: 5,
|
|
orderable: false,
|
|
searchable: false
|
|
}
|
|
],
|
|
language: {
|
|
info: $.t('datatable.info'),
|
|
infoEmpty: $.t('datatable.info_empty'),
|
|
infoFiltered: $.t('datatable.info_filtered'),
|
|
loadingRecords: "",
|
|
processing: $.t('datatable.processing'),
|
|
zeroRecords: "",
|
|
emptyTable: $.t('fs.no_files_folders')
|
|
},
|
|
orderFixed: [1, 'asc'],
|
|
order: [2, 'asc'],
|
|
initComplete: function(settings, json) {
|
|
$('#loader').addClass("d-none");
|
|
$('#file_manager_list_container').removeClass("d-none");
|
|
let api = $.fn.dataTable.Api(settings);
|
|
api.columns.adjust().draw("page");
|
|
drawAction();
|
|
}
|
|
});
|
|
|
|
dt.on('draw', drawAction);
|
|
|
|
function drawAction() {
|
|
//{{- if .CanAddFiles}}
|
|
if (dt.rows().count() === 0) {
|
|
$('#file_manager_list_container').addClass("d-none");
|
|
$('#upload_files_empty_container').removeClass("d-none");
|
|
return;
|
|
}
|
|
$('#upload_files_empty_container').addClass("d-none");
|
|
$('#file_manager_list_container').removeClass("d-none");
|
|
//{{- end}}
|
|
lightbox.reload();
|
|
KTMenu.createInstances();
|
|
|
|
let targets = document.querySelectorAll('#file_manager_list_body tr');
|
|
if (targets) {
|
|
KTUtil.each(targets, function (target) {
|
|
if (!target){
|
|
return;
|
|
}
|
|
let checkbox = target.querySelector('.form-check-input');
|
|
if (!checkbox) {
|
|
return;
|
|
}
|
|
if (target.classList.contains('row-selected')) {
|
|
checkbox.checked = true;
|
|
} else {
|
|
checkbox.checked = false;
|
|
}
|
|
});
|
|
}
|
|
toggleToolbars();
|
|
handleRowActions();
|
|
$('#file_manager_list_body').localize();
|
|
}
|
|
|
|
dt.on('user-select', function(e, dt, type, cell, originalEvent){
|
|
let pageSelected = dt.rows({ selected: true, page: 'current' }).count();
|
|
let totalSelected = dt.rows({ selected: true, search: 'applied' }).count();
|
|
if (totalSelected > pageSelected){
|
|
let currentIndexes = [];
|
|
dt.rows({ page: 'current' }).every(function (rowIdx, tableLoop, rowLoop){
|
|
currentIndexes.push(rowIdx);
|
|
});
|
|
|
|
dt.rows().deselect();
|
|
currentIndexes.forEach((idx) => {
|
|
dt.row(idx).select();
|
|
});
|
|
|
|
totalSelected = dt.rows({ selected: true, search: 'applied' }).count();
|
|
}
|
|
if ($(originalEvent.target).is(':checked')){
|
|
pageSelected++;
|
|
totalSelected++;
|
|
} else {
|
|
pageSelected--;
|
|
totalSelected--;
|
|
}
|
|
|
|
handleToogleToolbar(pageSelected, totalSelected);
|
|
});
|
|
}
|
|
|
|
function handleToogleToolbar(pageSelected, totalSelected) {
|
|
const navBar = document.querySelector('[data-kt-filemanager-table-nav-bar="base"]');
|
|
const toolbarSelected = document.querySelector('[data-kt-filemanager-table-toolbar="selected"]');
|
|
const selectedCount = document.querySelector('[data-kt-filemanager-table-select="selected_count"]');
|
|
const selectAllContainer = document.querySelector('[data-kt-filemanager-table-select="select_all_pages_container"]');
|
|
const selectAllCheck = document.querySelector('[data-kt-filemanager-table-select="select_all_pages"]');
|
|
|
|
if (pageSelected > 0) {
|
|
let pageTotal = dt.rows({ page: 'current' }).count();
|
|
if (pageSelected === pageTotal){
|
|
selectAllContainer.classList.remove("d-none");
|
|
$('#select_checkbox').prop("checked", true);
|
|
} else {
|
|
$('#select_checkbox').prop("checked", false);
|
|
selectAllCheck.checked = false;
|
|
selectAllContainer.classList.add('d-none');
|
|
}
|
|
if (selectedCount){
|
|
selectedCount.innerHTML = $.t('general.selected_items', { count: totalSelected});
|
|
}
|
|
if (navBar){
|
|
navBar.classList.add('d-none');
|
|
}
|
|
if (toolbarSelected){
|
|
toolbarSelected.classList.remove('d-none');
|
|
}
|
|
} else {
|
|
$('#select_checkbox').prop("checked", false);
|
|
selectAllCheck.checked = false;
|
|
if (navBar) {
|
|
navBar.classList.remove('d-none');
|
|
}
|
|
if (toolbarSelected) {
|
|
toolbarSelected.classList.add('d-none');
|
|
}
|
|
}
|
|
}
|
|
|
|
function handleRowActions() {
|
|
const renameButtons = document.querySelectorAll('[data-kt-filemanager-table-action="rename"]');
|
|
|
|
renameButtons.forEach(d => {
|
|
let el = $(d);
|
|
el.off("click");
|
|
el.on("click", function(e){
|
|
e.preventDefault();
|
|
const parent = e.target.closest('tr');
|
|
renameItem(dt.row(parent).data()["meta"]);
|
|
});
|
|
});
|
|
|
|
const moveCopyButtons = document.querySelectorAll('[data-kt-filemanager-table-action="move_or_copy"]');
|
|
|
|
moveCopyButtons.forEach(d => {
|
|
let el = $(d);
|
|
el.off("click");
|
|
el.on("click", function(e){
|
|
e.preventDefault();
|
|
const parent = e.target.closest('tr');
|
|
moveOrCopyItem(dt.row(parent).data()["meta"]);
|
|
});
|
|
});
|
|
|
|
const shareButtons = document.querySelectorAll('[data-kt-filemanager-table-action="share"]');
|
|
|
|
shareButtons.forEach(d => {
|
|
let el = $(d);
|
|
el.off("click");
|
|
el.on("click", function(e){
|
|
e.preventDefault();
|
|
const parent = e.target.closest('tr');
|
|
shareItem(dt.row(parent).data()["meta"]);
|
|
});
|
|
});
|
|
|
|
const deleteButtons = document.querySelectorAll('[data-kt-filemanager-table-action="delete"]');
|
|
|
|
deleteButtons.forEach(d => {
|
|
let el = $(d);
|
|
el.off("click");
|
|
el.on("click", function(e){
|
|
e.preventDefault();
|
|
const parent = e.target.closest('tr');
|
|
deleteItem(dt.row(parent).data()["meta"]);
|
|
});
|
|
});
|
|
|
|
const viewMediaLinks = document.querySelectorAll('[data-kt-filemanager-table-action="view_media"]');
|
|
|
|
viewMediaLinks.forEach(d => {
|
|
let el = $(d);
|
|
el.off("click");
|
|
el.on("click", function(e){
|
|
e.preventDefault();
|
|
const parent = e.target.closest('tr');
|
|
let rowData = dt.row(parent).data();
|
|
openMediaPlayer(rowData["name"], rowData["url"]);
|
|
});
|
|
});
|
|
}
|
|
|
|
var initLightbox = function() {
|
|
lightbox = GLightbox({
|
|
slideHTML: `<div class="gslide">
|
|
<div class="gslide-inner-content">
|
|
<div class="ginner-container">
|
|
<div class="gslide-media">
|
|
</div>
|
|
<div class="gslide-description gslide-description-bg">
|
|
<div class="gdesc-inner">
|
|
<h4 class="gslide-title"></h4>
|
|
<div class="gslide-desc"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>`,
|
|
preload: false,
|
|
closeOnOutsideClick: false
|
|
});
|
|
}
|
|
|
|
var handleSearchDatatable = function () {
|
|
const filterSearch = $(document.querySelector('[data-kt-filemanager-table-filter="search"]'));
|
|
filterSearch.off("keyup");
|
|
filterSearch.on('keyup', function (e) {
|
|
dt.rows().deselect();
|
|
dt.search(e.target.value).draw();
|
|
});
|
|
}
|
|
|
|
var initToggleToolbar = function () {
|
|
const selectAllCheck = document.querySelector('[data-kt-filemanager-table-select="select_all_pages"]');
|
|
if (selectAllCheck){
|
|
let el = $(selectAllCheck);
|
|
el.off("change");
|
|
el.on('change', function(e){
|
|
if (this.checked){
|
|
dt.rows({ search: 'applied' }).select();
|
|
} else {
|
|
let selectedIndexes = [];
|
|
dt.rows({ selected: true, page: 'current' }).every(function (rowIdx, tableLoop, rowLoop){
|
|
selectedIndexes.push(rowIdx);
|
|
});
|
|
dt.rows().deselect();
|
|
selectedIndexes.forEach((idx) => {
|
|
dt.row(idx).select();
|
|
});
|
|
}
|
|
toggleToolbars();
|
|
})
|
|
}
|
|
const downloadButton = document.querySelector('[data-kt-filemanager-table-select="download_selected"]');
|
|
if (downloadButton){
|
|
let el = $(downloadButton);
|
|
el.off("click");
|
|
el.on('click', function(e){
|
|
let filesArray = [];
|
|
dt.rows({ selected: true, search: 'applied' }).every(function (rowIdx, tableLoop, rowLoop){
|
|
let row = dt.row(rowIdx);
|
|
filesArray.push(getNameFromMeta(row.data()['meta']));
|
|
});
|
|
let token = "{{.CSRFToken}}";
|
|
let downloadURL = '{{.DownloadURL}}';
|
|
let currentDir = '{{.CurrentDir}}';
|
|
let ts = new Date().getTime().toString();
|
|
let files = JSON.stringify(filesArray);
|
|
$(`<form method="post" action="${downloadURL}?path=${currentDir}&_=${ts}" target="_blank" rel="noopener noreferrer">
|
|
<input type="hidden" name="_form_token" value="${token}">
|
|
<textarea name="files" hidden>${files}</textarea>
|
|
</form>`).appendTo('body').submit().remove();
|
|
});
|
|
}
|
|
|
|
const moveOrCopyButton = document.querySelector('[data-kt-filemanager-table-select="move_or_copy_selected"]');
|
|
if (moveOrCopyButton){
|
|
let el = $(moveOrCopyButton);
|
|
el.off("click");
|
|
el.on('click', function(e){
|
|
$('#errorMsg').addClass("d-none");
|
|
$('#move_copy_name_container').addClass("d-none");
|
|
$('#move_copy_source').val("");
|
|
$('#modal_move_or_copy').modal('show');
|
|
KTDatatablesFoldersExplorer.init('{{.DirsURL}}?dirtree=1&path={{.CurrentDir}}', '{{.CurrentDir}}');
|
|
});
|
|
}
|
|
|
|
const shareButton = document.querySelector('[data-kt-filemanager-table-select="share_selected"]');
|
|
if (shareButton){
|
|
let el = $(shareButton);
|
|
el.off("click");
|
|
el.on('click', function(e){
|
|
let filesArray = [];
|
|
dt.rows({ selected: true, search: 'applied' }).every(function (rowIdx, tableLoop, rowLoop){
|
|
let row = dt.row(rowIdx);
|
|
filesArray.push(getNameFromMeta(row.data()['meta']));
|
|
});
|
|
let files = encodeURIComponent(JSON.stringify(filesArray));
|
|
let shareURL = '{{.ShareURL}}';
|
|
let currentDir = '{{.CurrentDir}}';
|
|
let ts = new Date().getTime().toString();
|
|
window.open(`${shareURL}?path=${currentDir}&files=${files}&_=${ts}`,'_blank');
|
|
});
|
|
}
|
|
|
|
const deleteButton = document.querySelector('[data-kt-filemanager-table-select="delete_selected"]');
|
|
if (deleteButton) {
|
|
|
|
function getMultiDeleteErrorMessage(status, deleted) {
|
|
let errorMessage;
|
|
switch (status) {
|
|
case 403:
|
|
if (deleted > 0){
|
|
errorMessage = "fs.delete_multi.err_403_partial";
|
|
} else {
|
|
errorMessage = "fs.delete_multi.err_403";
|
|
}
|
|
break;
|
|
case 429:
|
|
if (deleted > 0){
|
|
errorMessage = "fs.delete_multi.err_429_partial";
|
|
} else {
|
|
errorMessage = "fs.delete_multi.err_429";
|
|
}
|
|
break;
|
|
}
|
|
if (!errorMessage){
|
|
if (deleted > 0){
|
|
errorMessage = "fs.delete_multi.err_generic_partial";
|
|
} else {
|
|
errorMessage = "fs.delete_multi.err_generic";
|
|
}
|
|
}
|
|
return errorMessage;
|
|
}
|
|
|
|
let el = $(deleteButton);
|
|
el.off("click");
|
|
el.on('click', function(e){
|
|
ModalAlert.fire({
|
|
text: $.t('general.delete_multi_confirm'),
|
|
icon: "warning",
|
|
confirmButtonText: $.t('general.delete_confirm_btn'),
|
|
cancelButtonText: $.t('general.cancel'),
|
|
customClass: {
|
|
confirmButton: "btn btn-danger",
|
|
cancelButton: 'btn btn-secondary'
|
|
}
|
|
}).then((result) => {
|
|
if (result.isConfirmed){
|
|
let hasError = false;
|
|
let deleted = 0;
|
|
let index = 0;
|
|
let errDivEl = $('#errorMsg');
|
|
let errTxtEl = $('#errorTxt');
|
|
errDivEl.addClass("d-none");
|
|
let selectedRowsIdx = [];
|
|
dt.rows({ selected: true, search: 'applied' }).every(function (rowIdx, tableLoop, rowLoop){
|
|
selectedRowsIdx.push(rowIdx);
|
|
});
|
|
if (selectedRowsIdx.length == 0){
|
|
return;
|
|
}
|
|
clearLoading();
|
|
KTApp.showPageLoading();
|
|
|
|
function deleteSelected() {
|
|
if (index >= selectedRowsIdx.length || hasError){
|
|
KTApp.hidePageLoading();
|
|
if (!hasError){
|
|
location.reload();
|
|
}
|
|
return;
|
|
}
|
|
let meta = dt.row(selectedRowsIdx[index]).data()['meta'];
|
|
let itemName = getNameFromMeta(meta);
|
|
let isDir = (getTypeFromMeta(meta) == "1");
|
|
let path;
|
|
if (isDir){
|
|
path = '{{.DirsURL}}';
|
|
} else {
|
|
path = '{{.FilesURL}}';
|
|
}
|
|
path+='?path={{.CurrentDir}}'+encodeURIComponent("/"+itemName);
|
|
|
|
if (selectedRowsIdx.length > 1){
|
|
let info = $.t('fs.deleting', {
|
|
idx : index + 1,
|
|
total: selectedRowsIdx.length
|
|
});
|
|
setLoadingText(info,itemName);
|
|
}
|
|
|
|
axios.delete(path,{
|
|
timeout: 15000,
|
|
headers: {
|
|
'X-CSRF-TOKEN': '{{.CSRFToken}}'
|
|
},
|
|
validateStatus: function (status) {
|
|
if (isDir){
|
|
return status == 202;
|
|
}
|
|
return status == 200;
|
|
}
|
|
}).then(function(response){
|
|
if (isDir){
|
|
taskStatusWaiter.wait({
|
|
taskID: response.data.message,
|
|
delay: 500
|
|
}).then((result) => {
|
|
index++;
|
|
if (result.status == 200){
|
|
deleted++;
|
|
} else {
|
|
hasError = true;
|
|
let errorMessage = getMultiDeleteErrorMessage(result.status, deleted);
|
|
setI18NData(errTxtEl, errorMessage);
|
|
errDivEl.removeClass("d-none");
|
|
}
|
|
deleteSelected();
|
|
});
|
|
} else {
|
|
index++;
|
|
deleted++;
|
|
deleteSelected();
|
|
}
|
|
}).catch(function(error){
|
|
index++;
|
|
hasError = true;
|
|
let status = 0;
|
|
if (error && error.response) {
|
|
status = error.response.status;
|
|
}
|
|
let errorMessage = getMultiDeleteErrorMessage(status, deleted);
|
|
setI18NData(errTxtEl, errorMessage);
|
|
errDivEl.removeClass("d-none");
|
|
deleteSelected();
|
|
});
|
|
}
|
|
|
|
deleteSelected();
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
$('#select_checkbox').on("click", function(){
|
|
let targets = document.querySelectorAll('#file_manager_list_body .form-check-input');
|
|
if (!targets){
|
|
return;
|
|
}
|
|
dt.rows().deselect();
|
|
let isChecked = $(this).is(':checked');
|
|
if (isChecked){
|
|
dt.rows({page: 'current'}).select();
|
|
}
|
|
KTUtil.each(targets, function (target) {
|
|
if (target){
|
|
target.checked = isChecked;
|
|
}
|
|
});
|
|
toggleToolbars();
|
|
});
|
|
|
|
toggleToolbars();
|
|
}
|
|
|
|
var toggleToolbars = function () {
|
|
let pageSelected = dt.rows({ selected: true, page: 'current' }).count();
|
|
let totalSelected = dt.rows({ selected: true , search: 'applied'}).count();
|
|
handleToogleToolbar(pageSelected, totalSelected);
|
|
}
|
|
|
|
return {
|
|
init: function () {
|
|
initLightbox();
|
|
initDatatable();
|
|
handleSearchDatatable();
|
|
initToggleToolbar();
|
|
}
|
|
}
|
|
}();
|
|
|
|
function getNameFromMeta(meta) {
|
|
return meta.split('_').slice(1).join('_');
|
|
}
|
|
|
|
function getTypeFromMeta(meta) {
|
|
return meta.split('_')[0];
|
|
}
|
|
|
|
//{{- if not .ShareUploadBaseURL}}
|
|
function onDirBrowserClick(dirPath) {
|
|
KTDatatablesFoldersExplorer.init('{{.DirsURL}}?dirtree=1&path='+dirPath, dirPath);
|
|
}
|
|
|
|
function moveOrCopyItem(meta) {
|
|
$('#errorMsg').addClass("d-none");
|
|
$('#move_copy_name_container').removeClass("d-none");
|
|
$('#move_copy_source').val(meta);
|
|
$('#move_copy_name').val(getNameFromMeta(meta));
|
|
$('#modal_move_or_copy').modal('show');
|
|
KTDatatablesFoldersExplorer.init('{{.DirsURL}}?dirtree=1&path={{.CurrentDir}}', '{{.CurrentDir}}');
|
|
}
|
|
|
|
function getMoveOrCopyItems() {
|
|
let items = [];
|
|
let targetDir = $("#move_copy_folder").val();
|
|
if (targetDir != "/") {
|
|
targetDir = targetDir.endsWith('/') ? targetDir.slice(0, -1) : targetDir;
|
|
}
|
|
if (targetDir.trim() == ""){
|
|
targetDir = "{{.CurrentDir}}";
|
|
} else {
|
|
targetDir = encodeURIComponent(targetDir);
|
|
}
|
|
|
|
if ($('#move_copy_name_container').hasClass("d-none")){
|
|
// bulk action
|
|
let dt = $('#file_manager_list').DataTable();
|
|
dt.rows({ selected: true, search: 'applied' }).every(function (rowIdx, tableLoop, rowLoop){
|
|
let row = dt.row(rowIdx);
|
|
let sourceName = getNameFromMeta(row.data()['meta']);
|
|
items.push({
|
|
targetDir: targetDir,
|
|
sourceName: sourceName,
|
|
targetName: sourceName
|
|
});
|
|
});
|
|
} else {
|
|
let meta = $('#move_copy_source').val();
|
|
let sourceName = getNameFromMeta(meta);
|
|
items.push({
|
|
targetDir: targetDir,
|
|
sourceName: sourceName,
|
|
targetName: $("#move_copy_name").val()
|
|
});
|
|
}
|
|
return items;
|
|
}
|
|
|
|
function checkMoveCopyItems(items) {
|
|
let hasSlash = items.some(item => item.targetName.includes("/"));
|
|
if (hasSlash){
|
|
return [];
|
|
}
|
|
return items;
|
|
}
|
|
|
|
function doCopy() {
|
|
$('#errorMsg').addClass("d-none");
|
|
let items = getMoveOrCopyItems();
|
|
if (items.length == 0){
|
|
return;
|
|
}
|
|
items = checkMoveCopyItems(items)
|
|
if (items.length == 0){
|
|
ModalAlert.fire({
|
|
text: $.t('fs.invalid_name'),
|
|
icon: "warning",
|
|
confirmButtonText: $.t('general.ok'),
|
|
customClass: {
|
|
confirmButton: "btn btn-primary"
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
|
|
function showCopyError(status) {
|
|
KTApp.hidePageLoading();
|
|
let errorMessage = "";
|
|
switch (status) {
|
|
case 403:
|
|
errorMessage = "fs.copy.err_403";
|
|
break;
|
|
case 429:
|
|
errorMessage = "fs.copy.err_429";
|
|
break;
|
|
default:
|
|
errorMessage = "fs.copy.err_generic";
|
|
}
|
|
ModalAlert.fire({
|
|
text: $.t(errorMessage),
|
|
icon: "warning",
|
|
confirmButtonText: $.t('general.ok'),
|
|
customClass: {
|
|
confirmButton: "btn btn-primary"
|
|
}
|
|
});
|
|
}
|
|
|
|
let hasError = false;
|
|
let index = 0;
|
|
|
|
clearLoading();
|
|
KTApp.showPageLoading();
|
|
|
|
function copyItem() {
|
|
if (index >= items.length || hasError){
|
|
KTApp.hidePageLoading();
|
|
if (!hasError){
|
|
location.reload();
|
|
}
|
|
return;
|
|
}
|
|
let item = items[index];
|
|
let sourcePath = decodeURIComponent('{{.CurrentDir}}');
|
|
if (!sourcePath.endsWith('/')){
|
|
sourcePath+="/";
|
|
}
|
|
sourcePath+=item.sourceName;
|
|
|
|
let targetPath = decodeURIComponent(item.targetDir);
|
|
if (!targetPath.endsWith('/')){
|
|
targetPath+="/";
|
|
}
|
|
targetPath+=item.targetName;
|
|
|
|
if (items.length > 1) {
|
|
let info = $.t('fs.copying', {
|
|
idx: index + 1,
|
|
total: items.length
|
|
});
|
|
setLoadingText(info,`${sourcePath} => ${targetPath}`);
|
|
}
|
|
let path = '{{.FileActionsURL}}/copy';
|
|
path+='?path={{.CurrentDir}}'+encodeURIComponent("/"+item.sourceName)+'&target='+item.targetDir+encodeURIComponent("/"+item.targetName);
|
|
|
|
axios.post(path, null, {
|
|
timeout: 15000,
|
|
headers: {
|
|
'X-CSRF-TOKEN': '{{.CSRFToken}}'
|
|
},
|
|
validateStatus: function (status) {
|
|
return status == 202;
|
|
}
|
|
}).then(function (response) {
|
|
taskStatusWaiter.wait({
|
|
taskID: response.data.message,
|
|
delay: 500
|
|
}).then((result) => {
|
|
index++;
|
|
if (result.status != 200){
|
|
hasError = true;
|
|
showCopyError(result.status);
|
|
}
|
|
copyItem();
|
|
});
|
|
}).catch(function (error) {
|
|
index++;
|
|
hasError = true;
|
|
let status = 0;
|
|
if (error && error.response) {
|
|
status = error.response.status;
|
|
}
|
|
showCopyError(status);
|
|
copyItem();
|
|
});
|
|
}
|
|
|
|
let filesArray = [];
|
|
for (let i = 0; i < items.length; i++){
|
|
filesArray.push(items[i].targetName);
|
|
}
|
|
|
|
CheckExist.fire({
|
|
operation: "copy",
|
|
files: filesArray,
|
|
path: items[0].targetDir
|
|
}).then((result)=>{
|
|
if (result.error) {
|
|
hasError = true;
|
|
ModalAlert.fire({
|
|
text: $.t("fs.copy.err_generic"),
|
|
icon: "warning",
|
|
confirmButtonText: $.t('general.ok'),
|
|
customClass: {
|
|
confirmButton: "btn btn-primary"
|
|
}
|
|
});
|
|
} else if (result.data.length > 0){
|
|
hasError = true;
|
|
ModalAlert.fire({
|
|
text: $.t("fs.copy.err_exists"),
|
|
icon: "warning",
|
|
confirmButtonText: $.t('general.ok'),
|
|
customClass: {
|
|
confirmButton: "btn btn-primary"
|
|
}
|
|
});
|
|
}
|
|
copyItem();
|
|
});
|
|
}
|
|
|
|
function doMove() {
|
|
$('#errorMsg').addClass("d-none");
|
|
let items = getMoveOrCopyItems();
|
|
if (items.length == 0){
|
|
return;
|
|
}
|
|
items = checkMoveCopyItems(items)
|
|
if (items.length == 0){
|
|
ModalAlert.fire({
|
|
text: $.t("fs.invalid_name"),
|
|
icon: "warning",
|
|
confirmButtonText: $.t('general.ok'),
|
|
customClass: {
|
|
confirmButton: "btn btn-primary"
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
|
|
function showMoveError(status) {
|
|
KTApp.hidePageLoading();
|
|
let errorMessage = "";
|
|
switch (status) {
|
|
case 400:
|
|
errorMessage = "fs.move.err_unsupported";
|
|
break;
|
|
case 403:
|
|
errorMessage = "fs.move.err_403";
|
|
break;
|
|
case 429:
|
|
errorMessage = "fs.move.err_429";
|
|
break;
|
|
default:
|
|
errorMessage = "fs.move.err_generic";
|
|
}
|
|
ModalAlert.fire({
|
|
text: $.t(errorMessage),
|
|
icon: "warning",
|
|
confirmButtonText: $.t('general.ok'),
|
|
customClass: {
|
|
confirmButton: "btn btn-primary"
|
|
}
|
|
});
|
|
}
|
|
|
|
let hasError = false;
|
|
let index = 0;
|
|
|
|
clearLoading();
|
|
KTApp.showPageLoading();
|
|
|
|
function moveItem() {
|
|
if (index >= items.length || hasError){
|
|
KTApp.hidePageLoading();
|
|
if (!hasError){
|
|
location.reload();
|
|
}
|
|
return;
|
|
}
|
|
let item = items[index];
|
|
let sourcePath = decodeURIComponent('{{.CurrentDir}}');
|
|
if (!sourcePath.endsWith('/')){
|
|
sourcePath+="/";
|
|
}
|
|
sourcePath+=item.sourceName;
|
|
|
|
let targetPath = decodeURIComponent(item.targetDir);
|
|
if (!targetPath.endsWith('/')){
|
|
targetPath+="/";
|
|
}
|
|
targetPath+=item.targetName;
|
|
|
|
if (items.length > 1) {
|
|
let info = $.t('fs.moving', {
|
|
idx: index + 1,
|
|
total: items.length
|
|
});
|
|
setLoadingText(info,`${sourcePath} => ${targetPath}`);
|
|
}
|
|
let path = '{{.FileActionsURL}}/move';
|
|
path+='?path={{.CurrentDir}}'+encodeURIComponent("/"+item.sourceName)+'&target='+item.targetDir+encodeURIComponent("/"+item.targetName);
|
|
|
|
axios.post(path, null, {
|
|
timeout: 15000,
|
|
headers: {
|
|
'X-CSRF-TOKEN': '{{.CSRFToken}}'
|
|
},
|
|
validateStatus: function (status) {
|
|
return status == 202;
|
|
}
|
|
}).then(function (response) {
|
|
taskStatusWaiter.wait({
|
|
taskID: response.data.message,
|
|
delay: 500
|
|
}).then((result) => {
|
|
index++;
|
|
if (result.status != 200){
|
|
hasError = true;
|
|
showMoveError(result.status);
|
|
}
|
|
moveItem();
|
|
});
|
|
}).catch(function (error) {
|
|
index++;
|
|
hasError = true;
|
|
let status = 0;
|
|
if (error && error.response) {
|
|
status = error.response.status;
|
|
}
|
|
showMoveError(status);
|
|
moveItem();
|
|
});
|
|
}
|
|
|
|
let filesArray = [];
|
|
for (let i = 0; i < items.length; i++){
|
|
filesArray.push(items[i].targetName);
|
|
}
|
|
|
|
CheckExist.fire({
|
|
operation: "move",
|
|
files: filesArray,
|
|
path: items[0].targetDir
|
|
}).then((result)=>{
|
|
if (result.error) {
|
|
hasError = true;
|
|
ModalAlert.fire({
|
|
text: $.t("fs.move.err_generic"),
|
|
icon: "warning",
|
|
confirmButtonText: $.t('general.ok'),
|
|
customClass: {
|
|
confirmButton: "btn btn-primary"
|
|
}
|
|
});
|
|
} else if (result.data.length > 0){
|
|
hasError = true;
|
|
ModalAlert.fire({
|
|
text: $.t("fs.move.err_exists"),
|
|
icon: "warning",
|
|
confirmButtonText: $.t('general.ok'),
|
|
customClass: {
|
|
confirmButton: "btn btn-primary"
|
|
}
|
|
});
|
|
}
|
|
moveItem();
|
|
});
|
|
}
|
|
|
|
function showDeleteItemError(status, itemName) {
|
|
KTApp.hidePageLoading();
|
|
let errorMessage;
|
|
switch (status) {
|
|
case 403:
|
|
errorMessage = "fs.delete.err_403";
|
|
break;
|
|
case 429:
|
|
errorMessage = "fs.delete.err_429";
|
|
break;
|
|
default:
|
|
errorMessage = "fs.delete.err_generic";
|
|
}
|
|
ModalAlert.fire({
|
|
text: $.t(errorMessage, {name: itemName}),
|
|
icon: "warning",
|
|
confirmButtonText: $.t('general.ok'),
|
|
customClass: {
|
|
confirmButton: "btn btn-primary"
|
|
}
|
|
});
|
|
}
|
|
|
|
function deleteItem(meta) {
|
|
$('#errorMsg').addClass("d-none");
|
|
let itemName = getNameFromMeta(meta);
|
|
|
|
ModalAlert.fire({
|
|
text: $.t('general.delete_confirm', {name: itemName}),
|
|
icon: "warning",
|
|
confirmButtonText: $.t('general.delete_confirm_btn'),
|
|
cancelButtonText: $.t('general.cancel'),
|
|
customClass: {
|
|
confirmButton: "btn btn-danger",
|
|
cancelButton: 'btn btn-secondary'
|
|
}
|
|
}).then((result) => {
|
|
if (result.isConfirmed){
|
|
clearLoading();
|
|
KTApp.showPageLoading();
|
|
let isDir = (getTypeFromMeta(meta) == "1");
|
|
let path;
|
|
if (isDir){
|
|
path = '{{.DirsURL}}';
|
|
} else {
|
|
path = '{{.FilesURL}}';
|
|
}
|
|
path+='?path={{.CurrentDir}}'+encodeURIComponent("/"+itemName);
|
|
|
|
axios.delete(path, {
|
|
timeout: 15000,
|
|
headers: {
|
|
'X-CSRF-TOKEN': '{{.CSRFToken}}'
|
|
},
|
|
validateStatus: function (status) {
|
|
if (isDir){
|
|
return status == 202;
|
|
}
|
|
return status == 200;
|
|
}
|
|
}).then(function(response){
|
|
if (isDir){
|
|
taskStatusWaiter.wait({
|
|
taskID: response.data.message,
|
|
delay: 500
|
|
}).then((result) => {
|
|
if (result.status == 200){
|
|
location.reload();
|
|
} else {
|
|
showDeleteItemError(result.status, itemName);
|
|
}
|
|
});
|
|
} else {
|
|
location.reload();
|
|
}
|
|
}).catch(function(error){
|
|
let status = 0;
|
|
if (error && error.response) {
|
|
status = error.response.status;
|
|
}
|
|
showDeleteItemError(status, itemName);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
function shareItem(meta) {
|
|
let filesArray = [];
|
|
filesArray.push(getNameFromMeta(meta));
|
|
let files = encodeURIComponent(JSON.stringify(filesArray));
|
|
let shareURL = '{{.ShareURL}}';
|
|
let currentDir = '{{.CurrentDir}}';
|
|
let ts = new Date().getTime().toString();
|
|
window.open(`${shareURL}?path=${currentDir}&files=${files}&_=${ts}`,'_blank');
|
|
}
|
|
|
|
function renameItem(meta) {
|
|
$('#errorMsg').addClass("d-none");
|
|
let oldName = getNameFromMeta(meta);
|
|
$('#rename_old_name').val(meta);
|
|
$('#rename_new_name').val(oldName);
|
|
$('#rename_title').text($.t('fs.rename.title', { name: oldName}));
|
|
$('#modal_rename').modal('show');
|
|
}
|
|
|
|
function showRenameItemError(status, oldName) {
|
|
KTApp.hidePageLoading();
|
|
let errorMessage;
|
|
switch (status) {
|
|
case 400:
|
|
errorMessage = "fs.rename.err_unsupported";
|
|
break;
|
|
case 403:
|
|
errorMessage = "fs.rename.err_403";
|
|
break;
|
|
case 429:
|
|
errorMessage = "fs.rename.err_429";
|
|
break;
|
|
default:
|
|
errorMessage = "fs.rename.err_generic";
|
|
}
|
|
|
|
ModalAlert.fire({
|
|
text: $.t(errorMessage, {name: oldName}),
|
|
icon: "warning",
|
|
confirmButtonText: $.t('general.ok'),
|
|
customClass: {
|
|
confirmButton: "btn btn-primary"
|
|
}
|
|
});
|
|
}
|
|
|
|
function doRename() {
|
|
let meta = $('#rename_old_name').val();
|
|
let oldName = getNameFromMeta(meta);
|
|
let newName = $('#rename_new_name').val();
|
|
if (!newName){
|
|
ModalAlert.fire({
|
|
text: $.t('general.name_required'),
|
|
icon: "warning",
|
|
confirmButtonText: $.t('general.ok'),
|
|
customClass: {
|
|
confirmButton: "btn btn-primary"
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
if (newName == oldName){
|
|
ModalAlert.fire({
|
|
text: $.t('general.name_different'),
|
|
icon: "warning",
|
|
confirmButtonText: $.t('general.ok'),
|
|
customClass: {
|
|
confirmButton: "btn btn-primary"
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
if (newName.includes("/")){
|
|
ModalAlert.fire({
|
|
text: $.t('fs.invalid_name'),
|
|
icon: "warning",
|
|
confirmButtonText: $.t('general.ok'),
|
|
customClass: {
|
|
confirmButton: "btn btn-primary"
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
|
|
clearLoading();
|
|
KTApp.showPageLoading();
|
|
|
|
function executeRename() {
|
|
let path = '{{.FileActionsURL}}/move';
|
|
path += '?path={{.CurrentDir}}' + encodeURIComponent("/" + oldName) + '&target={{.CurrentDir}}' + encodeURIComponent("/" + newName);
|
|
axios.post(path, null, {
|
|
timeout: 15000,
|
|
headers: {
|
|
'X-CSRF-TOKEN': '{{.CSRFToken}}'
|
|
},
|
|
validateStatus: function (status) {
|
|
return status == 202;
|
|
}
|
|
}).then(function (response) {
|
|
taskStatusWaiter.wait({
|
|
taskID: response.data.message,
|
|
delay: 500
|
|
}).then((result) => {
|
|
if (result.status == 200){
|
|
location.reload();
|
|
} else {
|
|
showRenameItemError(result.status, oldName);
|
|
}
|
|
});
|
|
}).catch(function (error) {
|
|
let status = 0;
|
|
if (error && error.response) {
|
|
status = error.response.status;
|
|
}
|
|
showRenameItemError(status, oldName);
|
|
});
|
|
}
|
|
|
|
CheckExist.fire({
|
|
operation: "move",
|
|
files: [newName],
|
|
path: '{{.CurrentDir}}'
|
|
}).then((result)=>{
|
|
if (result.error) {
|
|
KTApp.hidePageLoading();
|
|
ModalAlert.fire({
|
|
text: $.t('fs.rename.err_generic', { name: oldName }),
|
|
icon: "warning",
|
|
confirmButtonText: $.t('general.ok'),
|
|
customClass: {
|
|
confirmButton: "btn btn-primary"
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
if (result.data.length > 0){
|
|
KTApp.hidePageLoading();
|
|
ModalAlert.fire({
|
|
text: $.t('fs.rename.err_exists', { name: oldName }),
|
|
icon: "warning",
|
|
confirmButtonText: $.t('general.ok'),
|
|
customClass: {
|
|
confirmButton: "btn btn-primary"
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
executeRename();
|
|
});
|
|
}
|
|
|
|
function showCreateNewFolder(sender) {
|
|
if (sender == 0) {
|
|
$('.new_folder_divider').removeClass("d-none");
|
|
$('#file_manager_new_folder').removeClass("d-none");
|
|
$('#errorMsg').addClass("d-none");
|
|
let el = $('#file_manager_new_folder_input');
|
|
el.val("");
|
|
el.focus();
|
|
return;
|
|
}
|
|
$('.dir_browser_folder_divider').removeClass("d-none");
|
|
$('#dirsbrowser_new_folder').removeClass("d-none");
|
|
$('#errorModalMsg').addClass("d-none");
|
|
let el = $('#dirsbrowser_new_folder_input');
|
|
el.val("");
|
|
el.focus();
|
|
}
|
|
|
|
function hideCreateNewFolder(sender) {
|
|
if (sender == 0){
|
|
$('.new_folder_divider').addClass("d-none");
|
|
$('#file_manager_new_folder').addClass("d-none");
|
|
} else {
|
|
$('.dir_browser_folder_divider').addClass("d-none");
|
|
$('#dirsbrowser_new_folder').addClass("d-none");
|
|
}
|
|
}
|
|
|
|
function createNewFolder() {
|
|
let errDivEl = $('#errorMsg');
|
|
let errTxtEl = $('#errorTxt');
|
|
let dirName = $("#file_manager_new_folder_input").val();
|
|
let submitButton = document.querySelector('#file_manager_add_folder');
|
|
let cancelButton = document.querySelector('#file_manager_cancel_folder');
|
|
errDivEl.addClass("d-none");
|
|
if (!dirName){
|
|
setI18NData(errTxtEl, "fs.folder_name_required");
|
|
errDivEl.removeClass("d-none");
|
|
return;
|
|
}
|
|
if (dirName.includes("/")){
|
|
setI18NData(errTxtEl, "fs.invalid_name");
|
|
errDivEl.removeClass("d-none");
|
|
return;
|
|
}
|
|
|
|
let path = '{{.DirsURL}}?path={{.CurrentDir}}' + encodeURIComponent("/"+dirName);
|
|
submitButton.setAttribute('data-kt-indicator', 'on');
|
|
submitButton.disabled = true;
|
|
cancelButton.disabled = true;
|
|
|
|
axios.post(path, null, {
|
|
timeout: 15000,
|
|
headers: {
|
|
'X-CSRF-TOKEN': '{{.CSRFToken}}'
|
|
},
|
|
validateStatus: function (status) {
|
|
return status == 201;
|
|
}
|
|
}).then(function (response) {
|
|
location.reload();
|
|
}).catch(function (error) {
|
|
let errorMessage = "";
|
|
if (error && error.response) {
|
|
switch (error.response.status) {
|
|
case 403:
|
|
errorMessage = "fs.create_dir.err_403";
|
|
break;
|
|
case 429:
|
|
errorMessage = "fs.create_dir.err_429";
|
|
break;
|
|
}
|
|
}
|
|
if (!errorMessage){
|
|
errorMessage = "fs.create_dir.err_generic";
|
|
}
|
|
setI18NData(errTxtEl, errorMessage);
|
|
errDivEl.removeClass("d-none");
|
|
submitButton.removeAttribute('data-kt-indicator');
|
|
submitButton.disabled = false;
|
|
cancelButton.disabled = false;
|
|
});
|
|
}
|
|
//{{- end}}
|
|
|
|
var playerKeepAlive;
|
|
|
|
function uploadFiles(files) {
|
|
keepAlive();
|
|
let keepAliveTimer = setInterval(keepAlive, 300000);
|
|
|
|
let has_errors = false;
|
|
let index = 0;
|
|
let success = 0;
|
|
let checkedDirs = [];
|
|
$('#errorMsg').addClass("d-none");
|
|
clearLoading();
|
|
KTApp.showPageLoading();
|
|
|
|
function uploadFile() {
|
|
if (index >= files.length || has_errors) {
|
|
//console.log("upload done, index: "+index+" has errors: "+has_errors+" ok: "+success);
|
|
clearInterval(keepAliveTimer);
|
|
KTApp.hidePageLoading();
|
|
if (!has_errors) {
|
|
location.reload();
|
|
}
|
|
return;
|
|
}
|
|
|
|
let f = files[index];
|
|
let uploadPath;
|
|
let name = f.name;
|
|
let mkdirParents = "false";
|
|
if (f.fullPath){
|
|
name = f.fullPath;
|
|
let dirName = name.substr(0, name.lastIndexOf("/"));
|
|
if (!checkedDirs.includes(dirName)){
|
|
mkdirParents = "true";
|
|
checkedDirs.push(dirName);
|
|
}
|
|
}
|
|
//{{- if .ShareUploadBaseURL}}
|
|
uploadPath = '{{.ShareUploadBaseURL}}' + encodeURIComponent("/" + name)+"?mkdir_parents="+mkdirParents;
|
|
//{{- else}}
|
|
uploadPath = '{{.FileURL}}?path={{.CurrentDir}}' + encodeURIComponent("/" + name)+"&mkdir_parents="+mkdirParents;
|
|
//{{- end}}
|
|
let lastModified;
|
|
try {
|
|
lastModified = f.lastModified;
|
|
} catch (e) {
|
|
console.error("unable to get last modified time from file: " + e.message);
|
|
lastModified = "";
|
|
}
|
|
|
|
let info = "";
|
|
if (files.length > 1){
|
|
info = $.t('fs.uploading', {
|
|
idx: index + 1,
|
|
total: files.length
|
|
});
|
|
}
|
|
|
|
setLoadingText(info,f.name);
|
|
|
|
axios.post(uploadPath, f, {
|
|
headers: {
|
|
'X-SFTPGO-MTIME': lastModified,
|
|
'X-CSRF-TOKEN': '{{.CSRFToken}}'
|
|
},
|
|
onUploadProgress: function (progressEvent) {
|
|
if (!progressEvent.total){
|
|
return;
|
|
}
|
|
const percentage = Math.round((100 * progressEvent.loaded) / progressEvent.total);
|
|
if (percentage > 0 && percentage < 100){
|
|
setLoadingText(info,`${f.name} ${percentage}%`);
|
|
}
|
|
},
|
|
validateStatus: function (status) {
|
|
return status == 201;
|
|
}
|
|
}).then(function (response) {
|
|
index++;
|
|
success++;
|
|
uploadFile();
|
|
}).catch(function (error) {
|
|
let errorMessage;
|
|
if (error && error.response) {
|
|
switch (error.response.status) {
|
|
case 403:
|
|
errorMessage = "fs.upload.err_403";
|
|
break;
|
|
case 429:
|
|
errorMessage = "fs.upload.err_429";
|
|
break;
|
|
}
|
|
}
|
|
if (!errorMessage){
|
|
errorMessage = "fs.upload.err_generic";
|
|
}
|
|
index++;
|
|
has_errors = true;
|
|
setI18NData($('#errorTxt'), errorMessage);
|
|
$('#errorMsg').removeClass("d-none");
|
|
uploadFile();
|
|
});
|
|
}
|
|
|
|
let filesArray = [];
|
|
let dirsArray = [];
|
|
if (files.length > 0){
|
|
for (let i = 0; i < files.length; i++){
|
|
if (files[i].fullPath){
|
|
let dirName = files[i].fullPath.split('/')[0];
|
|
if (!dirsArray.includes(dirName)){
|
|
dirsArray.push(dirName);
|
|
}
|
|
if (!filesArray.includes(dirName)){
|
|
filesArray.push(dirName);
|
|
}
|
|
} else {
|
|
filesArray.push(files[i].name);
|
|
}
|
|
}
|
|
}
|
|
|
|
CheckExist.fire({
|
|
operation: "upload",
|
|
files: filesArray,
|
|
path: "{{.CurrentDir}}"
|
|
}).then((result)=> {
|
|
if (result.error) {
|
|
has_errors = true;
|
|
setI18NData($('#errorTxt'), "fs.upload.err_generic");
|
|
$('#errorMsg').removeClass("d-none");
|
|
uploadFile();
|
|
return;
|
|
}
|
|
let existingEntries = [];
|
|
let fileOverwriteDirs = [];
|
|
$.each(result.data, function (key, item) {
|
|
if (item.type === "1" && !dirsArray.includes(item.name)) {
|
|
fileOverwriteDirs.push(item.name);
|
|
} else {
|
|
existingEntries.push(item.name);
|
|
}
|
|
});
|
|
if (fileOverwriteDirs.length > 0) {
|
|
has_errors = true;
|
|
setI18NData($('#errorTxt'), "fs.upload.err_dir_overwrite", {val: fileOverwriteDirs.join(", ")});
|
|
$('#errorMsg').removeClass("d-none");
|
|
uploadFile();
|
|
return;
|
|
}
|
|
if (existingEntries.length > 0) {
|
|
KTApp.hidePageLoading();
|
|
ModalAlert.fire({
|
|
text: $.t('fs.upload.overwrite_text'),
|
|
items: existingEntries,
|
|
icon: "warning",
|
|
confirmButtonText: $.t('general.confirm'),
|
|
cancelButtonText: $.t('general.cancel'),
|
|
customClass: {
|
|
confirmButton: "btn btn-danger",
|
|
cancelButton: 'btn btn-secondary'
|
|
}
|
|
}).then((result) => {
|
|
if (result.isConfirmed){
|
|
KTApp.showPageLoading();
|
|
} else {
|
|
has_errors = true;
|
|
}
|
|
uploadFile();
|
|
});
|
|
return;
|
|
}
|
|
uploadFile();
|
|
});
|
|
}
|
|
|
|
var CheckExist = function () {
|
|
var promiseResolve;
|
|
|
|
function doCheck(operation, files, target) {
|
|
let path = '{{.CheckExistURL}}?op='+encodeURIComponent(operation)+"&path="+target;
|
|
axios.post(path, {
|
|
files: files
|
|
}, {
|
|
headers: {
|
|
timeout: 15000,
|
|
'X-CSRF-TOKEN': '{{.CSRFToken}}'
|
|
},
|
|
validateStatus: function (status) {
|
|
return status == 200;
|
|
}
|
|
}).then(function(response){
|
|
promiseResolve({
|
|
error: false,
|
|
data: response.data
|
|
});
|
|
}).catch(function(error){
|
|
promiseResolve({
|
|
error: true
|
|
});
|
|
});
|
|
}
|
|
|
|
return {
|
|
fire: function (params) {
|
|
return new Promise(function (resolve, reject) {
|
|
promiseResolve = resolve;
|
|
doCheck(params.operation, params.files, params.path);
|
|
});
|
|
}
|
|
}
|
|
}();
|
|
|
|
function openMediaPlayer(name, url){
|
|
$("#video_title").text(name);
|
|
$("#video_player").attr("src", url);
|
|
$("#video_player").get(0).load();
|
|
$('#modal_video_player').modal('show');
|
|
keepAlive();
|
|
playerKeepAlive = setInterval(keepAlive, 300000);
|
|
}
|
|
|
|
$(document).on("i18nshow", function(){
|
|
KTDatatablesServerSide.init();
|
|
|
|
var lastAddedFile = Date.now();
|
|
|
|
function canUpload() {
|
|
// Ugly hack to detect if we are still loading a large file list when the user try to upload files.
|
|
// The Dropzone addedfiles event is fired for directories before the files within them are added to the queue.
|
|
// TODO: investigate if there is a better way.
|
|
if (Date.now() - lastAddedFile < 500) {
|
|
ModalAlert.fire({
|
|
text: $.t('fs.upload_queue_not_ready'),
|
|
icon: "warning",
|
|
confirmButtonText: $.t('general.ok'),
|
|
customClass: {
|
|
confirmButton: "btn btn-primary"
|
|
}
|
|
});
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
var dropzone = new Dropzone("#upload_files", {
|
|
url: "{{.FilesURL}}?path={{.CurrentDir}}",
|
|
paramName: "filenames",
|
|
createImageThumbnails: false,
|
|
maxFiles: null,
|
|
maxFilesize: null,
|
|
autoQueue: false,
|
|
addRemoveLinks: false,
|
|
autoProcessQueue: false,
|
|
filesizeBase: 1000,
|
|
previewTemplate: dzPreviewTemplate,
|
|
init: function() {
|
|
var dropzone = this;
|
|
$("#upload_files_button").click(function(){
|
|
if (canUpload()){
|
|
uploadFiles(dropzone.getAcceptedFiles());
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
dropzone.on("addedfile", file => {
|
|
for (node of file.previewElement.querySelectorAll("[data-custom-size]")) {
|
|
node.textContent = fileSizeIEC(file.size);
|
|
}
|
|
if (file.fullPath){
|
|
for (var node of file.previewElement.querySelectorAll("[data-dz-name]")) {
|
|
node.textContent = file.fullPath;
|
|
}
|
|
}
|
|
lastAddedFile = Date.now();
|
|
});
|
|
|
|
var dropzoneEmpty = new Dropzone("#upload_files_empty", {
|
|
url: "{{.FilesURL}}?path={{.CurrentDir}}",
|
|
paramName: "filenames",
|
|
createImageThumbnails: false,
|
|
maxFiles: null,
|
|
maxFilesize: null,
|
|
autoQueue: false,
|
|
addRemoveLinks: false,
|
|
autoProcessQueue: false,
|
|
filesizeBase: 1000,
|
|
previewTemplate: dzPreviewTemplate,
|
|
init: function() {
|
|
var dropzoneEmpty = this;
|
|
$("#upload_files_empty_button").click(function(){
|
|
if (canUpload()){
|
|
uploadFiles(dropzoneEmpty.getAcceptedFiles());
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
dropzoneEmpty.on("addedfile", file => {
|
|
for (node of file.previewElement.querySelectorAll("[data-custom-size]")) {
|
|
node.textContent = fileSizeIEC(file.size);
|
|
}
|
|
if (file.fullPath){
|
|
for (var node of file.previewElement.querySelectorAll("[data-dz-name]")) {
|
|
node.textContent = file.fullPath;
|
|
}
|
|
}
|
|
lastAddedFile = Date.now();
|
|
});
|
|
|
|
$('#modal_video_player').on('hide.bs.modal', function () {
|
|
$("#video_player").get(0).pause();
|
|
if (playerKeepAlive != null) {
|
|
clearInterval(playerKeepAlive);
|
|
playerKeepAlive = null;
|
|
}
|
|
});
|
|
|
|
//{{- if not .ShareUploadBaseURL}}
|
|
$('#modal_rename').on('shown.bs.modal', function () {
|
|
let newNameEl = $('#rename_new_name');
|
|
newNameEl.focus();
|
|
newNameEl.select();
|
|
});
|
|
//{{- end}}
|
|
|
|
// onclick handlers
|
|
var createDirBtn = $('#id_create_dir_button');
|
|
if (createDirBtn){
|
|
createDirBtn.on("click", function (){
|
|
showCreateNewFolder(0);
|
|
});
|
|
}
|
|
|
|
var dirBrowserCreateDir = $('#id_dir_browser_create_dir');
|
|
if (dirBrowserCreateDir){
|
|
dirBrowserCreateDir.on("click", function(){
|
|
showCreateNewFolder(1);
|
|
});
|
|
}
|
|
|
|
var fileManagerAddFolder = $('#file_manager_add_folder');
|
|
if (fileManagerAddFolder){
|
|
fileManagerAddFolder.on("click", function() {
|
|
createNewFolder();
|
|
});
|
|
}
|
|
|
|
var fileManagerCancelCreateFolder = $('#file_manager_cancel_folder');
|
|
if (fileManagerCancelCreateFolder){
|
|
fileManagerCancelCreateFolder.on("click", function(){
|
|
hideCreateNewFolder(0);
|
|
})
|
|
}
|
|
|
|
var dirBrowserCancelCreateFolder = $('#dirsbrowser_cancel_folder');
|
|
if (dirBrowserCancelCreateFolder){
|
|
dirBrowserCancelCreateFolder.on("click", function(){
|
|
hideCreateNewFolder(1);
|
|
});
|
|
}
|
|
|
|
var doRenameBtn = $('#id_do_rename_button');
|
|
if (doRenameBtn){
|
|
doRenameBtn.on("click", function() {
|
|
doRename();
|
|
});
|
|
}
|
|
|
|
var doCopyBtn = $('#id_copy_button');
|
|
if (doCopyBtn){
|
|
doCopyBtn.on("click", function(){
|
|
doCopy();
|
|
});
|
|
}
|
|
|
|
var doMoveBtn = $('#id_move_button');
|
|
if (doMoveBtn){
|
|
doMoveBtn.on("click", function(){
|
|
doMove();
|
|
});
|
|
}
|
|
|
|
var dismissErrorModalBtn = $('#id_dismiss_error_modal_msg');
|
|
if (dismissErrorModalBtn){
|
|
dismissErrorModalBtn.on("click",function(){
|
|
$('#errorModalMsg').addClass("d-none");
|
|
});
|
|
}
|
|
|
|
});
|
|
</script>
|
|
{{- end}}
|
|
|
|
{{- define "additionalnavitems"}}
|
|
{{- if .QuotaUsage.HasQuotaInfo}}
|
|
<div class="d-flex align-items-center ms-2 ms-lg-3">
|
|
<div class="btn btn-icon btn-active-light-primary position-relative w-35px h-35px w-md-40px h-md-40px" data-kt-menu-trigger="{default:'click', lg: 'hover'}" data-kt-menu-attach="parent" data-kt-menu-placement="bottom-end">
|
|
<i class="ki-duotone {{if .QuotaUsage.IsQuotaLow}}ki-information-5 text-warning{{else}}ki-information-2{{end}} fs-2">
|
|
<span class="path1"></span>
|
|
<span class="path2"></span>
|
|
<span class="path3"></span>
|
|
</i>
|
|
</div>
|
|
<div class="menu menu-sub menu-sub-dropdown menu-column w-375px" data-kt-menu="true">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h3 class="card-title"><span data-i18n="fs.quota_usage.title" class="text-gray-700 fw-bold fs-6">Quota usage</span></h3>
|
|
</div>
|
|
<div class="card-body p-0">
|
|
{{- if .QuotaUsage.HasDiskQuota}}
|
|
{{- $size := .QuotaUsage.GetQuotaSize}}
|
|
{{- $files := .QuotaUsage.GetQuotaFiles}}
|
|
<div class="d-flex align-items-center bg-hover-lighten py-3 px-9">
|
|
<div class="symbol symbol-40px symbol-circle me-5">
|
|
<span class="symbol-label {{ if .QuotaUsage.IsDiskQuotaLow }}bg-light-warning{{end}}">
|
|
<i class="ki-duotone ki-external-drive {{ if .QuotaUsage.IsDiskQuotaLow }}text-warning{{end}} fs-1">
|
|
<span class="path1"></span>
|
|
<span class="path2"></span>
|
|
<span class="path3"></span>
|
|
<span class="path4"></span>
|
|
<span class="path5"></span>
|
|
</i>
|
|
</span>
|
|
</div>
|
|
<div class="mb-1 pe-3 flex-grow-1">
|
|
<span data-i18n="fs.quota_usage.disk" class="fs-6 text-gray-900 fw-semibold">Disk quota</span>
|
|
{{- if $size}}
|
|
{{- $percentage := .QuotaUsage.GetQuotaSizePercentage}}
|
|
<div class="{{if .QuotaUsage.IsQuotaSizeLow}}text-warning{{else}}text-gray-700{{end}} fw-semibold fs-6">
|
|
<span {{if gt $percentage 0}}data-i18n="fs.quota_usage.size_percentage" data-i18n-options='{ "val": "{{$size}}", "percentage": {{$percentage}} }'{{else}}data-i18n="fs.quota_usage.size" data-i18n-options='{ "val": "{{$size}}" }'{{end}}></span>
|
|
</div>
|
|
{{- end}}
|
|
{{- if $files}}
|
|
{{- $percentage := .QuotaUsage.GetQuotaFilesPercentage}}
|
|
<div class="{{if .QuotaUsage.IsQuotaFilesLow}}text-warning{{else}}text-gray-700{{end}} fw-semibold fs-6">
|
|
<span {{if gt $percentage 0}}data-i18n="fs.quota_usage.files_percentage" data-i18n-options='{ "val": "{{$files}}", "percentage": {{$percentage}} }'{{else}}data-i18n="fs.quota_usage.files" data-i18n-options='{ "val": "{{$files}}" }'{{end}}></span>
|
|
</div>
|
|
{{- end}}
|
|
</div>
|
|
</div>
|
|
{{- end}}
|
|
{{- if .QuotaUsage.HasTranferQuota}}
|
|
{{- $total := .QuotaUsage.GetTotalTransferQuota}}
|
|
{{- $upload := .QuotaUsage.GetUploadTransferQuota}}
|
|
{{- $download := .QuotaUsage.GetDownloadTransferQuota}}
|
|
<div class="d-flex align-items-center bg-hover-lighten py-3 px-9">
|
|
<div class="symbol symbol-40px symbol-circle me-5">
|
|
<span class="symbol-label {{ if .QuotaUsage.IsTransferQuotaLow }}bg-light-warning{{end}}">
|
|
<i class="ki-duotone ki-arrow-right-left {{ if .QuotaUsage.IsTransferQuotaLow }}text-warning{{end}} fs-1">
|
|
<span class="path1"></span>
|
|
<span class="path2"></span>
|
|
</i>
|
|
</span>
|
|
</div>
|
|
<div class="mb-1 pe-3 flex-grow-1">
|
|
<span data-i18n="fs.quota_usage.transfer" class="fs-6 text-gray-900 fw-semibold">Transfer quota</span>
|
|
{{- if $total}}
|
|
{{$percentage := .QuotaUsage.GetTotalTransferQuotaPercentage}}
|
|
<div class="{{if .QuotaUsage.IsTotalTransferQuotaLow}}text-warning{{else}}text-gray-700{{end}} fw-semibold fs-6">
|
|
<span {{if gt $percentage 0}}data-i18n="fs.quota_usage.total_percentage" data-i18n-options='{ "val": "{{$total}}", "percentage": {{$percentage}} }'{{else}}data-i18n="fs.quota_usage.total" data-i18n-options='{ "val": "{{$total}}" }'{{end}}>
|
|
</span>
|
|
</div>
|
|
{{- end}}
|
|
{{- if $download}}
|
|
{{$percentage := .QuotaUsage.GetDownloadTransferQuotaPercentage}}
|
|
<div class="{{if .QuotaUsage.IsDownloadTransferQuotaLow}}text-warning{{else}}text-gray-700{{end}} fw-semibold fs-6">
|
|
<span {{if gt $percentage 0}}data-i18n="fs.quota_usage.downloads_percentage" data-i18n-options='{ "val": "{{$download}}", "percentage": {{$percentage}} }'{{else}}data-i18n="fs.quota_usage.downloads" data-i18n-options='{ "val": "{{$download}}" }'{{end}}>
|
|
</span>
|
|
</div>
|
|
{{- end}}
|
|
{{- if $upload}}
|
|
{{$percentage := .QuotaUsage.GetUploadTransferQuotaPercentage}}
|
|
<div class="{{if .QuotaUsage.IsUploadTransferQuotaLow}}text-warning{{else}}text-gray-700{{end}} fw-semibold fs-6">
|
|
<span {{if gt $percentage 0}}data-i18n="fs.quota_usage.uploads_percentage" data-i18n-options='{ "val": "{{$upload}}", "percentage": {{$percentage}} }'{{else}}data-i18n="fs.quota_usage.uploads" data-i18n-options='{ "val": "{{$upload}}" }'{{end}}>
|
|
</span>
|
|
</div>
|
|
{{- end}}
|
|
</div>
|
|
</div>
|
|
{{- end}}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{{- end}}
|
|
{{- end}}
|
|
|
|
{{- define "modals"}}
|
|
<div class="modal fade" tabindex="-1" id="modal_upload">
|
|
<div class="modal-dialog modal-dialog-centered mw-600px">
|
|
<div class="modal-content">
|
|
<div class="modal-header border-0">
|
|
<h3 data-i18n="fs.upload.text" class="modal-title">Upload files</h3>
|
|
<div data-i18n="[aria-label]general.close" class="btn btn-icon btn-sm btn-active-light-primary" data-bs-dismiss="modal" aria-label="Close">
|
|
<i class="ki-solid ki-cross fs-2x text-gray-700"></i>
|
|
</div>
|
|
</div>
|
|
<div class="modal-body">
|
|
<form id="upload_files_form" action="{{.FilesURL}}?path={{.CurrentDir}}" method="POST" enctype="multipart/form-data">
|
|
<div class="fv-row">
|
|
<div class="dropzone mh-350px overflow-auto visibility-auto" id="upload_files">
|
|
<div class="dz-message needsclick align-items-center">
|
|
<i class="ki-duotone ki-file-up fs-3x text-primary"><span class="path1"></span><span class="path2"></span></i>
|
|
<div class="ms-4">
|
|
<h3 data-i18n="fs.upload.message" class="fs-5 fw-bold text-gray-900 mb-1">Drop files here or click to upload.</h3>
|
|
<!-- <span class="fs-7 fw-semibold text-gray-500">Upload up to 30 files</span> -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<div class="modal-footer border-0">
|
|
<button data-i18n="general.cancel" type="button" class="btn btn-light me-5" data-bs-dismiss="modal">Cancel</button>
|
|
<button data-i18n="general.submit" type="button" id="upload_files_button" class="btn btn-primary" data-bs-dismiss="modal">Submit</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="modal fade" tabindex="-1" id="modal_video_player" data-bs-backdrop="static" data-bs-keyboard="false">
|
|
<div class="modal-dialog modal-dialog-centered modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header border-0">
|
|
<h5 class="modal-title">
|
|
<span id="video_title"></span>
|
|
</h5>
|
|
<div data-i18n="[aria-label]general.close" class="btn btn-icon btn-sm btn-active-light-primary" data-bs-dismiss="modal" aria-label="Close">
|
|
<i class="ki-solid ki-cross fs-2x text-gray-700"></i>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="modal-body">
|
|
<video id="video_player" width="100%" height="auto" controls preload="metadata">
|
|
<span data-i18n="general.html5_media_not_supported"></span>
|
|
</video>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{- if not .ShareUploadBaseURL}}
|
|
<div class="modal fade" tabindex="-1" id="modal_rename">
|
|
<div class="modal-dialog modal-dialog-centered">
|
|
<div class="modal-content">
|
|
<div class="modal-header border-0">
|
|
<h5 class="modal-title">
|
|
<span id="rename_title"></span>
|
|
</h5>
|
|
<div data-i18n="[aria-label]general.close" class="btn btn-icon btn-sm btn-active-light-primary" data-bs-dismiss="modal" aria-label="Close">
|
|
<i class="ki-solid ki-cross fs-2x text-gray-700"></i>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="modal-body">
|
|
<input id="rename_old_name" type="text" class="d-none"/>
|
|
<div class="mb-10">
|
|
<label data-i18n="fs.rename.new_name" for="rename_new_name" class="form-label"></label>
|
|
<input id="rename_new_name" type="text" class="form-control"/>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="modal-footer border-0">
|
|
<button data-i18n="general.cancel" type="button" class="btn btn-secondary me-5" data-bs-dismiss="modal">Cancel</button>
|
|
<button data-i18n="general.confirm" id="id_do_rename_button" type="button" class="btn btn-primary" data-bs-dismiss="modal">Submit</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="modal fade" tabindex="-1" id="modal_move_or_copy">
|
|
<div class="modal-dialog modal-dialog-centered modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header border-0">
|
|
<h3 data-i18n="general.choose_target_folder" class="modal-title">
|
|
Choose target folder
|
|
</h3>
|
|
<div data-i18n="[aria-label]general.close" class="btn btn-icon btn-sm btn-active-light-primary" data-bs-dismiss="modal" aria-label="Close">
|
|
<i class="ki-solid ki-cross fs-2x text-gray-700"></i>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="modal-body">
|
|
<div id="errorModalMsg" class="d-none rounded border-warning border border-dashed bg-light-warning d-flex align-items-center p-5 mb-10">
|
|
<i class="ki-duotone ki-information-5 fs-3x text-warning me-5"><span class="path1"></span><span class="path2"></span><span class="path3"></span></i>
|
|
<div class="text-gray-700 fw-bold fs-5 d-flex flex-column pe-0 pe-sm-10">
|
|
<span id="errorModalTxt"></span>
|
|
</div>
|
|
<button id="id_dismiss_error_modal_msg" type="button" class="position-absolute position-sm-relative m-2 m-sm-0 top-0 end-0 btn btn-icon btn-sm btn-active-light-primary ms-sm-auto">
|
|
<i class="ki-solid ki-cross fs-2x text-gray-700"></i>
|
|
</button>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-9 align-items-center d-flex flex-stack">
|
|
<div class="badge badge-lg badge-light-primary">
|
|
<div id="dirs_browser_nav" class="d-flex align-items-center flex-wrap">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3 align-items-center d-flex justify-content-end">
|
|
<button id="id_dir_browser_create_dir" type="button" class="btn btn-flex btn-primary">
|
|
<i class="ki-duotone ki-add-folder fs-2">
|
|
<span class="path1"></span>
|
|
<span class="path2"></span>
|
|
</i>
|
|
<span data-i18n="general.add"></span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="dir_browser_folder_divider py-2 d-none">
|
|
<hr>
|
|
</div>
|
|
<div id="dirsbrowser_new_folder" class="d-flex align-items-center d-none">
|
|
<span>
|
|
<i class="ki-duotone ki-folder fs-2x text-primary me-4">
|
|
<span class="path1"></span>
|
|
<span class="path2"></span>
|
|
</i>
|
|
</span>
|
|
<input data-i18n="[placeholder]fs.create_folder_msg" id="dirsbrowser_new_folder_input" type="text" name="new_folder_name" placeholder="Enter the new folder name" class="form-control mw-250px me-3" />
|
|
<button class="btn btn-icon btn-light-primary me-3" id="dirsbrowser_add_folder">
|
|
<span class="indicator-label">
|
|
<i class="ki-duotone ki-check fs-1"></i>
|
|
</span>
|
|
<span class="indicator-progress">
|
|
<span class="spinner-border spinner-border-sm align-middle"></span>
|
|
</span>
|
|
</button>
|
|
<button class="btn btn-icon btn-light-danger" id="dirsbrowser_cancel_folder">
|
|
<i class="ki-solid ki-cross fs-1"></i>
|
|
</button>
|
|
</div>
|
|
<div class="dir_browser_folder_divider py-2 d-none">
|
|
<hr>
|
|
</div>
|
|
<table id="dirsbrowser_list" class="table align-middle table-row-dashed fs-6 gy-5">
|
|
<thead>
|
|
<tr class="text-start text-muted fw-bold fs-7 text-uppercase gs-0">
|
|
<th></th>
|
|
<th data-i18n="general.name" class="min-w-250px">Name</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="dirsbrowser_list_body" class="text-gray-600 fw-semibold">
|
|
</tbody>
|
|
</table>
|
|
|
|
<div class="form-floating d-none">
|
|
<input type="text" class="form-control form-control-solid" id="move_copy_source"/>
|
|
<label data-i18n="general.source_name" for="move_copy_source">Source name</label>
|
|
</div>
|
|
|
|
<div class="form-floating mb-5 mt-7">
|
|
<input type="text" class="form-control form-control-solid" id="move_copy_folder"/>
|
|
<label data-i18n="general.target_folder" for="move_copy_folder">Target folder</label>
|
|
</div>
|
|
|
|
<div class="form-floating" id="move_copy_name_container">
|
|
<input type="text" class="form-control form-control-solid" id="move_copy_name"/>
|
|
<label data-i18n="general.dest_name" for="move_copy_name">Destination name</label>
|
|
</div>
|
|
|
|
</div>
|
|
<div class="modal-footer border-0">
|
|
{{- if .CanCopy }}
|
|
<button id="id_copy_button" type="button" class="btn {{if .CanRename}}btn-light-primary me-5{{else}}btn-primary{{end}}" data-bs-dismiss="modal">
|
|
<span data-i18n="fs.copy.msg">Copy</span>
|
|
</button>
|
|
{{- end}}
|
|
{{- if .CanRename }}
|
|
<button id="id_move_button" type="button" class="btn btn-primary" data-bs-dismiss="modal">
|
|
<span data-i18n="fs.move.msg">Move</span>
|
|
</button>
|
|
{{- end}}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{{- end}}
|
|
{{- end}} |