| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169 |
- <!--
- Copyright (C) 2019-2022 Nicola Murino
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published
- by the Free Software Foundation, version 3.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
- -->
- {{template "base" .}}
- {{define "title"}}{{.Title}}{{end}}
- {{define "extra_css"}}
- <link href="{{.StaticURL}}/vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet">
- <link href="{{.StaticURL}}/vendor/datatables/buttons.bootstrap4.min.css" rel="stylesheet">
- <link href="{{.StaticURL}}/vendor/datatables/fixedHeader.bootstrap4.min.css" rel="stylesheet">
- <link href="{{.StaticURL}}/vendor/datatables/responsive.bootstrap4.min.css" rel="stylesheet">
- <link href="{{.StaticURL}}/vendor/datatables/dataTables.checkboxes.css" rel="stylesheet">
- <link href="{{.StaticURL}}/vendor/lightbox2/css/lightbox.min.css" rel="stylesheet">
- <link href="{{.StaticURL}}/vendor/video-js/video-js.min.css" rel="stylesheet" />
- <style>
- div.dataTables_wrapper span.selected-info,
- div.dataTables_wrapper span.selected-item {
- margin-left: 0.5em;
- }
- </style>
- {{end}}
- {{define "page_body"}}
- <div id="errorMsg" class="card mb-4 border-left-warning" style="display: none;">
- <div id="errorTxt" class="card-body text-form-error"></div>
- </div>
- <div class="card shadow mb-4">
- <div class="card-header py-3">
- <h6 class="m-0 font-weight-bold"><a href="{{.FilesURL}}?path=%2F"><i class="fas fa-home"></i> Home</a> {{range .Paths}}{{if eq .Href ""}}/{{.DirName}}{{else}}<a href="{{.Href}}">/{{.DirName}}</a>{{end}}{{end}}</h6>
- </div>
- <div class="card-body">
- {{if .Error}}
- <div class="card mb-4 border-left-warning">
- <div class="card-body text-form-error">{{.Error}}</div>
- </div>
- {{end}}
- <div class="table-responsive">
- <table class="table table-hover nowrap" id="dataTable" width="100%" cellspacing="0">
- <thead>
- <tr>
- <th></th>
- <th>Type</th>
- <th>Name</th>
- <th>Size</th>
- <th>Last modified</th>
- <th></th>
- <th></th>
- </tr>
- </thead>
- </table>
- </div>
- </div>
- </div>
- {{end}}
- {{define "dialog"}}
- <div class="modal fade" id="createDirModal" tabindex="-1" role="dialog" aria-labelledby="createDirModalLabel"
- aria-hidden="true">
- <div class="modal-dialog" role="document">
- <div class="modal-content">
- <div class="modal-header">
- <h5 class="modal-title" id="createDirModalLabel">
- Create a new directory
- </h5>
- <button class="close" type="button" data-dismiss="modal" aria-label="Close">
- <span aria-hidden="true">×</span>
- </button>
- </div>
- <form id="create_dir_form" action="" method="POST">
- <div class="modal-body">
- <div class="form-group">
- <label for="directory_name" class="col-form-label">Name</label>
- <input type="text" class="form-control" id="directory_name" required>
- </div>
- </div>
- <div class="modal-footer">
- <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
- <button type="submit" class="btn btn-primary">Submit</button>
- </div>
- </form>
- </div>
- </div>
- </div>
- <div class="modal fade" id="uploadFilesModal" tabindex="-1" role="dialog" aria-labelledby="uploadFilesModalLabel"
- aria-hidden="true">
- <div class="modal-dialog" role="document">
- <div class="modal-content">
- <div class="modal-header">
- <h5 class="modal-title" id="uploadFilesModalLabel">
- Upload one or more files
- </h5>
- <button class="close" type="button" data-dismiss="modal" aria-label="Close">
- <span aria-hidden="true">×</span>
- </button>
- </div>
- <form id="upload_files_form" action="{{.FilesURL}}?path={{.CurrentDir}}" method="POST" enctype="multipart/form-data">
- <div class="modal-body">
- <input type="file" class="form-control-file" id="files_name" name="filenames" required multiple>
- </div>
- <div class="modal-footer">
- <input type="hidden" name="_form_token" value="{{.CSRFToken}}">
- <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
- <button type="submit" class="btn btn-primary">Submit</button>
- </div>
- </form>
- </div>
- </div>
- </div>
- <div class="modal fade" id="renameModal" tabindex="-1" role="dialog" aria-labelledby="renameModalLabel"
- aria-hidden="true">
- <div class="modal-dialog" role="document">
- <div class="modal-content">
- <div class="modal-header">
- <h5 class="modal-title" id="renameModalLabel">
- Rename the selected item
- </h5>
- <button class="close" type="button" data-dismiss="modal" aria-label="Close">
- <span aria-hidden="true">×</span>
- </button>
- </div>
- <form id="rename_form" action="" method="POST">
- <div class="modal-body">
- <div class="form-group">
- <label for="rename_old_name" class="col-form-label">Old name</label>
- <input type="text" class="form-control" id="rename_old_name" readonly>
- </div>
- <div class="form-group">
- <label for="rename_new_dir" class="col-form-label">New base dir</label>
- <input type="text" class="form-control" id="rename_new_dir" required aria-describedby="renameNewDirHelpBlock">
- <small id="renameNewDirHelpBlock" class="form-text text-muted">
- Setting a directory other than the current one will move the item there. This directory must exists
- </small>
- </div>
- <div class="form-group">
- <label for="rename_new_name" class="col-form-label">New name</label>
- <input type="text" class="form-control" id="rename_new_name" required>
- </div>
- </div>
- <div class="modal-footer">
- <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
- <button type="submit" class="btn btn-primary">Submit</button>
- </div>
- </form>
- </div>
- </div>
- </div>
- <div class="modal fade" id="deleteModal" tabindex="-1" role="dialog" aria-labelledby="deleteModalLabel"
- aria-hidden="true">
- <div class="modal-dialog" role="document">
- <div class="modal-content">
- <div class="modal-header">
- <h5 class="modal-title" id="deleteModalLabel">
- Confirmation required
- </h5>
- <button class="close" type="button" data-dismiss="modal" aria-label="Close">
- <span aria-hidden="true">×</span>
- </button>
- </div>
- <div class="modal-body">Do you want to delete the selected item/s?</div>
- <div class="modal-footer">
- <button class="btn btn-secondary" type="button" data-dismiss="modal">
- Cancel
- </button>
- <a class="btn btn-warning" href="#" onclick="deleteAction()">
- Delete
- </a>
- </div>
- </div>
- </div>
- </div>
- <div class="modal fade" id="videoModal" tabindex="-1" role="dialog" aria-labelledby="videoModalLabel"
- aria-hidden="true">
- <div class="modal-dialog modal-lg" role="document">
- <div class="modal-content">
- <div class="modal-header">
- <h5 class="modal-title" id="videoModalLabel">
- <span id="video_title"></span>
- </h5>
- <button class="close" type="button" data-dismiss="modal" aria-label="Close">
- <span aria-hidden="true">×</span>
- </button>
- </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>
- <div class="modal fade" id="spinnerModal" tabindex="-1" role="dialog" data-keyboard="false" data-backdrop="static">
- <div class="modal-dialog modal-dialog-centered justify-content-center" role="document">
- <span style="color: #333333;" class="fa fa-spinner fa-spin fa-3x"></span>
- <!-- <span id="uploadProgress" style="color: #3A3B3C;" class="mx-3"></span> -->
- </div>
- </div>
- {{end}}
- {{define "extra_js"}}
- <script src="{{.StaticURL}}/vendor/datatables/jquery.dataTables.min.js"></script>
- <script src="{{.StaticURL}}/vendor/datatables/dataTables.bootstrap4.min.js"></script>
- <script src="{{.StaticURL}}/vendor/datatables/dataTables.buttons.min.js"></script>
- <script src="{{.StaticURL}}/vendor/datatables/buttons.bootstrap4.min.js"></script>
- <script src="{{.StaticURL}}/vendor/datatables/dataTables.fixedHeader.min.js"></script>
- <script src="{{.StaticURL}}/vendor/datatables/dataTables.responsive.min.js"></script>
- <script src="{{.StaticURL}}/vendor/datatables/responsive.bootstrap4.min.js"></script>
- <script src="{{.StaticURL}}/vendor/datatables/dataTables.checkboxes.min.js"></script>
- <script src="{{.StaticURL}}/vendor/lightbox2/js/lightbox.min.js"></script>
- <script src="{{.StaticURL}}/vendor/pdfobject/pdfobject.min.js"></script>
- <script src="{{.StaticURL}}/vendor/codemirror/codemirror.js"></script>
- <script src="{{.StaticURL}}/vendor/codemirror/meta.js"></script>
- <script src="{{.StaticURL}}/vendor/video-js/video.min.js"></script>
- {{if .HasIntegrations}}
- <script type="text/javascript">
- var childReference = null;
- var checkerStarted = false;
- const childProps = new Map();
- function openExternalURL(url, fileLink, fileName){
- if (childReference == null || childReference.closed) {
- childProps.set('link', fileLink);
- childProps.set('url', url);
- childProps.set('file_name', UnicodeDecodeB64(fileName));
- childReference = window.open(url, '_blank');
- if (!checkerStarted){
- keepAlive();
- setInterval(checkExternalWindow, 300000);
- checkerStarted = true;
- }
- } else {
- $('#errorTxt').text('An external window is already open, please close it before trying to open a new one');
- $('#errorMsg').show();
- setTimeout(function () {
- $('#errorMsg').hide();
- }, 8000);
- }
- }
- function notifyBlobDownloadError(message) {
- if (childReference == null || childReference.closed) {
- console.log("external window null or closed, cannot notify download error");
- return;
- }
- childReference.postMessage({
- type: 'blobDownloadError',
- message: message
- }, childProps.get('url'));
- }
- function notifySave(status, message) {
- if (childReference == null || childReference.closed) {
- console.log("external window null or closed, cannot notify save");
- return;
- }
- childReference.postMessage({
- type: 'blobSaveResult',
- status: status,
- message: message
- }, childProps.get('url'));
- }
- window.addEventListener('message', (event) => {
- var url = childProps.get('url');
- if (!url || !url.startsWith(event.origin)){
- console.log("origin: "+event.origin+" does not match the expected one: "+url+" refusing message");
- return;
- }
- if (childReference == null || childReference.closed) {
- console.log("external window null or closed, refusing message");
- return;
- }
- switch (event.data.type){
- case 'ready':
- // the child is ready send some details
- childReference.postMessage({
- type: 'readyResponse',
- user: '{{.LoggedUser.Username}}',
- file_name: childProps.get('file_name')
- }, childProps.get('url'));
- break;
- case 'sendBlob':
- // we have to download the blob, this could require some time so
- // we first send a blobDownloadStart message so the child can
- // show a spinner or something similar
- var errorMessage = "Error downloading file";
- childReference.postMessage({
- type: 'blobDownloadStart'
- }, childProps.get('url'));
- // download the file and send it as blob to the child window
- async function downloadFileAsBlob(){
- var errorMessage = "Error downloading file";
- let response;
- try {
- response = await fetch(childProps.get('link'),{
- headers: {
- 'X-CSRF-TOKEN': '{{.CSRFToken}}'
- },
- credentials: 'same-origin',
- redirect: 'error'
- });
- } catch (e){
- throw Error(errorMessage+": " +e.message);
- }
- if (response.status == 200){
- let responseBlob;
- try {
- responseBlob = await response.blob();
- } catch (e){
- throw Error(errorMessage+" as blob: " +e.message);
- }
- let fileBlob = new File([responseBlob], childProps.get('file_name'), {type: responseBlob.type, lastModified: ""});
- childReference.postMessage({
- type: 'blob',
- file: fileBlob
- }, childProps.get('url'));
- } else {
- let jsonResponse;
- try {
- jsonResponse = await response.json();
- } catch(e){
- throw Error(errorMessage);
- }
- if (jsonResponse.message) {
- errorMessage = jsonResponse.message;
- }
- if (jsonResponse.error) {
- errorMessage += ": " + jsonResponse.error;
- }
- throw Error(errorMessage);
- }
- }
- downloadFileAsBlob().catch(function(error){
- notifyBlobDownloadError(error.message);
- $('#errorTxt').text(error.message);
- $('#errorMsg').show();
- setTimeout(function () {
- $('#errorMsg').hide();
- }, 5000);
- });
- break;
- case 'saveBlob':
- spinnerDone = false;
- $('#spinnerModal').modal('show');
- async function saveBlob() {
- var errorMessage = "Error saving external file";
- var uploadPath = '{{.FileURL}}?path={{.CurrentDir}}'+encodeURIComponent("/"+unescapeHTML(childProps.get('file_name')));
- let response;
- try {
- response = await fetch(uploadPath, {
- method: 'POST',
- headers: {
- 'X-CSRF-TOKEN': '{{.CSRFToken}}'
- },
- credentials: 'same-origin',
- redirect: 'error',
- body: event.data.file
- });
- } catch (e){
- throw Error(errorMessage+": " +e.message);
- }
- if (response.status == 201){
- $('#spinnerModal').modal('hide');
- notifySave("OK", "");
- setTimeout(function () {
- location.reload();
- }, 2000);
- } else {
- let jsonResponse;
- try {
- jsonResponse = await response.json();
- } catch(e){
- throw Error(errorMessage);
- }
- if (jsonResponse.message) {
- errorMessage = jsonResponse.message;
- }
- if (jsonResponse.error) {
- errorMessage += ": " + jsonResponse.error;
- }
- throw Error(errorMessage);
- }
- }
- saveBlob().catch(function(error){
- $('#spinnerModal').modal('hide');
- notifySave("KO", error.message);
- $('#errorTxt').text(error.message);
- $('#errorMsg').show();
- setTimeout(function () {
- $('#errorMsg').hide();
- }, 5000);
- });
- break;
- default:
- console.log("Unsupported message: "+JSON.stringify(event.data));
- }
- });
- function checkExternalWindow() {
- if (childReference == null || childReference.closed) {
- return;
- }
- keepAlive();
- }
- </script>
- {{end}}
- <script type="text/javascript">
- var spinnerDone = false;
- var player;
- var playerKeepAlive;
- function shortenData(d, cutoff) {
- if ( typeof d !== 'string' ) {
- return d;
- }
- if ( d.length <= cutoff ) {
- return escapeHTML(d);
- }
- var shortened = d.substr(0, cutoff-1);
- return escapeHTML(shortened)+'…';
- }
- function openVideoPlayer(name, url, videoType){
- $("#video_title").text(UnicodeDecodeB64(name));
- $('#videoModal').modal('show');
- player.src({
- type: videoType,
- src: url
- });
- keepAlive();
- playerKeepAlive = setInterval(keepAlive, 300000);
- }
- function getIconForFile(filename) {
- var extension = filename.slice((filename.lastIndexOf(".") - 1 >>> 0) + 2).toLowerCase();
- switch (extension) {
- case "doc":
- case "docx":
- case "odt":
- case "wps":
- return "far fa-file-word";
- case "ppt":
- case "pptx":
- return "far fa-file-powerpoint";
- case "xls":
- case "xlsx":
- case "ods":
- return "far fa-file-excel";
- case "pdf":
- return "far fa-file-pdf";
- case "webm":
- case "mkv":
- case "flv":
- case "vob":
- case "ogv":
- case "ogg":
- case "avi":
- case "ts":
- case "mov":
- case "wmv":
- case "asf":
- case "mpeg":
- case "mpv":
- case "3gp":
- case "mp4":
- return "far fa-file-video";
- case "jpeg":
- case "jpg":
- case "png":
- case "gif":
- case "webp":
- case "tiff":
- case "psd":
- case "bmp":
- case "svg":
- case "jp2":
- return "far fa-file-image";
- case "go":
- case "sh":
- case "bat":
- case "java":
- case "php":
- case "cs":
- case "asp":
- case "aspx":
- case "css":
- case "html":
- case "xhtml":
- case "htm":
- case "js":
- case "jsp":
- case "py":
- case "rb":
- case "cgi":
- case "c":
- case "cpp":
- case "h":
- case "hpp":
- case "kt":
- case "ktm":
- case "kts":
- case "swift":
- case "r":
- return "far fa-file-code";
- case "zip":
- case "zipx":
- case "rar":
- case "tar":
- case "gz":
- case "bz2":
- case "zstd":
- case "zst":
- case "sz":
- case "lz":
- case "lz4":
- case "xz":
- case "jar":
- return "far fa-file-archive";
- case "txt":
- case "rtf":
- case "json":
- case "xml":
- case "yaml":
- case "toml":
- case "log":
- case "csv":
- case "ini":
- case "cfg":
- return "far fa-file-alt";
- default:
- return "far fa-file";
- }
- }
- function getNameFromMeta(meta) {
- return meta.split('_').slice(1).join('_');
- }
- function getTypeFromMeta(meta) {
- return meta.split('_')[0];
- }
- function deleteAction() {
- var table = $('#dataTable').DataTable();
- table.button('delete:name').enable(false);
- var selectedItems = table.column(0).checkboxes.selected()
- var has_errors = false;
- var index = 0;
- var success = 0;
- spinnerDone = false;
- $('#deleteModal').modal('hide');
- $('#spinnerModal').modal('show');
- function deleteItem() {
- if (index >= selectedItems.length || has_errors){
- $('#spinnerModal').modal('hide');
- spinnerDone = true;
- if (!has_errors){
- location.reload();
- } else {
- table.button('delete:name').enable(true);
- }
- return;
- }
- var selected = selectedItems[index];
- var itemType = getTypeFromMeta(selected);
- var itemName = getNameFromMeta(selected);
- var path;
- if (itemType == "1"){
- path = '{{.DirsURL}}';
- } else {
- path = '{{.FilesURL}}';
- }
- path+='?path={{.CurrentDir}}'+encodeURIComponent("/"+itemName);
- $.ajax({
- url: path,
- type: 'DELETE',
- dataType: 'json',
- headers: { 'X-CSRF-TOKEN': '{{.CSRFToken}}' },
- timeout: 60000,
- success: function (result) {
- index++;
- success++;
- deleteItem();
- },
- error: function ($xhr, textStatus, errorThrown) {
- index++;
- has_errors = true;
- var txt = "Unable to delete the selected item/s";
- if (success > 0){
- txt = "Not all the selected items have been deleted, please reload the page";
- }
- if ($xhr) {
- var json = $xhr.responseJSON;
- if (json) {
- if (json.message) {
- txt = json.message;
- }
- if (json.error) {
- txt += ": " + json.error;
- }
- }
- }
- $('#errorTxt').text(txt);
- $('#errorMsg').show();
- setTimeout(function () {
- $('#errorMsg').hide();
- }, 10000);
- deleteItem();
- }
- });
- }
- deleteItem();
- }
- function keepAlive() {
- $.ajax({
- url: '{{.ProfileURL}}',
- timeout: 15000
- });
- }
- $(document).ready(function () {
- player = videojs('video_player', {
- controls: true,
- autoplay: false,
- preload: 'auto'
- });
- $('#videoModal').on('hide.bs.modal', function () {
- player.pause();
- player.reset();
- if (playerKeepAlive != null){
- clearInterval(playerKeepAlive);
- }
- });
- $('#spinnerModal').on('shown.bs.modal', function () {
- if (spinnerDone){
- $('#spinnerModal').modal('hide');
- }
- });
- $("#create_dir_form").submit(function (event) {
- event.preventDefault();
- $('#createDirModal').modal('hide');
- var dirName = replaceSlash($("#directory_name").val());
- var path = '{{.DirsURL}}?path={{.CurrentDir}}' + encodeURIComponent("/"+dirName);
- $.ajax({
- url: path,
- type: 'POST',
- dataType: 'json',
- headers: { 'X-CSRF-TOKEN': '{{.CSRFToken}}' },
- timeout: 15000,
- success: function (result) {
- location.reload();
- },
- error: function ($xhr, textStatus, errorThrown) {
- var txt = "Unable to create the requested directory";
- if ($xhr) {
- var json = $xhr.responseJSON;
- if (json) {
- if (json.message) {
- txt = json.message;
- }
- if (json.error) {
- txt += ": " + json.error;
- }
- }
- }
- $('#errorTxt').text(txt);
- $('#errorMsg').show();
- setTimeout(function () {
- $('#errorMsg').hide();
- }, 5000);
- }
- });
- });
- $("#upload_files_form").submit(function (event){
- event.preventDefault();
- keepAlive();
- var keepAliveTimer = setInterval(keepAlive, 300000);
- var files = $("#files_name")[0].files;
- var has_errors = false;
- var index = 0;
- var success = 0;
- spinnerDone = false;
- $('#uploadFilesModal').modal('hide');
- $('#spinnerModal').modal('show');
- function uploadFile() {
- if (index >= files.length || has_errors){
- //console.log("upload done, index: "+index+" has errors: "+has_errors+" ok: "+success);
- clearInterval(keepAliveTimer);
- $('#spinnerModal').modal('hide');
- spinnerDone = true;
- if (!has_errors){
- location.reload();
- }
- return;
- }
- async function saveFile() {
- //console.log("save file, index: "+index);
- var errorMessage = "Error uploading files";
- let response;
- try {
- var f = files[index];
- var uploadPath = '{{.FileURL}}?path={{.CurrentDir}}'+encodeURIComponent("/"+f.name);
- var lastModified;
- try {
- lastModified = f.lastModified;
- } catch (e) {
- console.log("unable to get last modified time from file: "+e.message);
- lastModified = "";
- }
- response = await fetch(uploadPath, {
- method: 'POST',
- headers: {
- 'X-SFTPGO-MTIME': lastModified,
- 'X-CSRF-TOKEN': '{{.CSRFToken}}'
- },
- credentials: 'same-origin',
- redirect: 'error',
- body: f
- });
- } catch (e){
- throw Error(errorMessage+": " +e.message);
- }
- if (response.status == 201){
- index++;
- success++;
- uploadFile();
- } else {
- let jsonResponse;
- try {
- jsonResponse = await response.json();
- } catch(e){
- throw Error(errorMessage);
- }
- if (jsonResponse.message) {
- errorMessage = jsonResponse.message;
- }
- if (jsonResponse.error) {
- errorMessage += ": " + jsonResponse.error;
- }
- throw Error(errorMessage);
- }
- }
- saveFile().catch(function(error){
- index++;
- has_errors = true;
- $('#errorTxt').text(error.message);
- $('#errorMsg').show();
- setTimeout(function () {
- $('#errorMsg').hide();
- }, 10000);
- uploadFile();
- });
- }
- uploadFile();
- });
- $("#rename_form").submit(function (event){
- event.preventDefault();
- var table = $('#dataTable').DataTable();
- table.button('rename:name').enable(false);
- var selected = table.column(0).checkboxes.selected()[0];
- var itemType = getTypeFromMeta(selected);
- var itemName = getNameFromMeta(selected);
- var targetName = replaceSlash($("#rename_new_name").val());
- var targetDir = $("#rename_new_dir").val();
- if (targetDir != "/") {
- targetDir = targetDir.endsWith('/') ? targetDir.slice(0, -1) : targetDir;
- }
- if (targetDir.trim() == ""){
- targetDir = "{{.CurrentDir}}";
- } else {
- targetDir = encodeURIComponent(targetDir);
- }
- var path;
- if (itemType == "1"){
- path = '{{.DirsURL}}';
- } else {
- path = '{{.FilesURL}}';
- }
- path+='?path={{.CurrentDir}}'+encodeURIComponent("/"+itemName)+'&target='+targetDir+encodeURIComponent("/"+targetName);
- $('#renameModal').modal('hide');
- $.ajax({
- url: path,
- type: 'PATCH',
- dataType: 'json',
- headers: { 'X-CSRF-TOKEN': '{{.CSRFToken}}' },
- timeout: 15000,
- success: function (result) {
- location.reload();
- },
- error: function ($xhr, textStatus, errorThrown) {
- var txt = "Error renaming item";
- if ($xhr) {
- var json = $xhr.responseJSON;
- if (json) {
- if (json.message) {
- txt = json.message;
- }
- if (json.error) {
- txt += ": " + json.error;
- }
- }
- }
- $('#errorTxt').text(txt);
- $('#errorMsg').show();
- setTimeout(function () {
- $('#errorMsg').hide();
- }, 8000);
- var selectedItems = table.column(0).checkboxes.selected().length;
- table.button('rename:name').enable(selectedItems == 1);
- }
- });
- });
- $.fn.dataTable.ext.buttons.refresh = {
- text: '<i class="fas fa-sync-alt"></i>',
- name: 'refresh',
- titleAttr: "Refresh",
- action: function (e, dt, node, config) {
- location.reload();
- }
- };
- $.fn.dataTable.ext.buttons.download = {
- text: '<i class="fas fa-download"></i>',
- name: 'download',
- titleAttr: "Download Zip",
- action: function (e, dt, node, config) {
- var filesArray = [];
- var selected = dt.column(0).checkboxes.selected();
- for (i = 0; i < selected.length; i++) {
- filesArray.push(getNameFromMeta(selected[i]));
- }
- var files = encodeURIComponent(JSON.stringify(filesArray));
- var downloadURL = '{{.DownloadURL}}';
- var currentDir = '{{.CurrentDir}}';
- var ts = new Date().getTime().toString();
- window.location = `${downloadURL}?path=${currentDir}&files=${files}&_=${ts}`;
- },
- enabled: false
- };
- $.fn.dataTable.ext.buttons.addFiles = {
- text: '<i class="fas fa-file-upload"></i>',
- name: 'addFiles',
- titleAttr: "Upload files",
- action: function (e, dt, node, config) {
- document.getElementById("files_name").value = null;
- $('#uploadFilesModal').modal('show');
- },
- enabled: true
- };
- $.fn.dataTable.ext.buttons.addDirectory = {
- text: '<i class="fas fa-folder-plus"></i>',
- name: 'addDirectory',
- titleAttr: "Add directory",
- action: function (e, dt, node, config) {
- $("#directory_name").val("");
- $('#createDirModal').modal('show');
- },
- enabled: true
- };
- $.fn.dataTable.ext.buttons.rename = {
- text: '<i class="fas fa-pen"></i>',
- name: 'rename',
- titleAttr: "Rename",
- action: function (e, dt, node, config) {
- var selected = table.column(0).checkboxes.selected()[0];
- var itemName = getNameFromMeta(selected);
- $("#rename_old_name").val(itemName);
- $("#rename_new_dir").val(decodeURIComponent("{{.CurrentDir}}".replace(/\+/g, '%20')));
- $("#rename_new_name").val("");
- $('#renameModal').modal('show');
- },
- enabled: false
- };
- $.fn.dataTable.ext.buttons.delete = {
- text: '<i class="fas fa-trash"></i>',
- name: 'delete',
- titleAttr: "Delete",
- action: function (e, dt, node, config) {
- $('#deleteModal').modal('show');
- },
- enabled: false
- };
- $.fn.dataTable.ext.buttons.share = {
- text: '<i class="fas fa-share-alt"></i>',
- name: 'share',
- titleAttr: "Share",
- action: function (e, dt, node, config) {
- var filesArray = [];
- var selected = dt.column(0).checkboxes.selected();
- for (i = 0; i < selected.length; i++) {
- filesArray.push(getNameFromMeta(selected[i]));
- }
- var files = encodeURIComponent(JSON.stringify(filesArray));
- var shareURL = '{{.ShareURL}}';
- var currentDir = '{{.CurrentDir}}';
- var ts = new Date().getTime().toString();
- window.location = `${shareURL}?path=${currentDir}&files=${files}&_=${ts}`;
- },
- enabled: false
- };
- var table = $('#dataTable').DataTable({
- "ajax": {
- "url": "{{.DirsURL}}?path={{.CurrentDir}}",
- "dataSrc": "",
- "error": function ($xhr, textStatus, errorThrown) {
- $(".dataTables_processing").hide();
- var txt = "Failed to get directory listing";
- if ($xhr) {
- var json = $xhr.responseJSON;
- if (json) {
- if (json.message){
- txt += ": " + json.message;
- } else {
- txt += ": " + json.error;
- }
- }
- }
- $('#errorTxt').text(txt);
- $('#errorMsg').show();
- setTimeout(function () {
- $('#errorMsg').hide();
- }, 10000);
- }
- },
- "deferRender": true,
- "processing": true,
- "lengthMenu": [ 10, 25, 50, 100, 250, 500 ],
- "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 = "";
- }
- data.checkboxes = [];
- },
- "columns": [
- { "data": "meta" },
- { "data": "type" },
- {
- "data": "name",
- "render": function (data, type, row) {
- if (type === 'display') {
- var title = "";
- var cssClass = "";
- var shortened = shortenData(data, 70);
- data = escapeHTML(data);
- if (shortened != data){
- title = data;
- cssClass = "ellipsis";
- }
- if (row["type"] == "1") {
- return `<i class="fas fa-folder"></i> <a class="${cssClass}" href="${row['url']}" title="${title}">${shortened}</a>`;
- }
- if (row["size"] == "") {
- return `<i class="fas fa-external-link-alt"></i> <a class="${cssClass}" href="${row['url']}" title="${title}">${shortened}</a>`;
- }
- var icon = getIconForFile(data);
- return `<i class="${icon}"></i> <a class="${cssClass}" href="${row['url']}" title="${title}">${shortened}</a>`;
- }
- return data;
- }
- },
- { "data": "size" },
- { "data": "last_modified" },
- { "data": "edit_url",
- "render": function (data, type, row) {
- if (type === 'display') {
- var filename = escapeHTML(row["name"]);
- var extension = filename.slice((filename.lastIndexOf(".") - 1 >>> 0) + 2).toLowerCase();
- if (data){
- if (extension == "csv" || extension == "bat" || CodeMirror.findModeByExtension(extension) != null){
- {{if .CanAddFiles}}
- return `<a href="${data}"><i class="fas fa-edit"></i></a>`;
- {{else}}
- return `<a href="${data}"><i class="fas fa-eye"></i></a>`;
- {{end}}
- }
- }
- if (row["type"] == "2") {
- switch (extension) {
- case "jpeg":
- case "jpg":
- case "png":
- case "gif":
- case "webp":
- case "bmp":
- case "svg":
- case "ico":
- var title = escapeHTMLForceSafe(row["name"])
- return `<a href="${row['url']}" data-lightbox="image-gallery" data-title="${title}"><i class="fas fa-eye"></i></a>`;
- case "mp4":
- case "mov":
- var name = b64EncodeUnicode(row["name"]);
- return `<a href="#" onclick="openVideoPlayer('${name}', '${row['url']}', 'video/mp4');"><i class="fas fa-eye"></i></a>`;
- case "webm":
- var name = b64EncodeUnicode(row["name"]);
- return `<a href="#" onclick="openVideoPlayer('${name}', '${row['url']}', 'video/webm');"><i class="fas fa-eye"></i></a>`;
- case "ogv":
- case "ogg":
- var name = b64EncodeUnicode(row["name"]);
- return `<a href="#" onclick="openVideoPlayer('${name}}', '${row['url']}', 'video/ogg');"><i class="fas fa-eye"></i></a>`;
- case "pdf":
- if (PDFObject.supportsPDFs){
- var view_url = row['url'];
- view_url = view_url.replace('{{.FilesURL}}','{{.ViewPDFURL}}');
- return `<a href="${view_url}" target="_blank"><i class="fas fa-eye"></i></a>`;
- }
- }
- }
- }
- return "";
- }
- },
- { "data": "ext_url",
- "render": function (data, type, row) {
- {{if .HasIntegrations}}
- if (type === 'display') {
- if (data){
- var name = b64EncodeUnicode(escapeHTML(row["name"]));
- return `<a href="#" onclick="openExternalURL('${data}', '${row["ext_link"]}', '${name}');"><i class="fas fa-external-link-alt"></i></a>`;
- }
- }
- {{end}}
- return "";
- }
- }
- ],
- "buttons": [],
- "lengthChange": true,
- "columnDefs": [
- {
- "targets": [0],
- "checkboxes": {
- "selectCallback": function (nodes, selected) {
- var selectedItems = table.column(0).checkboxes.selected().length;
- var selectedText = "";
- if (selectedItems == 1) {
- selectedText = "1 item selected";
- } else if (selectedItems > 1) {
- selectedText = `${selectedItems} items selected`;
- }
- {{if .CanDownload}}
- table.button('download:name').enable(selectedItems > 0);
- {{end}}
- {{if .CanRename}}
- table.button('rename:name').enable(selectedItems == 1);
- {{end}}
- {{if .CanDelete}}
- table.button('delete:name').enable(selectedItems > 0);
- {{end}}
- {{if .CanShare}}
- table.button('share:name').enable(selectedItems > 0);
- {{end}}
- $('#dataTable_info').find('span').remove();
- $("#dataTable_info").append('<span class="selected-info"><span class="selected-item">' + selectedText + '</span></span>');
- }
- },
- "orderable": false,
- "searchable": false
- },
- {
- "targets": [1],
- "visible": false,
- "searchable": false
- },
- {
- "targets": [3, 4],
- "searchable": false
- },
- {
- "targets": [5, 6],
- "orderable": false,
- "searchable": false
- }
- ],
- "scrollX": false,
- "scrollY": false,
- "responsive": true,
- "language": {
- "loadingRecords": "",
- "emptyTable": "No files or folders"
- },
- "initComplete": function (settings, json) {
- table.button().add(0, 'refresh');
- //table.button().add(0, 'pageLength');
- {{if .CanShare}}
- table.button().add(0, 'share');
- {{end}}
- {{if .CanDownload}}
- table.button().add(0, 'download');
- {{end}}
- {{if .CanDelete}}
- table.button().add(0, 'delete');
- {{end}}
- {{if .CanRename}}
- table.button().add(0, 'rename');
- {{end}}
- {{if .CanCreateDirs}}
- table.button().add(0, 'addDirectory');
- {{end}}
- {{if .CanAddFiles}}
- table.button().add(0, 'addFiles');
- {{end}}
- table.buttons().container().appendTo('.col-md-6:eq(0)', table.table().container());
- },
- "orderFixed": [1, 'asc'],
- "order": [2, 'asc']
- });
- new $.fn.dataTable.FixedHeader(table);
- $.fn.dataTable.ext.errMode = 'none';
- });
- </script>
- {{end}}
|