sftpgo/templates/webclient/files.html
Nicola Murino 70cb71acfa
WebClient: don't hide initial errors in files page
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
2024-04-02 18:37:29 +02:00

2632 lines
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>&nbsp;(<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"];
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) {
$(".dataTables_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) {
$(".dataTables_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":
case "ico":
let desc = escapeHTML(filename).replace(/"/g, '&quot;');
previewDiv = `<div class="ms-2" data-kt-filemanger-table="view_item">
<a href="${row['url']}" data-gallery="gallery" data-glightbox="description: &lt;span class=&quot;fs-5 fw-bold&quot;&gt;${desc}&lt;/span&gt;" 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" 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" 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, true, false).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">
<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;
}
$('#loading_message').text("");
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);
let deleteTxt = "";
if (selectedRowsIdx.length > 1){
deleteTxt = $.t('fs.deleting', {
idx : index + 1,
total: selectedRowsIdx.length,
name: itemName
});
}
$('#loading_message').text(deleteTxt);
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;
$('#loading_message').text("");
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) {
msgTxt = $.t('fs.copying', {
idx: index + 1,
total: items.length,
name: `${sourcePath} => ${targetPath}`
});
$('#loading_message').text(msgTxt);
}
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;
$('#loading_message').text("");
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) {
msgTxt = $.t('fs.moving', {
idx: index + 1,
total: items.length,
name: `${sourcePath} => ${targetPath}`
});
$('#loading_message').text(msgTxt);
}
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){
$('#loading_message').text("");
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;
}
$('#loading_message').text("");
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");
$('#loading_message').text("");
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 uploadTxt = f.name;
if (files.length > 1){
uploadTxt = $.t('fs.uploading', {
idx: index + 1,
total: files.length,
name: uploadTxt
});
}
$('#loading_message').text(uploadTxt);
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){
$('#loading_message').text(`${uploadTxt} ${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 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(){
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;
}
}
});
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(){
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;
}
}
});
$('#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}}