1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810 |
- <!--
- 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 "title"}}{{.Title}}{{- end}}
- {{- define "page_body"}}
- {{- template "errmsg" .Error}}
- <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-duotone ki-magnifier fs-1 position-absolute ms-6">
- <span class="path1"></span>
- <span class="path2"></span>
- </i>
- <input type="text" data-kt-filemanager-table-filter="search" class="form-control form-control-solid 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 type="button" class="btn btn-flex btn-light-primary me-3" onclick="showCreateNewFolder(0);">
- <i class="ki-duotone ki-add-folder fs-2">
- <span class="path1"></span>
- <span class="path2"></span>
- </i>
- New Folder
- </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>
- Upload Files
- </button>
- {{- end}}
- </div>
- <div class="d-flex justify-content-end 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 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">
- Actions
- <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 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 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 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 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>
- <div class="card-body">
- <div class="d-flex flex-stack">
- <div class="badge badge-lg badge-light-primary">
- <div class="d-flex align-items-center flex-wrap">
- <i class="ki-duotone ki-home fs-1 text-primary me-3"></i>
- <a 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>
- <div id="file_manager_new_folder" class="d-flex align-items-center py-7 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 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" onclick="createNewFolder();">
- <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" onclick="hideCreateNewFolder(0);">
- <i class="ki-duotone ki-cross fs-1">
- <span class="path1"></span>
- <span class="path2"></span>
- </i>
- </button>
- </div>
- <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">
- <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 class="min-w-250px">Name</th>
- <th class="min-w-10px">Size</th>
- <th 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>
- {{- 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"/>
- <link href="{{.StaticURL}}/vendor/video-js/video-js.min.css" rel="stylesheet" type="text/css"/>
- <style>
- .gslide-description-bg {
- background: var(--bs-app-bg-color) !important;
- opacity: 0.9;
- }
- </style>
- {{- end}}
- {{- define "extra_js"}}
- <script src="{{.StaticURL}}/assets/plugins/custom/datatables/datatables.bundle.js"></script>
- <script src="{{.StaticURL}}/vendor/glightbox/glightbox.min.js"></script>
- <script src="{{.StaticURL}}/vendor/pdfobject/pdfobject.min.js"></script>
- <script src="{{.StaticURL}}/vendor/video-js/video.min.js"></script>
- {{- if not .ShareUploadBaseURL}}
- <script type="text/javascript">
- 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"]
- </script>
- {{- end}}
- <script type="text/javascript">
- function keepAlive() {
- //{{- if not .ShareUploadBaseURL}}
- axios.get('{{.ProfileURL}}',{
- timeout: 15000
- }).catch(function (error){});
- //{{- end}}
- }
- //{{- 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 = "Failed to get directory listing";
- if ($xhr) {
- let json = $xhr.responseJSON;
- if (json) {
- if (json.message) {
- txt += ": " + json.message;
- } else {
- txt += ": " + json.error;
- }
- }
- }
- $('#errorModalTxt').text(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);
- let dirPath = row['dir_path'];
- 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="#" onclick="onDirBrowserClick('${dirPath}');" class="text-gray-700 text-hover-primary">${data}</a>
- </div>`
- }
- return data;
- }
- }
- ],
- lengthChange: true,
- columnDefs: [
- {
- targets: 0,
- visible: false,
- searchable: false
- },
- {
- targets: 1,
- visible: true,
- searchable: true
- }
- ],
- language: {
- loadingRecords: "",
- emptyTable: "No more subfolders in here"
- },
- order: [1, 'asc']
- });
- dt.on('draw', function () {
- let navHTML = `<i class="ki-duotone ki-home fs-1 text-primary me-3"></i>
- <a href="#" onclick="onDirBrowserClick('%2F');">Home</a>`;
- 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);
- navHTML += `<i class="ki-duotone ki-right fs-2x text-primary mx-1"></i>
- <a href="#" onclick="onDirBrowserClick('${fullPath}');">${dir}</a>`;
- }
- }
- }
- document.getElementById("dirs_browser_nav").innerHTML = navHTML;
- $('#move_copy_folder').val(p);
- });
- }
- var handleCreateNewFolder = function() {
- $('#dirsbrowser_add_folder').click(function(){
- let errDivEl = $('#errorModalMsg');
- let errTxtEl = $('#errorModalTxt');
- let dirName = replaceSlash($("#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){
- errTxtEl.text("Folder name is required");
- 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;
- $('#dirsbrowser_new_folder').addClass("d-none");
- }).catch(function (error) {
- let errorMessage = "Unable to create the new folder";
- if (error && error.response) {
- if (error.response.data.message) {
- errorMessage = error.response.data.message;
- }
- if (error.response.data.error) {
- errorMessage += ": " + error.response.data.error;
- }
- }
- errTxtEl.text(errorMessage);
- errDivEl.removeClass("d-none");
- submitButton.removeAttribute('data-kt-indicator');
- submitButton.disabled = false;
- cancelButton.disabled = false;
- });
- });
- }
- return {
- init: function (url, dirPath) {
- curDir = dirPath;
- if (dt) {
- dt.ajax.url(url).load();
- return;
- }
- initDatatable(url);
- handleCreateNewFolder();
- }
- }
- }();
- //{{- end}}
- </script>
- <script type="text/javascript">
- var KTDatatablesServerSide = function () {
- // Shared variables
- //var table;
- var dt;
- var lightbox;
- // Private functions
- var initDatatable = function () {
- $('#errorMsg').addClass("d-none");
- dt = $("#file_manager_list").DataTable({
- ajax: {
- url: "{{.DirsURL}}?path={{.CurrentDir}}",
- dataSrc: "",
- error: function ($xhr, textStatus, errorThrown) {
- $(".dataTables_processing").hide();
- let txt = "Failed to get directory listing";
- if ($xhr) {
- let json = $xhr.responseJSON;
- if (json) {
- if (json.message){
- txt += ": " + json.message;
- } else {
- txt += ": " + json.error;
- }
- }
- }
- $('#errorTxt').text(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" },
- {
- 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, '"');
- 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-5 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":
- let mediaType = 'video/mp4';
- if (extension == 'webm'){
- mediaType = 'video/webm';
- } else if (extension == 'ogg' || extension == 'ogv') {
- mediaType = 'video/ogg';
- } else if (extension == 'mp3'){
- mediaType = 'audio/mpeg';
- } else if (extension == 'wav'){
- mediaType = 'audio/wav';
- }
- let name = b64EncodeUnicode(row["name"]);
- previewDiv = `<div class="ms-2" data-kt-filemanger-table="view_item">
- <a href="#" onclick="openVideoPlayer('${name}', '${row['url']}', '${mediaType}');" class="btn btn-sm btn-icon btn-light btn-active-light-primary">
- <i class="ki-duotone ki-eye fs-5 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-5 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-5 m-0">
- <span class="path1"></span>
- <span class="path2"></span>
- <span class="path3"></span>
- </i>
- </a>
- </div>`;
- }
- //{{- end}}
- }
- }
- let meta = b64EncodeUnicode(row["meta"]);
- 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-7 w-150px py-4" data-kt-menu="true">
- {{- if .CanRename}}
- <div class="menu-item px-3">
- <a href="#" onclick="renameItem('${meta}');" class="menu-link px-3" data-kt-filemanager-table="rename">Rename</a>
- </div>
- {{- end}}
- {{- if or .CanRename .CanAddFiles}}
- <div class="menu-item px-3">
- <a href="#" onclick="moveOrCopyItem('${meta}');" class="menu-link px-3" data-kt-filemanager-table-filter="move_or_copy">Move or copy</a>
- </div>
- {{- end}}
- {{- if .CanShare}}
- <div class="menu-item px-3">
- <a href="#" onclick="shareItem('${meta}');" class="menu-link px-3" data-kt-filemanager-table="share">Share</a>
- </div>
- {{- end}}
- {{- if .CanDelete}}
- <div class="menu-item px-3">
- <a href="#" onclick="deleteItem('${meta}');" class="menu-link text-danger px-3" data-kt-filemanager-table-filter="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: {
- loadingRecords: "",
- emptyTable: "No files or folders"
- },
- orderFixed: [1, 'asc'],
- order: [2, 'asc']
- });
- //table = dt.$;
- dt.on('draw', function () {
- 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();
- });
- 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 toolbarBase = document.querySelector('[data-kt-filemanager-table-toolbar="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 = `${totalSelected} Selected`;
- }
- if (toolbarBase){
- toolbarBase.classList.add('d-none');
- }
- if (toolbarSelected){
- toolbarSelected.classList.remove('d-none');
- }
- } else {
- $('#select_checkbox').prop("checked", false);
- selectAllCheck.checked = false;
- if (toolbarBase) {
- toolbarBase.classList.remove('d-none');
- }
- if (toolbarBase) {
- toolbarSelected.classList.add('d-none');
- }
- }
- }
- 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.addEventListener('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){
- selectAllCheck.addEventListener('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){
- downloadButton.addEventListener('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){
- moveOrCopyButton.addEventListener('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){
- shareButton.addEventListener('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) {
- deleteButton.addEventListener('click', function(e){
- ModalAlert.fire({
- text: "Do you want to delete the selected item/s? This action is irreversible",
- icon: "warning",
- confirmButtonText: "Delete",
- cancelButtonText: '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;
- }
- keepAlive();
- let keepAliveTimer = setInterval(keepAlive, 300000);
- $('#loading_message').text("");
- KTApp.showPageLoading();
- function deleteSelected() {
- if (index >= selectedRowsIdx.length || hasError){
- clearInterval(keepAliveTimer);
- KTApp.hidePageLoading();
- if (!hasError){
- location.reload();
- }
- return;
- }
- let meta = dt.row(selectedRowsIdx[index]).data()['meta'];
- let attrs = getDeleteReqAttrs(meta);
- let deleteTxt = "";
- if (selectedRowsIdx.length > 1){
- let name = getNameFromMeta(meta);
- deleteTxt = `Delete ${index+1}/${selectedRowsIdx.length}: ${name}`;
- }
- $('#loading_message').text(deleteTxt);
- axios.delete(attrs.path,{
- timeout: attrs.reqTimeout,
- headers: {
- 'X-CSRF-TOKEN': '{{.CSRFToken}}'
- },
- validateStatus: function (status) {
- return status == 200;
- }
- }).then(function(response){
- index++;
- deleted++;
- deleteSelected();
- }).catch(function(error){
- index++;
- hasError = true;
- let errorMessage = "Unable to delete the selected item/s";
- if (deleted > 0){
- errorMessage = "Not all the selected items have been deleted, please reload the page";
- }
- if (error && error.response) {
- if (error.response.data.message) {
- errorMessage = error.response.data.message;
- }
- if (error.response.data.error) {
- errorMessage += ": " + error.response.data.error;
- }
- }
- errTxtEl.text(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");
- let decodedMeta = UnicodeDecodeB64(meta);
- $('#move_copy_name_container').removeClass("d-none");
- $('#move_copy_source').val(meta);
- $('#move_copy_name').val(getNameFromMeta(decodedMeta));
- $('#modal_move_or_copy').modal('show');
- KTDatatablesFoldersExplorer.init('{{.DirsURL}}?dirtree=1&path={{.CurrentDir}}', '{{.CurrentDir}}');
- }
- function getMoveOtCopyItems() {
- 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")){
- 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 = UnicodeDecodeB64($('#move_copy_source').val());
- let sourceName = getNameFromMeta(meta);
- items.push({
- targetDir: targetDir,
- sourceName: sourceName,
- targetName: $("#move_copy_name").val()
- });
- }
- return items;
- }
- function doCopy() {
- let items = getMoveOtCopyItems();
- if (items.length == 0){
- return;
- }
- keepAlive();
- let keepAliveTimer = setInterval(keepAlive, 300000);
- let hasError = false;
- let index = 0;
- let errDivEl = $('#errorMsg');
- let errTxtEl = $('#errorTxt');
- errDivEl.addClass("d-none");
- $('#loading_message').text("");
- KTApp.showPageLoading();
- function copyItem() {
- if (index >= items.length || hasError){
- clearInterval(keepAliveTimer);
- 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 msgTxt = `${sourcePath} => ${targetPath}`;
- msgTxt = `Copy ${index+1}/${items.length}: ${msgTxt}`;
- $('#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: 180000,
- headers: {
- 'X-CSRF-TOKEN': '{{.CSRFToken}}'
- },
- validateStatus: function (status) {
- return status == 200;
- }
- }).then(function (response) {
- index++;
- copyItem();
- }).catch(function (error) {
- index++;
- hasError = true;
- let errorMessage = "Error copying item";
- if (error && error.response) {
- if (error.response.data.message) {
- errorMessage = error.response.data.message;
- }
- if (error.response.data.error) {
- errorMessage += ": " + error.response.data.error;
- }
- }
- errTxtEl.text(errorMessage);
- errDivEl.removeClass("d-none");
- copyItem();
- });
- }
- copyItem();
- }
- function doMove() {
- let items = getMoveOtCopyItems();
- if (items.length == 0){
- return;
- }
- keepAlive();
- let keepAliveTimer = setInterval(keepAlive, 300000);
- let hasError = false;
- let index = 0;
- let errDivEl = $('#errorMsg');
- let errTxtEl = $('#errorTxt');
- errDivEl.addClass("d-none");
- $('#loading_message').text("");
- KTApp.showPageLoading();
- function moveItem() {
- if (index >= items.length || hasError){
- clearInterval(keepAliveTimer);
- 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 msgTxt = `${sourcePath} => ${targetPath}`;
- msgTxt = `Move ${index+1}/${items.length}: ${msgTxt}`;
- $('#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: 180000,
- headers: {
- 'X-CSRF-TOKEN': '{{.CSRFToken}}'
- },
- validateStatus: function (status) {
- return status == 200;
- }
- }).then(function (response) {
- index++;
- moveItem();
- }).catch(function (error) {
- index++;
- hasError = true;
- let errorMessage = "Error moving item";
- if (error && error.response) {
- if (error.response.data.message) {
- errorMessage = error.response.data.message;
- }
- if (error.response.data.error) {
- errorMessage += ": " + error.response.data.error;
- }
- }
- errTxtEl.text(errorMessage);
- errDivEl.removeClass("d-none");
- moveItem();
- });
- }
- moveItem();
- }
- function getDeleteReqAttrs(meta) {
- let path;
- let reqTimeout = 15000;
- let itemType = getTypeFromMeta(meta);
- let itemName = getNameFromMeta(meta);
- if (itemType == "1"){
- path = '{{.DirsURL}}';
- reqTimeout = 120000
- } else {
- path = '{{.FilesURL}}';
- }
- path+='?path={{.CurrentDir}}'+encodeURIComponent("/"+itemName);
- return { path, reqTimeout}
- }
- function deleteItem(meta) {
- let errDivEl = $('#errorMsg');
- let errTxtEl = $('#errorTxt');
- errDivEl.addClass("d-none");
- meta = UnicodeDecodeB64(meta);
- let itemName = getNameFromMeta(meta);
- ModalAlert.fire({
- text: `Do you want to delete "${itemName}"? This action is irreversible`,
- icon: "warning",
- confirmButtonText: "Delete",
- cancelButtonText: 'Cancel',
- customClass: {
- confirmButton: "btn btn-danger",
- cancelButton: 'btn btn-secondary'
- }
- }).then((result) => {
- if (result.isConfirmed){
- $('#loading_message').text("");
- KTApp.showPageLoading();
- let attrs = getDeleteReqAttrs(meta);
- axios.delete(attrs.path, {
- timeout: attrs.reqTimeout,
- headers: {
- 'X-CSRF-TOKEN': '{{.CSRFToken}}'
- },
- validateStatus: function (status) {
- return status == 200;
- }
- }).then(function(response){
- location.reload();
- }).catch(function(error){
- KTApp.hidePageLoading();
- let errorMessage = `Unable to delete "${itemName}"`;
- if (error && error.response) {
- if (error.response.data.message) {
- errorMessage = error.response.data.message;
- }
- if (error.response.data.error) {
- errorMessage += ": " + error.response.data.error;
- }
- }
- errTxtEl.text(errorMessage);
- errDivEl.removeClass("d-none");
- });
- }
- });
- }
- function shareItem(meta) {
- meta = UnicodeDecodeB64(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 decodedMeta = UnicodeDecodeB64(meta);
- let oldName = getNameFromMeta(decodedMeta);
- $('#rename_old_name').val(meta);
- $('#rename_new_name').val(oldName);
- $('#rename_title').text(`Rename "${oldName}"`);
- $('#modal_rename').modal('show');
- }
- function doRename() {
- let decodedMeta = UnicodeDecodeB64($('#rename_old_name').val());
- let oldName = getNameFromMeta(decodedMeta);
- let newName = $('#rename_new_name').val();
- let errDivEl = $('#errorMsg');
- let errTxtEl = $('#errorTxt');
- if (!newName){
- errTxtEl.text("New name is required");
- errDivEl.removeClass("d-none");
- return;
- }
- if (newName == oldName){
- errTxtEl.text("The new name must be different from the current name");
- errDivEl.removeClass("d-none");
- return;
- }
- 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 == 200;
- }
- }).then(function (response) {
- location.reload();
- }).catch(function (error) {
- let errorMessage = `Unable to rename "${oldName}"`;
- if (error && error.response) {
- if (error.response.data.message) {
- errorMessage = error.response.data.message;
- }
- if (error.response.data.error) {
- errorMessage += ": " + error.response.data.error;
- }
- }
- errTxtEl.text(errorMessage);
- errDivEl.removeClass("d-none");
- });
- }
- function showCreateNewFolder(sender) {
- if (sender == 0) {
- $('#file_manager_new_folder').removeClass("d-none");
- $('#errorMsg').addClass("d-none");
- let el = $('#file_manager_new_folder_input');
- el.val("");
- el.focus();
- return;
- }
- $('#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){
- $('#file_manager_new_folder').addClass("d-none");
- } else {
- $('#dirsbrowser_new_folder').addClass("d-none");
- }
- }
- function createNewFolder() {
- let errDivEl = $('#errorMsg');
- let errTxtEl = $('#errorTxt');
- let dirName = replaceSlash($("#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){
- errTxtEl.text("Folder name is required");
- 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 = "Unable to create the new folder";
- if (error && error.response) {
- if (error.response.data.message) {
- errorMessage = error.response.data.message;
- }
- if (error.response.data.error) {
- errorMessage += ": " + error.response.data.error;
- }
- }
- errTxtEl.text(errorMessage);
- errDivEl.removeClass("d-none");
- submitButton.removeAttribute('data-kt-indicator');
- submitButton.disabled = false;
- cancelButton.disabled = false;
- });
- }
- //{{- end}}
- var player;
- var playerKeepAlive;
- function uploadFiles(files) {
- keepAlive();
- let keepAliveTimer = setInterval(keepAlive, 300000);
- let has_errors = false;
- let index = 0;
- let success = 0;
- $('#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;
- //{{- if .ShareUploadBaseURL}}
- uploadPath = '{{.ShareUploadBaseURL}}' + fixedEncodeURIComponent("/"+escapeHTML(f.name));
- //{{- else}}
- uploadPath = '{{.FileURL}}?path={{.CurrentDir}}' + encodeURIComponent("/" + f.name);
- //{{- end}}
- let lastModified;
- try {
- lastModified = f.lastModified;
- } catch (e) {
- console.log("unable to get last modified time from file: " + e.message);
- lastModified = "";
- }
- let uploadTxt = f.name;
- if (files.length > 1){
- uploadTxt = `Upload ${index+1}/${files.length}: ${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 = "Error uploading files";
- if (error && error.response) {
- if (error.response.data.message) {
- errorMessage = error.response.data.message;
- }
- if (error.response.data.error) {
- errorMessage += ": " + error.response.data.error;
- }
- }
- index++;
- has_errors = true;
- $('#errorTxt').text(errorMessage);
- $('#errorMsg').removeClass("d-none");
- uploadFile();
- });
- }
- uploadFile();
- }
- function openVideoPlayer(name, url, videoType){
- if (!player){
- player = videojs('video_player', {
- controls: true,
- autoplay: false,
- preload: 'auto'
- });
- }
- $("#video_title").text(UnicodeDecodeB64(name));
- $('#modal_video_player').modal('show');
- player.src({
- type: videoType,
- src: url
- });
- keepAlive();
- playerKeepAlive = setInterval(keepAlive, 300000);
- }
- // On document ready
- KTUtil.onDOMContentLoaded(function () {
- KTDatatablesServerSide.init();
- var dropzone = new Dropzone("#upload_files", {
- url: "{{.FilesURL}}?path={{.CurrentDir}}",
- paramName: "filenames",
- maxFiles: 250,
- maxFilesize: null,
- autoQueue: false,
- addRemoveLinks: true,
- autoProcessQueue: false,
- filesizeBase: 1000,
- init: function() {
- var dropzone = this;
- $("#upload_files_button").click(function(){
- uploadFiles(dropzone.getAcceptedFiles());
- });
- }
- });
- dropzone.on("addedfile", file => {
- file.previewElement.querySelector(".dz-progress").style.display = 'none';
- });
- $('#modal_video_player').on('hide.bs.modal', function () {
- player.pause();
- player.reset();
- 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}}
- });
- </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-350px" data-kt-menu="true">
- <div class="card">
- <div class="card-header">
- <h3 class="card-title"><span class="text-gray-700 fw-semibold 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 class="fs-6 text-dark 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">Size: {{$size}}{{if gt $percentage 0}} ({{$percentage}}%){{end}}</div>
- {{- end}}
- {{- if $files}}
- {{- $percentage := .QuotaUsage.GetQuotaFilesPercentage}}
- <div class="{{if .QuotaUsage.IsQuotaFilesLow}}text-warning{{else}}text-gray-700{{end}} fw-semibold fs-6">Files: {{$files}}{{if gt $percentage 0}} ({{$percentage}}%){{end}}</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 class="fs-6 text-dark 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">Total: {{$total}}{{if gt $percentage 0}} ({{$percentage}}%){{end}}</div>
- {{- end}}
- {{- if $download}}
- {{$percentage := .QuotaUsage.GetDownloadTransferQuotaPercentage}}
- <div class="{{if .QuotaUsage.IsDownloadTransferQuotaLow}}text-warning{{else}}text-gray-700{{end}} fw-semibold fs-6">Download: {{$download}}{{if gt $percentage 0}} ({{$percentage}}%){{end}}</div>
- {{- end}}
- {{- if $upload}}
- {{$percentage := .QuotaUsage.GetUploadTransferQuotaPercentage}}
- <div class="{{if .QuotaUsage.IsUploadTransferQuotaLow}}text-warning{{else}}text-gray-700{{end}} fw-semibold fs-6">Upload: {{$upload}}{{if gt $percentage 0}} ({{$percentage}}%){{end}}</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 class="modal-title">Upload files</h3>
- <div class="btn btn-icon btn-sm btn-active-color-primary" data-bs-dismiss="modal" aria-label="Close">
- <i class="ki-duotone ki-cross fs-1"><span class="path1"></span><span class="path2"></span></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" 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 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-400">Upload up to 30 files</span> -->
- </div>
- </div>
- </div>
- </div>
- </form>
- </div>
- <div class="modal-footer border-0">
- <button type="button" class="btn btn-light me-5" data-bs-dismiss="modal">Cancel</button>
- <button 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 class="btn btn-icon btn-sm btn-active-color-primary" data-bs-dismiss="modal" aria-label="Close">
- <i class="ki-duotone ki-cross fs-1"><span class="path1"></span><span class="path2"></span></i>
- </div>
- </div>
- <div class="modal-body">
- <video id="video_player" class="video-js vjs-big-play-centered vjs-fluid">
- <p class="vjs-no-js">To view this video please enable JavaScript, and consider upgrading to a web browser that supports HTML5 video</p>
- </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 class="btn btn-icon btn-sm btn-active-color-primary" data-bs-dismiss="modal" aria-label="Close">
- <i class="ki-duotone ki-cross fs-1"><span class="path1"></span><span class="path2"></span></i>
- </div>
- </div>
- <div class="modal-body">
- <input id="rename_old_name" type="text" class="d-none"/>
- <div class="mb-10">
- <label for="rename_new_name" class="form-label">New name</label>
- <input id="rename_new_name" type="text" class="form-control"/>
- </div>
- </div>
- <div class="modal-footer border-0">
- <button type="button" class="btn btn-secondary me-5" data-bs-dismiss="modal">Cancel</button>
- <button type="button" class="btn btn-primary" data-bs-dismiss="modal" onclick="doRename();">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 class="modal-title">
- Choose target folder
- </h3>
- <div class="btn btn-icon btn-sm btn-active-color-primary" data-bs-dismiss="modal" aria-label="Close">
- <i class="ki-duotone ki-cross fs-1"><span class="path1"></span><span class="path2"></span></i>
- </div>
- </div>
- <div class="modal-body">
- <div id="errorModalMsg" class="d-none alert alert-dismissible 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 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" onclick="dismissErrorModalMsg();">
- <i class="ki-duotone ki-cross fs-2x text-primary"><span class="path1"></span><span class="path2"></span></i>
- </button>
- </div>
- <script type="text/javascript">
- function dismissErrorModalMsg(){
- $('#errorModalMsg').addClass("d-none");
- }
- </script>
- <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 type="button" class="btn btn-flex btn-primary" onclick="showCreateNewFolder(1);">
- <i class="ki-duotone ki-add-folder fs-2">
- <span class="path1"></span>
- <span class="path2"></span>
- </i>
- Add
- </button>
- </div>
- </div>
- <div id="dirsbrowser_new_folder" class="d-flex align-items-center py-7 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 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" onclick="hideCreateNewFolder(1);">
- <i class="ki-duotone ki-cross fs-1">
- <span class="path1"></span>
- <span class="path2"></span>
- </i>
- </button>
- </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 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 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 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 for="move_copy_name">Destination name</label>
- </div>
- </div>
- <div class="modal-footer border-0">
- {{- if .CanAddFiles }}
- <button type="button" class="btn btn-light-primary me-5" data-bs-dismiss="modal" onclick="doCopy();">Copy</button>
- {{- end}}
- {{- if .CanRename }}
- <button type="button" class="btn btn-primary" data-bs-dismiss="modal" onclick="doMove();">Move</button>
- {{- end}}
- </div>
- </div>
- </div>
- </div>
- {{- end}}
- {{- end}}
|