UNPKG

@astsiry/media-manager-ui

Version:

Private media manager UI for internal CDN/FTP use

113 lines (111 loc) 25.9 kB
function v(f){return typeof f=="object"&&f!==null&&!Array.isArray(f)}var T=class{constructor({containerId:t="",basePath:i="/",btnText:e="Toogle media manager",btnId:s="mediaToggle",API_URL:n="http://192.168.0.121:8000",uiText:l}){this.isReady=!1;this.searchTerm="";this.headerTitle="";this.uiText={headerTitle:"Media Manager",defaultLoadingText:"Loading folder structure",noFolder:"No folder",noFile:"No file",noFileSelected:"No file selected",noFileFound:"No matching files found",noFileInFolder:"No files in this folder",dragAndDropText:"or drag & drop files here",upload:"Upload",searchPlaceholder:"Search files...",loadingFolderStructure:"Loading folder structure",newFolderTitle:"Enter new folder name:",loadingFolderCreation:"Creating folder",notifFolderCreateSuccess:"Folder created successfully",notifFolderCreateError:"Failed to create folder",failed:"Failed",delete:"Delete",deleteConfirmationText:"Are you sure ? <br>All instances that use this file will become unavailable.",copied:"Copied!",uploadSuccess:"Upload success",uploadFailed:"Upload failed.",deleteSuccess:"File deleted",deleteFailed:"Failed to delete file.",loadingUpload:"Uploading file",loadingDelete:"Delleting file",newFolder:"New Folder",home:"Home",imgCopied:"Image tag copied!",imgCopyBtnText:"Image tag",urlCopied:"URL copied!",urlCopyBtnText:"Copy URL",download:"Download",confirmBtnText:"Yes",cancelBtnText:"No",promptBtnText:"OK",cancelPropmtBtnText:"Cancel"};l&&(this.uiText={...this.uiText,...l}),this.API_URL=n,this.openFolders=new Set,this.container=document.getElementById(t),this.basePath=i,this.btnText=e,this.btnId=s,this.folderTree={"/":{}},this.currentPath="/",this.selectedFile=null,this._renderStructure(),this._bindEvents(),this._init()}async initCdnUrl(){this.cdnUrl=await(await fetch(`${this.API_URL}/media/cdn_url`)).json(),this.basePath&&this.basePath!=="/"&&(this.cdnUrl=this.joinUrlParts(this.cdnUrl,this.basePath))}async _init(){await this.initCdnUrl(),await this._fetchFolderTree(),this._renderFolders(),this._renderThumbnails(),this._renderPreview(),this._renderImageViewerModal(),this.isReady=!0,this._toggleLoader(!1)}getDefaultUIText(){return this.uiText}_renderStructure(){if(!this.container)return;this.container.insertAdjacentHTML("afterbegin",` <button class="media-btn" id="${this.btnId}"> <div class="loading-in-btn ant-spinner-wrapper"> <div class="ant-spinner-dot ant-dot-1"></div> <div class="ant-spinner-dot ant-dot-2"></div> <div class="ant-spinner-dot ant-dot-3"></div> <div class="ant-spinner-dot ant-dot-4"></div> </div> ${this.btnText} </button> `),this.container.insertAdjacentHTML("beforeend",` <div class="modal-backdrop" id="modalBackdrop"></div> <div class="media-modal" id="mediaModal"> <div class="modal-header" data-uiText="headerTitle"> <h3><i class="bi bi-images"></i> ${this.uiText.headerTitle}</h3> <span class="modal-close" id="modalClose">&times;</span> </div> <div class="modal-body"> <div id="media-loader" class="hide-loader"> <div class="ant-spinner-wrapper"> <div class="ant-spinner-dot ant-dot-1"></div> <div class="ant-spinner-dot ant-dot-2"></div> <div class="ant-spinner-dot ant-dot-3"></div> <div class="ant-spinner-dot ant-dot-4"></div> </div> <div class="loader-text"> <span class="msg" data-uiText="defaultLoadingText">${this.uiText.defaultLoadingText}</span> <span class="dot">.</span><span class="dot">.</span><span class="dot">.</span> </div> </div> <div class="breadcrumbs" id="breadcrumbTrail"></div> <div class="columns-wrapper"> <div class="col folder-tree" id="folderCol"></div> <div class="col" id="previewCol"> <div class="thumb-grid" id="thumbGrid"> <div class="empty-preview"> <i class="bi bi-folder-x"></i> <div data-uiText="noFolder">${this.uiText.noFolder}</div> </div> </div> <div class="drop-zone" id="dropZone"> <div class="upload-wrapper"> <div class="upload-list"></div> </div> <input type="file" accept="*" multiple hidden id="uploadInput" style="display:none"> <button class="upload-btn" id="uploadBtn" data-uiText="upload">${this.uiText.upload}</button> <p id="uploadText" data-uiText="dragAndDropText">${this.uiText.dragAndDropText}</p> </div> </div> <div class="col preview" id="imagePreview"> <div class="preview-empty"> <i class="bi bi-file-earmark-x"></i> <div data-uiText="noFile"> ${this.uiText.noFile}</div> </div> </div> </div> </div> </div> `),this.modal=this.container.querySelector("#mediaModal"),this.backdrop=this.container.querySelector("#modalBackdrop"),this.folderCol=this.container.querySelector("#folderCol"),this.thumbGrid=this.container.querySelector("#thumbGrid"),this.previewCol=this.container.querySelector("#imagePreview"),this.uploadBtn=this.container.querySelector("#uploadBtn"),this.uploadInput=this.container.querySelector("#uploadInput"),this.breadcrumbTrail=this.container.querySelector("#breadcrumbTrail"),this.toggleBtn=document.getElementById(this.btnId),this.closeBtn=this.container.querySelector("#modalClose");let t=document.createElement("div");t.className="thumb-search-wrapper",this.searchInput=document.createElement("input"),this.searchInput.className="thumb-search-input",this.searchInput.type="search",this.searchInput.dataset.uiText="searchPlaceholder",this.searchInput.placeholder=this.uiText.searchPlaceholder;let i=document.createElement("i");i.className="bi bi-x-lg clear-search hidden";let e=document.createElement("i");e.className="bi bi-search trigger-search";let s=()=>{i.classList.toggle("hidden",!this.searchInput.value.trim())},n=()=>{this.searchTerm=this.searchInput.value.trim(),this._renderThumbnails()};this.searchInput.oninput=s,this.searchInput.onkeydown=l=>{l.key==="Enter"&&n()},this.searchInput.onblur=n,e.onclick=n,i.onclick=()=>{this.searchInput.value="",this.searchTerm="",s(),this._renderThumbnails()},t.append(this.searchInput,e,i),this.thumbGrid.insertAdjacentElement("beforebegin",t)}_bindEvents(){this.toggleBtn.onclick=()=>{this.modal.classList.add("show"),this.backdrop.classList.add("show"),this.isReady||this._toggleLoader(!0,this.uiText.loadingFolderStructure)},this.closeBtn.onclick=()=>{this.modal.classList.remove("show"),this.backdrop.classList.remove("show")},this.uploadBtn.onclick=()=>this.uploadInput.click(),this.uploadInput.onchange=async t=>{let i=t.target.files;await this._handleFilesUpload(i)},this.container&&(this.dropZone=this.container.querySelector("#dropZone"),this.dropZone.addEventListener("dragover",t=>{t.preventDefault(),this.dropZone.classList.add("dragover")}),this.dropZone.addEventListener("dragleave",()=>{this.dropZone.classList.remove("dragover")}),this.dropZone.addEventListener("drop",async t=>{t.preventDefault(),t.stopPropagation();let i=t.dataTransfer.files;await this._handleFilesUpload(i),this.dropZone.classList.remove("dragover")}))}_toggleLoader(t=!0,i="Loading"){if(!this.container)return;let e=this.container.querySelector("#media-loader");if(!e)return;let s=e.querySelector(".loader-text .msg");s&&(s.textContent=i,t?(e.classList.add("show-loader"),e.classList.remove("hide-loader")):(e.classList.remove("show-loader"),e.classList.add("hide-loader"),this.container.querySelector(".loading-in-btn")?.classList.add("hidden")))}_expandToPath(t){this.openFolders||(this.openFolders=new Set);let i=t.split("/").filter(Boolean),e="/";for(let s=0;s<i.length;s++)e+=i[s]+"/",this.openFolders.add(e.replace(/\/\//g,"/").replace(/\/\//g,"/"))}async _createFolder(){let t=await this._customPrompt(this.uiText.newFolderTitle||"");if(!t)return;this._toggleLoader(!0,this.uiText.loadingFolderCreation);let e=(this.currentPath+t+"/").replace(/\/\//g,"/");(await fetch(`${this.API_URL}/media/folder`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:(this.basePath+"/"+e).replace(/\/\//g,"/").replace(/\/\//g,"/")})})).ok?(this._ensureFolderPath(e),this.currentPath=e,this._expandToPath(e),this.selectedFile=null,this._renderFolders(),this._renderThumbnails(),this._renderPreview(),this._notify(this.uiText.notifFolderCreateSuccess||"","success")):this._notify(this.uiText.notifFolderCreateError||"","error"),this._toggleLoader(!1)}async _handleFilesUpload(t){if(!t||!t.length||!this.container)return;let i=this.container.querySelector("#uploadBtn"),e=this.container.querySelector("#uploadText");if(!i||!e)return;i.classList.add("hidden"),e.classList.add("hidden");let s=this.dropZone.querySelector(".upload-wrapper"),n=this.dropZone.querySelector(".upload-list");s.classList.add("show-upload"),n.innerHTML="";let l=Array.from(t),r=new Map;for(let c of l){let a=document.createElement("div");a.className="upload-skeleton",a.innerHTML=` <div class="file-info">${c.name}</div> <div class="progress-bar"><div class="bar"></div></div> `,n.appendChild(a),r.set(c.name,a)}let d=l.map(c=>{let a=new FormData;return a.append("file",c),a.append("folder",(this.basePath+"/"+this.currentPath).replace(/\/\//g,"/").replace(/\/\//g,"/")),fetch(`${this.API_URL}/media/upload`,{method:"POST",body:a}).then(async h=>{if(!h.ok)throw new Error("Upload failed");let{filename:o}=await h.json();this._addFile(this.currentPath,o);let p=this._isImage(o),m=document.createElement("div");m.className="upload-result",m.innerHTML=p?`<img src="${this.cdnUrl}/${this.currentPath}${o}" />`:`<i class="bi ${this._getFileTypeIcon(o)} file-icon"></i>`;let u=document.createElement("i");u.className="bi bi-check-circle-fill success-icon",m.appendChild(u);let g=r.get(c.name);g&&n.replaceChild(m,g),this._renderThumbnails()}).catch(()=>{let h=r.get(c.name);h&&(h.classList.add("error"),h.innerHTML+=`<div class="error-text">${this.uiText.failed}</div>`)})});Promise.allSettled(d).then(()=>{this._notify(this.uiText.uploadSuccess??"","success"),setTimeout(()=>{s.classList.remove("show-upload"),i.classList.remove("hidden"),e.classList.remove("hidden"),setTimeout(()=>{n.innerHTML=""},1e3)},1500)})}async _uploadFile(t){this._toggleLoader(!0,this.uiText.loadingUpload);let i=new FormData;i.append("file",t),i.append("folder",(this.basePath+"/"+this.currentPath).replace(/\/\//g,"/").replace(/\/\//g,"/"));let e=await fetch(`${this.API_URL}/media/upload`,{method:"POST",body:i});if(e.ok){let s=await e.json();this._addFile(this.currentPath,s.filename),this.selectedFile=s.filename,this._renderThumbnails()}else alert(this.uiText.uploadFailed);this._toggleLoader(!1)}_ensureFolderPath(t){let i=t.replace(/^\/|\/$/g,"").split("/").filter(Boolean),e=this.folderTree["/"];for(let s of i)e[s]||(e[s]={}),e=e[s];return e.files||(e.files=[]),e}_getFolderNode(t){let i=t.replace(/^\/|\/$/g,"").split("/").filter(Boolean),e=this.folderTree["/"];for(let s of i){if(!e[s])return null;e=e[s]}return e}_addFile(t,i){let e=this._ensureFolderPath(t);e.files.includes(i)||e.files.push(i)}_deleteFile(t,i){let e=this._ensureFolderPath(t);e.files&&(e.files=e.files.filter(s=>s!==i))}_getFiles(t){return this._getFolderNode(t)?.files?.slice().sort((e,s)=>{let n=parseInt(e.split("-")[0],10);return parseInt(s.split("-")[0],10)-n})||[]}_renderFolders(t=null){this.folderCol.innerHTML="";let i=document.createElement("button");i.innerHTML=`<i class="bi bi-folder-plus"></i> ${this.uiText.newFolder}`,i.dataset.uiText="newFolder",i.className="upload-btn",i.onclick=()=>this._createFolder(),this.folderCol.prepend(i);let e=document.createElement("div");e.className="folder-label home-folder",e.innerHTML=`<i class="bi bi-house-door-fill"></i> <span data-uiText="home">${this.uiText.home}</span>`,e.onclick=()=>{this.currentPath="/",this.selectedFile=null,this._renderFolders(),this._renderThumbnails(),this._renderPreview(),this._renderBreadcrumbs()},this.currentPath==="/"&&e.classList.add("active"),this.folderCol.appendChild(e),t||(t=this._buildTree(this.folderTree["/"],"/")),this.folderCol.appendChild(t),this._renderBreadcrumbs()}_buildTree(t,i){let e=document.createElement("ul");return e.className="folder-tree-parrent",Object.entries(t).forEach(([s,n])=>{if(s==="files"||s==="_hasContent")return;let l=document.createElement("li"),r=`/${i}${s}/`.replace(/\/\//g,"/"),d=document.createElement("div");d.className="folder-label",d.dataset.path=r;let c=typeof n=="object"&&n!==null&&("_hasContent"in n||Object.keys(n).some(u=>u!=="files"&&u!=="_hasContent")),a=this.openFolders.has(r)||this.currentPath===r,h=document.createElement("i");h.className=c?"caret bi bi-caret-right-fill":"caret";let o=document.createElement("i");o.className="bi bi-folder";let p=document.createElement("span");p.textContent=s,d.append(h,o,p),l.appendChild(d);let m;(c||a)&&v(n)&&(m=this._buildTree(n,r),m.style.display=a?"block":"none",a&&h.classList.add("rotate"),l.appendChild(m)),d.onclick=async()=>{let u=`/${i}${s}/`.replace(/\/\//g,"/");if(this.currentPath=u,this.selectedFile=null,c){let g=h.classList.toggle("rotate");m.style.display=g?"block":"none";let b=`/${i}${s}/`.replace(/\/\//g,"/");g?this.openFolders.add(b):this.openFolders.delete(b)}this._renderThumbnails(),this._renderPreview(),this._renderBreadcrumbs(),this.container&&(this.container.querySelectorAll(".active-folder").forEach(g=>{g.classList.remove("active-folder")}),d.classList.add("active-folder"))},this.currentPath===r&&d.classList.add("active-folder"),e.appendChild(l)}),e}_renderBreadcrumbs(){let t=this.currentPath.split("/").filter(Boolean),i="/",e=[];e.push(`<span data-path="/"><i class="bi bi-house-door-fill"></i> ${this.uiText.home}</span>`);for(let s=0;s<t.length;s++)i+=t[s]+"/",e.push(`<span class="sep">/</span><span data-path="${i}">${t[s]}</span>`);this.breadcrumbTrail.innerHTML=e.join(""),[...this.breadcrumbTrail.querySelectorAll("span[data-path]")].forEach(s=>{s.onclick=()=>{if(this.currentPath=s.dataset.path,this.selectedFile=null,this._renderThumbnails(),this._renderPreview(),this._renderBreadcrumbs(),!this.container)return;this.container.querySelectorAll(".active-folder").forEach(l=>{l.classList.remove("active-folder")});let n=this.folderCol.querySelector(`.folder-label[data-path="${this.currentPath}"]`);n&&n.classList.add("active-folder")}})}_renderThumbnails(t=""){let i=this._getFiles(this.currentPath);if(this.thumbGrid.innerHTML="",i.length===0){let n=document.createElement("div");n.className="empty-preview",n.innerHTML=` <i class="bi bi-folder-x"></i> <div data-uiText="noFileInFolder">${this.uiText.noFileInFolder}</div> `,this.thumbGrid.appendChild(n);return}let e=this.searchTerm.toLowerCase(),s=e?i.filter(n=>n.toLowerCase().includes(e)):i;if(!s.length&&e){let n=document.createElement("div");n.className="empty-preview",n.innerHTML=` <i class="bi bi-folder-x empty-icon"></i> <div class="empty-text" data-uiText="noFileFound">${this.uiText.noFileFound}</div> `,this.thumbGrid.appendChild(n);return}s.forEach((n,l)=>{let r=document.createElement("div");r.className="thumb",this.selectedFile===n&&r.classList.add("selected");let d=document.createElement("div");if(d.className="thumbnail-skeleton",r.appendChild(d),this._isImage(n)){let o=document.createElement("img"),p=`${this.cdnUrl}/${this.currentPath}/${n}`.replace(/\/\//g,"/").replace(/\/\//g,"/").replace(/\/\//g,"/");o.src=p,o.style.opacity="0",o.onload=()=>{d.remove(),o.style.opacity="1"},r.append(o)}else{let o=document.createElement("i");o.className=`bi ${this._getFileTypeIcon(n)} file-icon`,d.remove(),r.append(o)}let c=document.createElement("div");if(c.className="actions",this._isImage(n)){let o=document.createElement("i");o.className="bi bi-eye",o.onclick=p=>{p.stopPropagation(),this.selectedFile=n;let m=i.filter(u=>this._isImage(u)).indexOf(n);console.log("ast img",m,n,i,s),this._showImageModal(m),this._renderPreview()},c.append(o)}let a=document.createElement("i");a.className="bi bi-trash",a.onclick=async o=>{if(o.stopPropagation(),!await this._customConfirm(`${this.uiText.deleteConfirmationText} "${n}"`,!0))return;this._toggleLoader(!0,`${this.uiText.loadingDelete} : ${n}`);let m=`${(this.basePath+"/"+this.currentPath).replace(/\/\//g,"/").replace(/\/\//g,"/")}${n}`.replace(/\/\//g,"/");(await fetch(`${this.API_URL}/media/delete?path=${encodeURIComponent(m)}`,{method:"DELETE"})).ok?(this._deleteFile(this.currentPath,n),this.selectedFile===n&&(this.selectedFile=null),this._renderThumbnails(),this._renderPreview(),this._toggleLoader(!1),this._notify(this.uiText.deleteSuccess??"","success")):(this._notify(this.uiText.deleteFailed??"","error"),this._toggleLoader(!1))},c.append(a),r.append(c),r.onclick=()=>{this.selectedFile=n,this._renderThumbnails(),this._renderPreview()};let h=document.createElement("div");h.className="thumb-filename",h.textContent=n,r.appendChild(h),this.thumbGrid.appendChild(r)})}async _fetchFolderTree(){let t=await fetch(`${this.API_URL}/media/all_tree?base=${encodeURIComponent(this.basePath)}`);if(!t.ok)return;let i=await t.json();this.folderTree=i,this._renderFolders()}async _fetchFolderContent(t){let i=await fetch(`${this.API_URL}/media/tree?path=${encodeURIComponent(t)}`);return i.ok?await i.json():null}joinUrlParts(...t){return t.map((i,e)=>e===0?i.replace(/\/+$/,""):i.replace(/^\/+|\/+$/g,"")).filter(Boolean).join("/")}_renderPreview(){if(this.previewCol.innerHTML="",!this.selectedFile){let a=document.createElement("div");a.className="preview-empty",a.innerHTML=` <i class="bi bi-file-earmark-x"></i> <div data-uiText="noFileSelected">${this.uiText.noFileSelected}</div> `,this.previewCol.appendChild(a);return}let t=document.createElement("div");t.className="preview-title",t.innerHTML=`<i class="bi bi-file-earmark-check"></i> ${this.selectedFile}`,this.previewCol.appendChild(t);let i=(a,h=this.uiText.copied)=>{if(a.classList.contains("copied"))return;a.classList.add("copied");let o=document.createElement("div");o.className="copy-msg show",o.innerHTML=`<i class="bi bi-check-circle-fill"></i> ${h}`,a.appendChild(o),setTimeout(()=>{o.classList.remove("show"),a.classList.remove("copied"),setTimeout(()=>o.remove(),300)},2e3)},e=this.joinUrlParts(this.cdnUrl,this.currentPath,this.selectedFile);console.log("here",this.cdnUrl,e);let s,n;if(this._isImage(this.selectedFile)){let a=`<img src="${e}" />`;s=document.createElement("div"),s.className="code-snippet",s.innerHTML=` <code>${a.replace(/</g,"&lt;").replace(/>/g,"&gt;")}</code> <i class="bi bi-clipboard copy-icon" title="Copy"></i> `,s.querySelector(".copy-icon").onclick=()=>{this._copyToClipboard(a),i(s,this.uiText.imgCopied)},n=document.createElement("button"),n.className="btn-block",n.innerHTML=`<i class="bi bi-code-slash"></i> ${this.uiText.imgCopyBtnText}`,n.onclick=()=>{this._copyToClipboard(a),i(s,this.uiText.imgCopied)}}let l=document.createElement("div");l.className="code-snippet",l.innerHTML=` <code>${e}</code> <i class="bi bi-clipboard copy-icon" title="Copy"></i> `;let r=l.querySelector(".copy-icon");r&&(r.onclick=()=>{this._copyToClipboard(e),i(l,this.uiText.urlCopied)});let d=document.createElement("button");d.className="btn-block",d.innerHTML=`<i class="bi bi-link"></i> ${this.uiText.urlCopyBtnText}`,d.onclick=()=>{this._copyToClipboard(e),i(l,this.uiText.urlCopied)};let c=document.createElement("button");c.className="btn-block",c.innerHTML=`<i class="bi bi-download"></i> ${this.uiText.download}`,c.onclick=()=>{let a=document.createElement("a");a.href=e,a.target="_blank",a.download=this.selectedFile+".jpg",a.click()},this._isImage(this.selectedFile)&&(this.previewCol.appendChild(s),this.previewCol.appendChild(n)),this.previewCol.append(l,d,c)}_copyToClipboard(t){if(navigator.clipboard&&window.isSecureContext)navigator.clipboard.writeText(t).then(()=>{});else{let i=document.createElement("textarea");i.value=t,i.style.position="fixed",i.style.opacity="0",document.body.appendChild(i),i.focus(),i.select();try{document.execCommand("copy")}catch(e){console.error("Fallback copy failed:",e)}document.body.removeChild(i)}}_renderImageViewerModal(){let t=document.createElement("div");if(t.id="image-viewer-modal",t.className="image-modal hidden",t.innerHTML=` <div class="image-modal-content"> <span class="image-modal-close">&times;</span> <div class="image-modal-nav"> <i class="bi bi-caret-left-fill nav-left"></i> <div class="lightbox-skeleton hidden" id="image-modal-skeleton"></div> <img src="" alt="Full preview" class="lightbox-image hidden" id="image-viewer-img" /> <i class="bi bi-caret-right-fill nav-right"></i> </div> <div class="image-modal-thumbs" id="image-modal-thumbs"></div> </div> `,document.body.appendChild(t),this.imageModal=t,this.imageModalImg=t.querySelector("#image-viewer-img")||void 0,this.imageModalThumbs=t.querySelector("#image-modal-thumbs")||void 0,this.imageModalSkeleton=t.querySelector("#image-modal-skeleton")||void 0,!t)return;let i=t.querySelector(".image-modal-close");i&&(i.onclick=()=>this._closeImageModal()),t.onclick=n=>{n.target===t&&this._closeImageModal()};let e=t.querySelector(".nav-left"),s=t.querySelector(".nav-right");e&&(e.onclick=()=>this._navigateImage(-1)),s&&(s.onclick=()=>this._navigateImage(1))}_showImageModal(t){let i=this.searchTerm.toLowerCase(),e=this._getFiles(this.currentPath),s=i?e.filter(n=>n.toLowerCase().includes(i)):e;this.modalFiles=s.filter(n=>this._isImage(n))||[],this.modalIndex=t,this._updateImageModal(),this.imageModal&&(this.imageModal.classList.remove("hidden"),this.imageModal.classList.add("show"))}_closeImageModal(){this.imageModal&&(this.imageModal.classList.remove("show"),setTimeout(()=>{this.imageModal&&this.imageModal.classList.add("hidden")},300))}_navigateImage(t){this.modalFiles&&(this.modalIndex=(this.modalIndex+t+this.modalFiles.length)%this.modalFiles.length,this._updateImageModal())}_updateImageModal(){if(!this.modalFiles||this.modalIndex==null||!this.imageModalImg||!this.imageModalThumbs||!this.imageModalSkeleton)return;let t=this.modalFiles[this.modalIndex],i=typeof t=="string"?t:t.name;this.selectedFile=i,this._renderThumbnails(),this._renderPreview();let e=typeof t=="string"?`${this.cdnUrl}${this.currentPath}${t}`:t.preview;this.imageModalImg.classList.add("hidden"),this.imageModalSkeleton.classList.remove("hidden"),this.imageModalImg.onload=()=>{!this.imageModalImg||!this.imageModalSkeleton||(this.imageModalSkeleton.classList.add("hidden"),this.imageModalImg.classList.remove("hidden"))},this.imageModalImg.src=e,this.imageModalThumbs.innerHTML="",this.modalFiles.forEach((s,n)=>{if(!this.imageModalThumbs)return;let l=typeof s=="string"?s:s.name,r=typeof s=="string"?`${this.cdnUrl}${this.currentPath}${l}`:s.preview,d=document.createElement("img");d.src=r,d.className="modal-thumb",n===this.modalIndex&&d.classList.add("active"),d.onclick=()=>{this.modalIndex=n,this._updateImageModal()},this.imageModalThumbs.appendChild(d)})}_isImage(t){return/\.(jpe?g|png|ico|gif|bmp|webp|svg)$/i.test(t)}_getFileTypeIcon(t){let i=t.split(".").pop();if(!i)return"bi-file-earmark";let e=i.toLowerCase();return["pdf"].includes(e)?"bi-file-earmark-pdf":["doc","docx"].includes(e)?"bi-file-earmark-word":["xls","xlsx","csv"].includes(e)?"bi-file-earmark-excel":["zip","rar","tar","gz","7z"].includes(e)?"bi-file-earmark-zip":["exe","apk","msi","dmg","app"].includes(e)?"bi-gear":["mp4","avi","mov","wmv","mkv","webm","flv"].includes(e)?"bi-file-earmark-play":this._isImage(t)?"bi-file-image":"bi-file-earmark"}_notify(t,i="info"){let e={success:"bi-check-circle-fill",error:"bi-x-circle-fill",info:"bi-info-circle-fill"},s=document.createElement("div");s.className=`media-toast ${i}`,s.innerHTML=` <i class="bi ${e[i]||"bi-info-circle-fill"} toast-icon"></i> <span class="toast-message">${t}</span> `,document.body.appendChild(s),setTimeout(()=>s.classList.add("show"),10),setTimeout(()=>s.classList.remove("show"),3e3),setTimeout(()=>s.remove(),3500)}_customConfirm(t,i=!1){return new Promise(e=>{let s=document.createElement("div");s.className="custom-modal-backdrop",s.innerHTML=` <div class="custom-modal"> <h3>${t}</h3> <div class="custom-modal-actions"> <button class="btn-confirm ${i?"deleteBtn":""}" data-uiText="confirmBtnText">${i?this.uiText.delete:this.uiText.confirmBtnText}</button> <button class="btn-cancel" data-uiText="cancelBtnText">${this.uiText.cancelBtnText}</button> </div> </div> `,document.body.appendChild(s);let n=s.querySelector(".btn-confirm");n&&(n.onclick=()=>{s.remove(),e(!0)});let l=s.querySelector(".btn-cancel");l&&(l.onclick=()=>{s.remove(),e(!1)})})}_customPrompt(t){return new Promise(i=>{let e=document.createElement("div");e.className="custom-modal-backdrop",e.innerHTML=` <div class="custom-modal"> <h3>${t}</h3> <div class="custom-input-container"> <i class="bi bi-folder-plus"></i> <input type="text" class="custom-input" /> </div> <div class="custom-modal-actions"> <button class="btn-confirm">${this.uiText.promptBtnText}</button> <button class="btn-cancel">${this.uiText.cancelPropmtBtnText}</button> </div> </div> `,document.body.appendChild(e);let s=e.querySelector("input");if(!s)return;let n=e.querySelector(".btn-confirm");n&&(n.onclick=()=>{let r=s.value.trim();e.remove(),i(r||null)});let l=e.querySelector(".btn-cancel");l&&(l.onclick=()=>{e.remove(),i(null)}),s.focus()})}};export{T as MediaManager};