1import { Modal } from "bootstrap"; 2import { createApp, defineComponent, ref, getCurrentInstance, useTemplateRef, computed, onMounted, nextTick } from "vue"; 3import { VueDraggable } from "vue-draggable-plus"; 4import { ItemCardPlaceholder, ItemCard, MultiUploader, createItem } from "vue-multi-uploader"; 5import { a8 as injectCssToDocument, a7 as mergeDeep, ad as forceArray, ac as data, m as useStack } from "./unicorn.js"; 6const css = ".vue-drag-uploader {\n --vmu-img-size: 155px;\n display: flex;\n flex-wrap: wrap;\n padding: 1rem;\n border: 1px dotted #999;\n border-radius: 4px;\n cursor: pointer;\n color: #999;\n min-height: 250px;\n}\n.vue-drag-uploader--readonly {\n border: 1px solid #999;\n}\n.vue-drag-uploader.h-ondrag {\n border: 1px dotted #666;\n background-color: rgba(0, 0, 0, 0.05);\n color: #666;\n}\n.vue-drag-uploader__wrapper {\n width: 100%;\n}\n.vue-drag-uploader__draggable-wrapper, .vue-drag-uploader__transition-wrapper {\n display: flex;\n flex-wrap: wrap;\n}\n.vue-drag-uploader-item {\n width: var(--vmu-img-size);\n height: var(--vmu-img-size);\n border: 1px solid rgba(0, 0, 0, 0.25);\n border-radius: 3px;\n cursor: pointer;\n padding: 0.5rem;\n}\n.vue-drag-uploader .add-button {\n display: flex;\n align-items: center;\n text-align: center;\n transition: background-color 0.5s;\n}\n.vue-drag-uploader .add-button:hover {\n background-color: rgba(0, 0, 0, 0.05);\n}\n.vue-drag-uploader .add-button__body {\n margin: 0 auto;\n}\n.vue-drag-uploader .add-button__icon {\n margin-bottom: 10px;\n}\n.vue-drag-uploader .add-button__text {\n font-size: 14px;\n}\n.vue-drag-uploader .preview-img {\n position: relative;\n cursor: pointer;\n padding: 1px;\n}\n.vue-drag-uploader .preview-img > * {\n position: absolute;\n}\n.vue-drag-uploader .preview-img:hover .error-message__message {\n display: block;\n padding: 10px;\n}\n.vue-drag-uploader .preview-img__body {\n left: 0;\n top: 0;\n width: 100%;\n height: 100%;\n background: transparent no-repeat center center;\n background-size: cover;\n}\n.vue-drag-uploader .preview-img__title {\n margin: 0 auto;\n}\n.vue-drag-uploader .preview-img__overlay {\n display: flex;\n align-items: center;\n left: 0;\n top: 0;\n bottom: 0;\n right: 0;\n background-color: rgba(0, 0, 0, 0.35);\n opacity: 0;\n transition: opacity 0.5s;\n}\n.vue-drag-uploader .preview-img__overlay:hover {\n opacity: 1;\n}\n.vue-drag-uploader .preview-img__remove-icon {\n position: absolute;\n top: 5px;\n right: 5px;\n color: white;\n opacity: 0.75;\n transition: opacity 0.5s;\n}\n.vue-drag-uploader .preview-img__remove-icon:hover {\n opacity: 1;\n}\n.vue-drag-uploader .preview-img__progress {\n height: 5px;\n background-color: rgba(255, 255, 255, 0.8);\n width: 100%;\n bottom: 0;\n left: 0;\n}\n.vue-drag-uploader .preview-img__progress-bar {\n background-color: var(--bs-primary, #007bff);\n width: 0;\n height: 100%;\n}\n.vue-drag-uploader .error-message {\n width: 100%;\n background-color: #dc3545;\n color: white;\n font-size: 14px;\n word-break: break-all;\n top: calc(100% - 26px);\n min-height: 26px;\n}\n.vue-drag-uploader .error-message__notice {\n display: inline-block;\n padding: 3px;\n text-align: center;\n width: 100%;\n}\n.vue-drag-uploader .error-message__message {\n display: none;\n}"; 7const defaultOptions = { 8 readonly: false, 9 disabled: false, 10 sortable: false, 11 thumbSize: 150, 12 maxConcurrent: 5, 13 canReplace: false, 14 tmplSelector: "#multi-uploader-field-tmpl" 15}; 16class MultiUploaderElement extends HTMLElement { 17 static is = "uni-multi-uploader"; 18 modalElement; 19 vm; 20 async connectedCallback() { 21 let options = JSON.parse( 22 this.getAttribute("options") || "{}" 23 ); 24 const resolvedOptions = mergeDeep({}, defaultOptions, options); 25 resolvedOptions.thumbSize ??= 150; 26 this.modalElement = this.querySelector(".modal"); 27 const tmplSelector = resolvedOptions.tmplSelector; 28 const app = createApp( 29 createAppInstance(resolvedOptions, document.querySelector(tmplSelector).innerHTML, this) 30 );
31 this.vm = app.mount(this); 32 } 33} 34async function init() { 35 injectCssToDocument(css); 36 customElements.define(MultiUploaderElement.is, MultiUploaderElement); 37} 38const ready = /* @__PURE__ */ init(); 39function createAppInstance(opt, tmpl, el) { 40 return defineComponent({ 41 name: "MultiUploaderFieldApp", 42 template: tmpl, 43 components: { 44 VueDraggable, 45 MultiUploader, 46 ItemCard, 47 ItemCardPlaceholder 48 }, 49 props: { 50 stackName: String 51 }, 52 setup(props, { expose }) { 53 const options = ref(opt); 54 const current = ref(); 55 const currentIndex = ref(); 56 const loading = ref(false); 57 const dragarea = ref(); 58 const modal = ref(); 59 const app = getCurrentInstance(); 60 const uploader = useTemplateRef("uploader"); 61 const canModify = computed(() => !options.value.disabled && !options.value.readonly); 62 const instance = ref(); 63 onMounted(() => { 64 instance.value = uploader.value.instance; 65 domEmit("multi-uploader:mounted", { app, uploader }); 66 }); 67 const items = ref([]); 68 for (let item of forceArray(options.value.value)) { 69 if (typeof item === "string") { 70 item = { 71 url: item 72 }; 73 } 74 const uploadItem = createItem({ 75 url: item.url || "", 76 thumbUrl: item.thumbUrl || item.thumb_url || item.url || "", 77 data: item 78 }); 79 items.value.push(uploadItem); 80 } 81 const uploadUrl = options.value.uploadUrl; 82 const value = items.value; 83 const uploaderOptions = ref({ 84 maxFiles: () => options.value.maxFiles, 85 readonly: () => options.value.readonly, 86 disabled: () => options.value.disabled, 87 accept: () => options.value.accept, 88 maxConcurrent: () => options.value.maxConcurrent, 89 prepareXhr(xhr) { 90 xhr.setRequestHeader( 91 "X-CSRF-TOKEN", 92 data("csrf-token") 93 ); 94 }, 95 onItemUploadSuccess(item, xhr) { 96 const res = JSON.parse(xhr.responseText); 97 item.url = res.data.url; 98 item.thumbUrl = res.data.thumbUrl || res.data.thumb_url || res.data.url; 99 item.data = res.data; 100 item.data.title ??= item.url.split("/").pop()?.split("?").shift() || ""; 101 } 102 }); 103 const draggableOptions = { 104 draggable: ".c-drag-item", 105 animation: 300, 106 disabled: !canModify.value 107 }; 108 function openFile(item) { 109 if (options.value.openFileHandler) { 110 options.value.openFileHandler(item); 111 } else { 112 window.open(item.download_url || item.url); 113 } 114 } 115 async function itemClick(item, i, event) { 116 current.value = item; 117 currentIndex.value = i; 118 domEmit("item-click", { item, i }); 119 nextTick().then(() => { 120 Modal.getOrCreateInstance(modal.value).show(); 121 }); 122 } 123 function metaSave() { 124 current.value = void 0; 125 currentIndex.value = void 0; 126 } 127 function isImage(url) { 128 const ext = url.split(".").pop().split("?").shift() || ""; 129 const allow = ["png", "jpeg", "jpg", "gif", "bmp", "webp"]; 130 return allow.indexOf(ext.toLowerCase()) !== -1; 131 } 132 function dragover(e) { 133 if (!options.value.canReplace) { 134 return; 135 } 136 dragarea.value.style.opacity = "0.75"; 137 } 138 function dragleave(e) { 139 if (!options.value.canReplace) { 140 return; 141 } 142 dragarea.value.style.opacity = "1"; 143 } 144 function drop(event) { 145 if (!options.value.canReplace) { 146 return; 147 } 148 dragarea.value.style.opacity = "1"; 149 const item = current.value; 150 const file = event.dataTransfer?.files[0] || null; 151 if (!file) { 152 return; 153 } 154 instance.value.checkFile(file); 155 if (instance.value.isReadonly) { 156 return; 157 } 158 item.file = file; 159 loading.value = true; 160 try { 161 instance.value.uploadFile(item); 162 } finally { 163 loading.value = false;
164 } 165 } 166 function uploading() { 167 useStack(props.stackName).push(true); 168 domEmit("uploading"); 169 } 170 function uploaded() { 171 useStack(props.stackName).pop(); 172 domEmit("uploaded"); 173 } 174 function onChange(item) { 175 domEmit("change", item); 176 } 177 function domEmit(event, detail) { 178 el.dispatchEvent(new CustomEvent(event, { detail })); 179 } 180 const foo = ref(); 181 foo.value = "Bar"; 182 const icons = ref({ 183 default: "fas fa-file", 184 pdf: "fas fa-file-pdf text-danger", 185 xls: "fas fa-file-excel text-success", 186 xlsx: "fas fa-file-excel text-success", 187 doc: "fas fa-file-word text-primary", 188 docx: "fas fa-file-word text-primary", 189 ppt: "fas fa-file-powerpoint text-warning", 190 pptx: "fas fa-file-powerpoint text-warning", 191 zip: "fas fa-file-archive text-dark", 192 "7z": "fas fa-file-archive text-dark", 193 rar: "fas fa-file-archive text-dark", 194 mp4: "fas fa-file-video text-dark", 195 avi: "fas fa-file-video text-dark", 196 flv: "fas fa-file-video text-dark", 197 mov: "fas fa-file-video text-dark", 198 ogg: "fas fa-file-video text-dark", 199 webm: "fas fa-file-video text-dark", 200 mpg: "fas fa-file-video text-dark", 201 mp3: "fas fa-file-audio text-dark", 202 acc: "fas fa-file-audio text-dark", 203 wav: "fas fa-file-audio text-dark" 204 }); 205 function setIcons(newIcons, merge = true) { 206 if (merge) { 207 icons.value = { ...icons.value, ...newIcons }; 208 return; 209 } 210 icons.value = newIcons; 211 } 212 expose({ 213 uploader, 214 instance, 215 value, 216 canModify, 217 openFile, 218 itemClick, 219 isImage, 220 setIcons 221 }); 222 function fileIcon(item) { 223 let path = item.file ? item.file.name : item.url; 224 path = String(path).split("?")[0]; 225 const ext = path.split(".").pop() || ""; 226 const def = "default" in icons ? icons.default : "fas fa-file"; 227 return icons[String(ext || "default").toLowerCase()] || def; 228 } 229 return { 230 uploader, 231 uploadUrl, 232 value, 233 uploaderOptions, 234 draggableOptions, 235 modal, 236 dragarea, 237 options, 238 current, 239 currentIndex, 240 loading, 241 instance, 242 canModify, 243 openFile, 244 itemClick, 245 metaSave, 246 isImage, 247 dragover, 248 dragleave, 249 drop, 250 uploading, 251 uploaded, 252 onChange, 253 domEmit, 254 fileIcon 255 }; 256 } 257 }); 258} 259export { 260 MultiUploaderElement, 261 ready 262}; 263//# sourceMappingURL=field-multi-uploader.js.map
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.