VvebOIDC/public/admin/default/libs/media/media.js

1213 lines
33 KiB
JavaScript

function ucFirst(str) {
if (!str) return str;
return str[0].toUpperCase() + str.slice(1);
}
/*
var mediaPath = "/public/media/";
var mediaScanUrl = "scan.php";
var uploadUrl = "upload.php";
*/
function fileExtension(filename) {
return filename.split('.').pop();
}
let videoExtensions = ['mp4', 'webm', 'mov', 'ogg', 'mkv', 'flv', 'avi', '3gp', 'mpg', 'mpeg'];
function isVideo(filename) {
return videoExtensions.indexOf(fileExtension(filename)) != -1;
}
function clearMedia(id = "featured-image") {
document.getElementById(id + "-input").value = "";
document.getElementById(id + "-thumb").setAttribute("src", "../media/placeholder.svg");
}
class MediaModal {
constructor (modal = true)
{
this.isInit = false;
this.isModal = modal;
this.modalHtml =
`
<div class="modal fade modal-full" id="MediaModal" tabindex="-1" role="dialog" aria-labelledby="MediaModalLabel" aria-hidden="true">
<div class="modal-dialog modal-xl modal-dialog-scrollable" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title fw-normal" id="MediaModalLabel">Media</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close">
<!-- <span aria-hidden="true"><i class="la la-times la-lg"></i></span> -->
</button>
</div>
<div class="modal-body">
<div class="filemanager">
<div class="top-right d-flex justify-content-between">
<div class="">
<div class="breadcrumbs"></div>
</div>
<div class="">
<div class="search">
<input type="search" id="media-search-input" placeholder="Find a file.." />
</div>
<button class="btn btn-outline-secondary btn-sm btn-icon me-5 float-end"
data-bs-toggle="collapse"
data-bs-target=".upload-collapse"
aria-expanded="false"
>
<i class="la la-upload la-lg"></i>
Upload file
</button>
</div>
</div>
<div class="top-panel">
<div class="upload-collapse collapse">
<button id="upload-close" type="button" class="btn btn-sm" aria-label="Close" data-bs-toggle="collapse" data-bs-target=".upload-collapse" aria-expanded="true">
<span aria-hidden="true"><i class="la la-times la-lg"></i></span>
</button>
<h3>Drop or choose files to upload</h3>
<input type="file" multiple class="">
<div class="status"></div>
</div>
</div>
<div class="display-panel">
<ul class="data" id="media-files"></ul>
<div class="nothingfound" style="display:none">
<div class="nofiles">
<i class="la la-folder-open"></i>
</div>
<div>No files here.</div>
<div class="mt-4">
<button class="btn btn-outline-secondary btn-sm btn-icon" data-bs-toggle="collapse" data-bs-target=".upload-collapse" aria-expanded="false">
<i class="la la-upload la-lg"></i>
Upload file
</button>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer justify-content-between">
<div class="align-left">
</div>
<div class="align-right">
<button type="button" class="btn btn-secondary btn-icon me-1" data-bs-dismiss="modal">
<i class="icon-close"></i>
<span>Cancel</span>
</button>
<button type="button" class="btn btn-primary btn-icon save-btn">
<i class="icon-add"></i>
<span>Add selected</span>
</button>
</div>
</div>
</div>
</div>
</div>`;
this.response = [],
this.currentPath = '';
this.breadcrumbsUrls = [];
this.filemanager = null;
this.breadcrumbs = null;
this.fileList = null;
this.mediaPath = mediaPath;
this.type = "single";
this.currentMedia;
}
addModalHtml() {
if (this.isModal) document.body.append(generateElements(this.modalHtml)[0]);
document.querySelector("#MediaModal .save-btn").addEventListener("click", () => this.save());
}
showUploadLoading() {
document.querySelector("#MediaModal .upload-collapse .status").innerHTML = `
<div class="spinner-border" style="width: 5rem; height: 5rem;margin: 5rem auto; display:block" role="status">
<span class="visually-hidden">Loading...</span>
</div>`;
}
hideUploadLoading() {
document.querySelector("#MediaModal .upload-collapse .status").innerHTML = '';
}
save() {
let files = [];
let file = "";
let src = "";
if (this.type == "single") {
file = document.querySelector("#MediaModal .files input:checked").value ?? false;
if (!file) return;
if (file.indexOf("//") == -1) {
src = this.mediaPath + file;
}
files.push(file);
if (this.targetThumb) {
document.querySelector(this.targetThumb)?.setAttribute("src", src);
}
} else {
document.querySelectorAll("#MediaModal .files input:checked").forEach(e => {
files.push(e.value);
src += this.mediaPath + e.value + ",";
file += e.value + ",";
});
}
if (this.callback) {
this.callback(src, file, files);
}
if (this.targetInput) {
let input = document.querySelector(this.targetInput);
input.value = file;
const e = new Event("change",{bubbles: true});
input.dispatchEvent(e);
}
document.querySelectorAll("#MediaModal .files input:checked").forEach(e => e.checked = false);
let modal = bootstrap.Modal.getOrCreateInstance(document.getElementById('MediaModal'));
if (this.isModal) modal.hide();
}
init() {
if (!this.isInit) {
if (this.isModal) this.addModalHtml();
let self = this;
this.initGallery();
this.isInit = true;
document.querySelector(".filemanager input[type=file]").addEventListener("change", this.onUpload);
document.getElementById("bulk-delete").addEventListener("click", e => self.deleteFile());
document.querySelector(".filemanager").addEventListener("click", function (e) {
let element = e.target.closest(".btn-delete");
if (element) {
// self.deleteFile(element);
} else {
element = e.target.closest(".btn-rename");
if (element) {
// self.editMedia(element);
// e.preventDefault();
// e.stopImmediatePropagation();
return;
} else {
element = e.target.closest(".btn-new-folder");
if (element) {
self.newFolder(element);
}
}
}
});
let offcanvas = document.querySelector("#media-offcanvas");
offcanvas?.addEventListener("click", function (e) {
let element = e.target.closest(".save-btn");
if (element) {
self.saveMediaContent(element);
} else {
element = e.target.closest("#next-media");
if (element) {
self.nextMedia(element);
} else {
element = e.target.closest("#prev-media");
if (element) {
self.prevMedia(element);
}
}
}
});
const event = new CustomEvent( "mediaModal:init", {detail: { type:this.type, targetInput:this.targetInput, targetThumb:this.targetThumb, callback:this.callback} });
window.dispatchEvent(event);
}
}
open(element, callback) {
if (element instanceof Element) {
this.targetInput = element.dataset.targetInput;
this.targetThumb = element.dataset.targetThumb;
if (element.dataset.type) {
this.type = element.dataset.type;
}
} else if (element) {
this.targetInput = element.targetInput;
this.targetThumb = element.targetThumb;
if (element.type) {
this.type = element.type;
}
}
this.callback = callback;
this.init();
if (this.type == "single") {
document.querySelectorAll("#MediaModal .files input[type=checkbox]").forEach(e => e.setAttribute("type", "radio"));
} else {
document.querySelectorAll("#MediaModal .files input[type=radio]").forEach(e => e.setAttribute("type", "checkbox"));
}
let modal = bootstrap.Modal.getOrCreateInstance(document.getElementById('MediaModal'));
if (this.isModal) modal.show();
}
initGallery() {
this.filemanager = document.querySelector('.filemanager'),
this.breadcrumbs = document.querySelector('.breadcrumbs'),
this.fileList = this.filemanager.querySelector('.data');
let _this = this;
// Start by fetching the file data from scan.php with an AJAX request
fetch(mediaScanUrl)
.then((response) => {
if (!response.ok) { throw new Error(response) }
return response.json();
})
.then((data) => {
_this.response = [data],
_this.currentPath = '',
_this.breadcrumbsUrls = [];
let folders = [],
files = [];
window.dispatchEvent(new HashChangeEvent("hashchange"));
})
.catch(error => {
console.log(error.statusText);
displayToast("danger", "Error", "Error loading media!", "top");
});
// This event listener monitors changes on the URL. We use it to
// capture back/forward navigation in the browser.
window.addEventListener('hashchange', function(){
_this.goto(window.location.hash);
// We are triggering the event. This will execute
// this function on page load, so that we show the correct folder:
});
// Hiding and showing the search box
let search = this.filemanager.querySelector('input[type=search]');
this.filemanager.querySelector('.search').addEventListener("click", function(e) {
let _search = this;
_search.querySelectorAll('span').forEach(function (el,i) { el.style.display = "none";});
search.style.display = "block";
search.focus();
});
// Listening for keyboard input on the search field.
// We are using the "input" event which detects cut and paste
// in addition to keyboard input.
search.addEventListener('input', function(e) {
let folders = [];
let files = [];
let value = this.value.trim();
if(value.length) {
_this.filemanager.classList.add('searching');
// Update the hash on every key stroke
window.location.hash = 'search=' + value.trim();
}
else {
_this.filemanager.classList.remove('searching');
window.location.hash = encodeURIComponent(_this.currentPath);
}
});
search.addEventListener('keyup', function(e) {
// Clicking 'ESC' button triggers focusout and cancels the search
let search = this;
if(e.keyCode == 27) {
search.trigger('focusout');
}
});
search.addEventListener("focusout", function(e) {
// Cancel the search
let search = this;
if(!search.value.trim().length) {
window.location.hash = encodeURIComponent(_this.currentPath);
search.style.display = 'none';
search.parentNode.querySelectorAll('span').style.display = '';
}
});
// Clicking on folders
let self = this;
this.fileList.addEventListener('click', function(e) {
let el = e.target.closest(".btn-delete");
if (el) {
self.deleteFile(el);
} else {
el = e.target.closest(".btn-rename");
if (el) {
self.editMedia(el);
e.preventDefault();
e.stopImmediatePropagation();
return;
} else {
el = e.target.closest(".btn-new-folder");
if (el) {
self.newFolder(el);
} else {
el = event.target.closest('li.folders');
if (el) {
e.preventDefault();
let nextDir = el.querySelector('a').getAttribute('href');
if(_this.filemanager.classList.contains('searching')) {
// Building the this.breadcrumbs
_this.breadcrumbsUrls = _this.generateBreadcrumbs(nextDir);
_this.filemanager.classList.remove('searching');
let search = _this.filemanager.querySelector('input[type=search]');
search.val('')
search.style.display = 'none';
_this.filemanager.querySelectorAll('span').forEach(e => e.style.display = '');
}
else {
_this.breadcrumbsUrls.push(nextDir);
}
window.location.hash = encodeURIComponent(nextDir);
_this.currentPath = nextDir;
}
}
}
}
});
// Clicking on this.breadcrumbs
this.breadcrumbs.addEventListener('click', function(e){
let el = event.target.closest('a');
if (el) {
e.preventDefault();
let index = [...el.parentNode.children].indexOf(el),
nextDir = _this.breadcrumbsUrls[index];
nextDir = el.getAttribute("href");
_this.breadcrumbsUrls.length = Number(index);
window.location.hash = encodeURIComponent(nextDir);
}
});
}
// Navigates to the given hash (path)
goto(hash) {
hash = decodeURIComponent(hash).slice(1).split('=');
let _this = this;
if (hash.length) {
let rendered = '';
// if hash has search in it
if (hash[0] === 'search') {
this.filemanager.classList.add('searching');
rendered = _this.searchData(_this.response, hash[1].toLowerCase());
if (rendered.length) {
this.currentPath = hash[0];
this.render(rendered);
}
else {
this.render(rendered);
}
}
// if hash is some path
else if (hash[0].trim().length) {
rendered = this.searchByPath(hash[0]);
if (rendered.length) {
this.currentPath = hash[0];
this.breadcrumbsUrls = this.generateBreadcrumbs(hash[0]);
this.render(rendered);
}
else {
this.currentPath = hash[0];
this.breadcrumbsUrls = this.generateBreadcrumbs(hash[0]);
this.render(rendered);
}
}
// if there is no hash
else {
this.currentPath = this.response[0].path;
this.breadcrumbsUrls.push(this.response[0].path);
this.render(this.searchByPath(this.response[0].path));
}
}
}
// Splits a file path and turns it into clickable breadcrumbs
_
generateBreadcrumbs(nextDir){
let path = nextDir.split('/').slice(0);
for(let i=1;i<path.length;i++){
path[i] = path[i-1]+ '/' +path[i];
}
return path;
}
// Locates a file by path
searchByPath(dir) {
let path = dir.split('/'),
demo = this.response,
flag = 0;
for(let i=0;i<path.length;i++){
for(let j=0;j<demo.length;j++){
if(demo[j].name === path[i]){
flag = 1;
demo = demo[j].items;
break;
}
}
}
//demo = flag ? demo : [];
return demo;
}
// Recursively search through the file tree
searchData(data, searchTerms) {
let _this = this;
let folders = [];
let files = [];
let _searchData = function (data, searchTerms) {
data.forEach(function(d){
if(d.type === 'folder') {
_searchData(d.items,searchTerms);
if(d.name.toLowerCase().indexOf(searchTerms) >= 0) {
folders.push(d);
}
}
else if(d.type === 'file') {
if(d.name.toLowerCase().indexOf(searchTerms) >= 0) {
files.push(d);
}
}
});
};
_searchData(data, searchTerms);
return {folders: folders, files: files};
}
onUpload(event) {
const data = new FormData();
let size = 0;
for (const file of this.files) {
data.append("files[]", file, file.name);
size += file.size;
}
data.append("mediaPath", Vvveb.MediaModal.mediaPath + Vvveb.MediaModal.currentPath);
data.append("onlyFilename", true);
data.append("size", size);
data.append("csrf", document.querySelector("[name='csrf']")?.value);
if (typeof uploadMaxFilesize !== "undefined" && uploadMaxFilesize && (size > parseInt(uploadMaxFilesize))) {
displayToast("danger", "Error", "File size bigger than upload max file size!", "top");
}
if (typeof postMaxSize !== "undefined" && postMaxSize && (size > parseInt(postMaxSize))) {
displayToast("danger", "Error", "File size bigger than post max size!", "top");
}
return fetch(uploadUrl, {
method: "POST",
body: data,
}).then((response) => {
if (!response.ok) { return Promise.reject(response); }
return response.json()
}).then((response) => {
for (const data of response) {
Vvveb.MediaModal.hideUploadLoading();
if (data.success) {
displayToast("success", "Success", data.message, "top");
} else {
displayToast("danger", "Error", data.message, "top");
}
if (!data.file) continue;
let fileElement = Vvveb.MediaModal.addFile({
name:data.file,
size:data.size ?? 0,
type:"file",
path: Vvveb.MediaModal.currentPath + "/" + data.file,
},true);
fileElement.scrollIntoView({behavior: "smooth", block: "center", inline: "center"});
}
document.querySelector(".nothingfound").style.display = "none";
})
.catch(error => {
let message = error.statusText ?? "Error uploading!";
Vvveb.MediaModal.hideUploadLoading();
displayToast("danger", "Error", message, "top");
error.text().then( errorMessage => {
let message = errorMessage.substr(0, 200);
displayToast("danger", "Error", message, "top");
});
});
/*
if (this.files && this.files[0]) {
Vvveb.MediaModal.showUploadLoading();
let file;
for (file of this.files) {
let reader = new FileReader();
reader.onload = (e) => imageIsLoaded(e, file);
reader.readAsDataURL(file);
}
}
*/
function imageIsLoaded(e, file) {
let image = e.target.result;
let formData = new FormData();
formData.append("file", file);
formData.append("mediaPath", Vvveb.MediaModal.mediaPath + Vvveb.MediaModal.currentPath);
formData.append("onlyFilename", true);
formData.append("csrf", document.querySelector("[name='csrf']")?.value);
fetch(uploadUrl, {method: "POST", body: formData})
.then((response) => {
if (!response.ok) {
return Promise.resolve(response.text()).then((responseInText) => {
return Promise.reject([response, responseInText]);
});
}
return response.json();
})
.then((data) => {
let fileElement = Vvveb.MediaModal.addFile({
name:data.file,
type:"file",
path: Vvveb.MediaModal.currentPath + "/" + data.file,
size:1
},true);
fileElement.scrollIntoView({behavior: "smooth", block: "center", inline: "center"});
Vvveb.MediaModal.hideUploadLoading();
if (data.success) {
displayToast("success", "Success", data.message, "top");
} else {
displayToast("danger", "Error", data.message, "top");
}
})
.catch(error => {
let [response, responseInText] = error;
let message = response.statusText ?? "Error uploading!";
Vvveb.MediaModal.hideUploadLoading();
displayToast("danger", "Error uploading!", message.substr(0, 200), "top");
});
}
}
deleteFile(el = null) {
let parent, file, message;
if (el) {
parent = el.closest("li");
file = parent.querySelector('input[type="hidden"]').value;
message = `Are you sure you want to delete "${file}"?`;
} else {
file = [];
parent = [];
document.querySelectorAll('input[type="checkbox"][name="file[]"]:checked').forEach((e, i) => {
file.push(e.value);
parent.push(e.closest("li"));
});
if (!file.length) {
alert("No files selected!");
return;
}
message = "Are you sure you want to delete selected files?";
}
if (confirm(message)) {
const data = new FormData();
if (Array.isArray(parent)) {
for (const f of file) data.append("file[]", f);
} else {
data.append("file", file);
}
data.append("csrf", document.querySelector("[name='csrf']")?.value);
fetch(deleteUrl, {method: "POST", body: data})
.then((response) => {
if (!response.ok) { return Promise.reject(response); }
return response.json();
})
.then((data) => {
let bg = "success";
if (data.success) {
if (Array.isArray(parent)) {
for (const e of parent) e.remove();
} else {
parent.remove();
}
} else {
bg = "danger";
}
displayToast(bg, "Delete", data.message, "top");
})
.catch(error => {
console.log(error);
let message = error.statusText ?? "Error deleting file!";
displayToast("danger", "Error", message, "top");
error.text().then( errorMessage => {
let message = errorMessage.substr(0, 200);
displayToast("danger", "Error", message, "top");
});
});
}
}
enableNavigateBtns(media) {
let nextMedia = media?.nextElementSibling?.closest(".files") ?? false;
let prevMedia = media?.previousElementSibling?.closest(".files") ?? false;
let nextBtn = document.getElementById("next-media");
let prevBtn = document.getElementById("prev-media");
if (nextMedia) {
nextBtn.disabled = false;
} else {
nextBtn.disabled = true;
nextMedia = false;
}
if (prevMedia) {
prevBtn.disabled = false;
} else {
prevBtn.disabled = true;
prevMedia = false;
}
}
navigateMedia(media, next = true) {
let nextMedia = media?.nextElementSibling?.closest(".files") ?? false;
let prevMedia = media?.previousElementSibling?.closest(".files") ?? false;
if (next && nextMedia) {
this.currentMedia = nextMedia;
} else if (prevMedia) {
this.currentMedia = prevMedia;
}
this.editMedia(this.currentMedia);
}
nextMedia(el) {
this.navigateMedia(this.currentMedia);
}
prevMedia(el) {
this.navigateMedia(this.currentMedia, false);
}
newFolder(el) {
let hash = decodeURIComponent(window.location.hash).slice(1).split('=');
let rendered = this.response;
if (hash[0].trim().length) {
rendered = this.searchByPath(hash[0]);
} else {
rendered = this.searchByPath(this.response[0].path);
}
let folder = prompt('Folder name');
if (folder) {
const data = new FormData();
data.append("folder", folder);
data.append("path", Vvveb.MediaModal.currentPath);
data.append("csrf", document.querySelector("[name='csrf']")?.value);
fetch(mediaUrl + "&action=newFolder", {method: "POST", body: data})
.then((response) => {
if (!response.ok) { throw new Error(response) }
return response.json();
})
.then((data) => {
let bg = "success";
if (data.success) {
} else {
bg = "danger";
}
rendered.push({
name: folder,
type: 'folder',
path: Vvveb.MediaModal.currentPath + "/" + folder,
items: []});
this.render(rendered);
displayToast(bg, "Save", data.message, "top");
})
.catch(error => {
displayToast("danger", "Error", "Error saving!", "top");
});
}
}
editMedia(el) {
let parent = el.closest("li");
let file = parent.querySelector('input[type="hidden"]').value;
let name = parent.querySelector('.name');
//folder
if (parent.classList.contains("folders")) {
let folder = prompt('Folder name', name.innerText);
if (folder) {
const data = new FormData();
data.append("file", file);
data.append("newname", folder);
data.append("csrf", document.querySelector("[name='csrf']")?.value);
fetch(renameUrl, {method: "POST", body: data})
.then((response) => {
if (!response.ok) { return Promise.reject(response); }
return response.json();
})
.then((data) => {
let bg = "success";
if (data.success) {
name.innerText = folder;
} else {
bg = "danger";
}
displayToast(bg, "Rename", data.message, "top");
})
.catch(error => {
console.log(error);
let message = error.statusText ?? "Error renaming file!";
displayToast("danger", "Error", message, "top");
error.text().then( errorMessage => {
let message = errorMessage.substr(0, 200);
displayToast("danger", "Error", message, "top");
});
});
}
return;
}
//file
let offcanvas = document.getElementById("media-offcanvas");
//if (this.currentMedia == parent) return;
this.currentMedia = parent;
this.enableNavigateBtns(parent);
//let image = parent.querySelector('img.image').getAttribute("src");
//let newfile = prompt(`Enter new file name for "${file}"`, file);
let img = offcanvas.querySelector("img");
let video = offcanvas.querySelector("video");
offcanvas.querySelector("[name=file]").value = file;
if (isVideo(file)) {
video.setAttribute("src", mediaPath + file);
video.style.display = "";
img.style.display = "none";
} else {
img.setAttribute("src", mediaPath + file);
img.style.display = "";
video.style.display = "none";
}
//if (newfile) {
fetch(mediaUrl + "&action=mediaContent&" + new URLSearchParams({file}))
.then((response) => {
if (!response.ok) { throw new Error(response) }
return response.json();
})
.then((data) => {
//clear previous text
document.querySelectorAll("[data-v-languages] input[type=text], [data-v-languages] textarea").forEach(i => i.value = "");
for (const lang of data) {
let language_id = lang["language_id"];
for (const field of ['name', 'caption', 'description', 'language_id']) {
let name = `media_content[${language_id}][${field}]`;
let input = offcanvas.querySelector(`[name="${name}"]`);
if (input) {
input.value = lang[field] ?? "";
}
}
}
})
.catch(error => {
displayToast("danger", "Error", "Error loading media content!", "top");
});
//}
}
saveMediaContent(el) {
let offcanvas = document.getElementById("media-offcanvas");
let saveBtn = offcanvas.querySelector('.save-btn');
let loading = saveBtn.querySelector('.loading');
let btnText = saveBtn.querySelector('.button-text');
loading.classList.toggle("d-none");
btnText.classList.toggle("d-none");
const data = new FormData(document.getElementById("media-content-form"));
data.append("csrf", document.querySelector("[name='csrf']")?.value);
fetch(mediaUrl + "&action=mediaContentSave", {method: "POST", body: data})
.then((response) => {
if (!response.ok) { throw new Error(response) }
return response.json();
})
.then((data) => {
let bg = "success";
if (data.success) {
} else {
bg = "danger";
}
displayToast(bg, "Save", data.message ?? data, "top");
loading.classList.toggle("d-none");
btnText.classList.toggle("d-none");
})
.catch(error => {
displayToast("danger", "Error", "Error saving!", "top");
loading.classList.toggle("d-none");
btnText.classList.toggle("d-none");
});
}
addFile(f, selected) {
let _this= this;
let isImage = false;
let actions = '';
let fileSize = _this.bytesToSize(f.size),
name = _this.escapeHTML(f.name),
fileType = name.split('.').pop(),
icon = '<span class="icon file"></span>';
if (fileType == "jpg" || fileType == "jpeg" || fileType == "png" || fileType == "gif" || fileType == "svg" || fileType == "webp" || fileType == "heic" || fileType == "heif") {
//icon = '<div class="image" style="background-image: url(' + _this.mediaPath + f.path + ');"></div>';
icon = '<img class="image" loading="lazy" src="' + _this.mediaPath + f.path + '">';
isImage = true;
} else {
icon = '<span class="icon file f-'+fileType+'">.'+fileType+'</span>';
}
if (!this.isModal) {
actions = `<a href="javascript:void(0);" title="Rename" class="btn btn-outline-primary btn-sm btn-rename py-0 border-secondary border-opacity-25"
data-bs-toggle="offcanvas" aria-expanded="false" data-bs-target="#media-offcanvas" aria-controls="media-offcanvas" data-bs-reference="parent">
<i class="la la-pen"></i>
</a>
<a href="javascript:void(0);" title="Delete" class="btn btn-outline-danger btn-sm btn-delete py-0 border-secondary border-opacity-25">
<i class="la la-trash"></i>
</a>`;
} else {
}
let detail = { file: _this.mediaPath + f.path, name, fileType, fileSize, isImage, fileType, actions };
const event = new CustomEvent("mediaModal:fileActions", {detail});
window.dispatchEvent(event);
if (isImage && this.isModal) detail.actions += '<a href="javascript:void(0);" class="preview-link p-2"><i class="la la-search-plus"></i></a>';
let file = generateElements('<li class="files">\
<label class="form-check">\
<input type="hidden" value="' + f.path + '" name="filename[]">\
<input type="' + ((_this.type == "single") ? "radio" : "checkbox") + '" class="form-check-input" value="' + f.path + '" name="file[]" ' + ((selected == "single") ? "checked" : "") + '><span class="form-check-label"></span>\
<div href="#\" class="files">'+icon+'<div class="info"><div class="name">'+ name +'</div><span class="details">'+fileSize+'</span>\
' + detail.actions + '\
<div class="preview">\
<img src="' + _this.mediaPath + f.path + '">\
<div>\
<span class="name">'+ name +'</span><span class="details">'+fileSize+'</span>\
</div>\
</div>\
</div>\
</label>\
</li>')[0];
_this.fileList.append(file);
if (selected) {
file.querySelector("input[type='radio'], input[type='checkbox']").checked = true;
}
return file;
}
addFolder(f, selected) {
let actions = '';
let itemsLength = f.items.length,
name = this.escapeHTML(f.name),
icon = '<span class="icon folder"></span>';
if(itemsLength) {
icon = '<span class="icon folder full"></span>';
}
if(itemsLength == 1) {
itemsLength += ' item';
}
else if(itemsLength > 1) {
itemsLength += ' items';
}
else {
itemsLength = 'Empty';
}
if (!this.isModal) {
actions = `<a href="javascript:void(0);" title="Rename" class="btn btn-outline-primary btn-sm btn-rename py-0 border-secondary border-opacity-25">
<i class="la la-pen"></i>
</a>
<a href="javascript:void(0);" title="Delete" class="btn btn-outline-danger btn-sm btn-delete py-0 border-secondary border-opacity-25">
<i class="la la-trash"></i>
</a>`;
} else {
}
let _this= this;
let folder = generateElements('<li class="folders">\
<input type="hidden" value="' + f.path + '" name="filename[]">\
<!-- <input type="' + ((_this.type == "single") ? "radio" : "checkbox") + '" class="form-check-input" value="' + f.path + '" name="file[]" ' + ((selected == "single") ? "checked" : "") + '><span class="form-check-label"></span>-->\
<a href="'+ f.path +'" title="'+ f.path +'" class="folders">'+icon+'<div class="info"><span class="name">' + name + '</span> <span class="details">' + itemsLength + '</span>' + actions + '</div></a></li>')[0];
this.fileList.append(folder);
return folder;
}
render(data) {
let scannedFolders = [],
scannedFiles = [];
if(Array.isArray(data)) {
data.forEach(function (d) {
if (d.type === 'folder') {
scannedFolders.push(d);
}
else if (d.type === 'file') {
scannedFiles.push(d);
}
});
}
else if(typeof data === 'object') {
scannedFolders = data.folders;
scannedFiles = data.files;
}
// Empty the old result and make the new one
this.fileList.replaceChildren();//.style.display = 'none';
if(!scannedFolders.length && !scannedFiles.length) {
this.filemanager.querySelector('.nothingfound').style.display = '';
}
else {
this.filemanager.querySelector('.nothingfound').style.display = 'none';
}
let _this = this;
if(scannedFolders.length) {
scannedFolders.forEach(function(f) {
_this.addFolder(f);
});
}
if(scannedFiles.length) {
scannedFiles.forEach(function(f) {
_this.addFile(f);
});
}
// Generate the breadcrumbs
let url = '';
if(this.filemanager.classList.contains('searching')){
url = '<span>Search results: </span>';
this.fileList.classList.remove('animated');
}
else {
this.fileList.classList.add('animated');
this.breadcrumbsUrls.forEach(function (u, i) {
let name = u.split('/');
if (i !== _this.breadcrumbsUrls.length - 1) {
url += '<a href="'+u+'"><span class="folderName">' + name[name.length-1] + '</span></a> <span class="arrow">→</span> ';
}
else {
url += '<span class="folderName">' + name[name.length-1] + '</span>';
}
});
}
this.breadcrumbs.replaceChildren();
this.breadcrumbs.appendChild(generateElements('<a href="/"><i class="la la-home"></i><span class="folderName">&ensp;home</span></a>')[0]);
this.breadcrumbs.appendChild(generateElements('<span>' + url + '</span>')[0]);
// Show the generated elements
this.fileList.animate({'display':'inline-block'});
}
// This function escapes special html characters in names
escapeHTML(text) {
return text.replace(/\&/g,'&amp;').replace(/\</g,'&lt;').replace(/\>/g,'&gt;');
}
// Convert file sizes from bytes to human readable units
bytesToSize(bytes) {
let sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
if (bytes == 0) return '0 Bytes';
let i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i];
}
}
/*
export {
MediaModal
}
*/