[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 /** 2 * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> 3 * @license GNU General Public License version 2 or later; see LICENSE.txt 4 */ 5 if (!Joomla) { 6 throw new Error('Joomla API is not properly initiated'); 7 } 8 /** 9 * Extract the extensions 10 * 11 * @param {*} path 12 * @returns {string} 13 */ 14 15 16 const getExtension = path => { 17 const parts = path.split(/[#]/); 18 19 if (parts.length > 1) { 20 return parts[1].split(/[?]/)[0].split('.').pop().trim(); 21 } 22 23 return path.split(/[#?]/)[0].split('.').pop().trim(); 24 }; 25 26 class JoomlaFieldMedia extends HTMLElement { 27 constructor() { 28 super(); 29 this.onSelected = this.onSelected.bind(this); 30 this.show = this.show.bind(this); 31 this.clearValue = this.clearValue.bind(this); 32 this.modalClose = this.modalClose.bind(this); 33 this.setValue = this.setValue.bind(this); 34 this.updatePreview = this.updatePreview.bind(this); 35 this.validateValue = this.validateValue.bind(this); 36 this.markValid = this.markValid.bind(this); 37 this.markInvalid = this.markInvalid.bind(this); 38 } 39 40 static get observedAttributes() { 41 return ['type', 'base-path', 'root-folder', 'url', 'modal-container', 'modal-width', 'modal-height', 'input', 'button-select', 'button-clear', 'button-save-selected', 'preview', 'preview-width', 'preview-height']; 42 } 43 44 get type() { 45 return this.getAttribute('type'); 46 } 47 48 set type(value) { 49 this.setAttribute('type', value); 50 } 51 52 get basePath() { 53 return this.getAttribute('base-path'); 54 } 55 56 set basePath(value) { 57 this.setAttribute('base-path', value); 58 } 59 60 get rootFolder() { 61 return this.getAttribute('root-folder'); 62 } 63 64 set rootFolder(value) { 65 this.setAttribute('root-folder', value); 66 } 67 68 get url() { 69 return this.getAttribute('url'); 70 } 71 72 set url(value) { 73 this.setAttribute('url', value); 74 } 75 76 get modalContainer() { 77 return this.getAttribute('modal-container'); 78 } 79 80 set modalContainer(value) { 81 this.setAttribute('modal-container', value); 82 } 83 84 get input() { 85 return this.getAttribute('input'); 86 } 87 88 set input(value) { 89 this.setAttribute('input', value); 90 } 91 92 get buttonSelect() { 93 return this.getAttribute('button-select'); 94 } 95 96 set buttonSelect(value) { 97 this.setAttribute('button-select', value); 98 } 99 100 get buttonClear() { 101 return this.getAttribute('button-clear'); 102 } 103 104 set buttonClear(value) { 105 this.setAttribute('button-clear', value); 106 } 107 108 get buttonSaveSelected() { 109 return this.getAttribute('button-save-selected'); 110 } 111 112 set buttonSaveSelected(value) { 113 this.setAttribute('button-save-selected', value); 114 } 115 116 get modalWidth() { 117 return parseInt(this.getAttribute('modal-width'), 10); 118 } 119 120 set modalWidth(value) { 121 this.setAttribute('modal-width', value); 122 } 123 124 get modalHeight() { 125 return parseInt(this.getAttribute('modal-height'), 10); 126 } 127 128 set modalHeight(value) { 129 this.setAttribute('modal-height', value); 130 } 131 132 get previewWidth() { 133 return parseInt(this.getAttribute('preview-width'), 10); 134 } 135 136 set previewWidth(value) { 137 this.setAttribute('preview-width', value); 138 } 139 140 get previewHeight() { 141 return parseInt(this.getAttribute('preview-height'), 10); 142 } 143 144 set previewHeight(value) { 145 this.setAttribute('preview-height', value); 146 } 147 148 get preview() { 149 return this.getAttribute('preview'); 150 } 151 152 set preview(value) { 153 this.setAttribute('preview', value); 154 } 155 156 get previewContainer() { 157 return this.getAttribute('preview-container'); 158 } // attributeChangedCallback(attr, oldValue, newValue) {} 159 160 161 connectedCallback() { 162 this.button = this.querySelector(this.buttonSelect); 163 this.inputElement = this.querySelector(this.input); 164 this.buttonClearEl = this.querySelector(this.buttonClear); 165 this.modalElement = this.querySelector('.joomla-modal'); 166 this.buttonSaveSelectedElement = this.querySelector(this.buttonSaveSelected); 167 this.previewElement = this.querySelector('.field-media-preview'); 168 169 if (!this.button || !this.inputElement || !this.buttonClearEl || !this.modalElement || !this.buttonSaveSelectedElement) { 170 throw new Error('Misconfiguaration...'); 171 } 172 173 this.button.addEventListener('click', this.show); // Bootstrap modal init 174 175 if (this.modalElement && window.bootstrap && window.bootstrap.Modal && !window.bootstrap.Modal.getInstance(this.modalElement)) { 176 Joomla.initialiseModal(this.modalElement, { 177 isJoomla: true 178 }); 179 } 180 181 if (this.buttonClearEl) { 182 this.buttonClearEl.addEventListener('click', this.clearValue); 183 } 184 185 this.supportedExtensions = Joomla.getOptions('media-picker', {}); 186 187 if (!Object.keys(this.supportedExtensions).length) { 188 throw new Error('Joomla API is not properly initiated'); 189 } 190 191 this.updatePreview(); 192 this.inputElement.removeAttribute('readonly'); 193 this.inputElement.addEventListener('change', this.validateValue); 194 } 195 196 disconnectedCallback() { 197 if (this.button) { 198 this.button.removeEventListener('click', this.show); 199 } 200 201 if (this.buttonClearEl) { 202 this.buttonClearEl.removeEventListener('click', this.clearValue); 203 } 204 205 if (this.inputElement) { 206 this.inputElement.removeEventListener('change', this.validateValue); 207 } 208 } 209 210 onSelected(event) { 211 event.preventDefault(); 212 event.stopPropagation(); 213 this.modalClose(); 214 return false; 215 } 216 217 show() { 218 this.modalElement.open(); 219 Joomla.selectedMediaFile = {}; 220 this.buttonSaveSelectedElement.addEventListener('click', this.onSelected); 221 } 222 223 async modalClose() { 224 try { 225 await Joomla.getMedia(Joomla.selectedMediaFile, this.inputElement, this); 226 } catch (err) { 227 Joomla.renderMessages({ 228 error: [Joomla.Text._('JLIB_APPLICATION_ERROR_SERVER')] 229 }); 230 } 231 232 Joomla.selectedMediaFile = {}; 233 Joomla.Modal.getCurrent().close(); 234 } 235 236 setValue(value) { 237 this.inputElement.value = value; 238 this.validatedUrl = value; 239 this.updatePreview(); // trigger change event both on the input and on the custom element 240 241 this.inputElement.dispatchEvent(new Event('change')); 242 this.dispatchEvent(new CustomEvent('change', { 243 detail: { 244 value 245 }, 246 bubbles: true 247 })); 248 } 249 250 validateValue(event) { 251 let { 252 value 253 } = event.target; 254 if (this.validatedUrl === value || value === '') return; 255 256 if (/^(http(s)?:\/\/).+$/.test(value)) { 257 try { 258 fetch(value).then(response => { 259 if (response.status === 200) { 260 this.validatedUrl = value; 261 this.markValid(); 262 } else { 263 this.validatedUrl = value; 264 this.markInvalid(); 265 } 266 }); 267 } catch (err) { 268 this.validatedUrl = value; 269 this.markInvalid(); 270 } 271 } else { 272 if (/^\//.test(value)) { 273 value = value.substring(1); 274 } 275 276 const hashedUrl = value.split('#'); 277 const urlParts = hashedUrl[0].split('/'); 278 const rest = urlParts.slice(1); 279 fetch(`$Joomla.getOptions('system.paths').rootFull}/$value}`).then(response => response.blob()).then(blob => { 280 if (blob.type.includes('image')) { 281 const img = new Image(); 282 img.src = URL.createObjectURL(blob); 283 284 img.onload = () => { 285 this.inputElement.value = `$urlParts[0]}/$rest.join('/')}#joomlaImage://local-${urlParts[0]}/${rest.join('/')}?width=${img.width}&height=${img.height}`; 286 this.validatedUrl = `$urlParts[0]}/$rest.join('/')}#joomlaImage://local-${urlParts[0]}/${rest.join('/')}?width=${img.width}&height=${img.height}`; 287 this.markValid(); 288 }; 289 } else if (blob.type.includes('audio')) { 290 this.inputElement.value = value; 291 this.validatedUrl = value; 292 this.markValid(); 293 } else if (blob.type.includes('video')) { 294 this.inputElement.value = value; 295 this.validatedUrl = value; 296 this.markValid(); 297 } else if (blob.type.includes('application/pdf')) { 298 this.inputElement.value = value; 299 this.validatedUrl = value; 300 this.markValid(); 301 } else { 302 this.validatedUrl = value; 303 this.markInvalid(); 304 } 305 }).catch(() => { 306 this.setValue(value); 307 this.validatedUrl = value; 308 this.markInvalid(); 309 }); 310 } 311 } 312 313 markValid() { 314 this.inputElement.removeAttribute('required'); 315 this.inputElement.removeAttribute('pattern'); 316 317 if (document.formvalidator) { 318 document.formvalidator.validate(this.inputElement); 319 } 320 } 321 322 markInvalid() { 323 this.inputElement.setAttribute('required', ''); 324 this.inputElement.setAttribute('pattern', '/^(http://INVALID/).+$/'); 325 326 if (document.formvalidator) { 327 document.formvalidator.validate(this.inputElement); 328 } 329 } 330 331 clearValue() { 332 this.setValue(''); 333 this.validatedUrl = ''; 334 this.inputElement.removeAttribute('required'); 335 this.inputElement.removeAttribute('pattern'); 336 337 if (document.formvalidator) { 338 document.formvalidator.validate(this.inputElement); 339 } 340 } 341 342 updatePreview() { 343 if (['true', 'static'].indexOf(this.preview) === -1 || this.preview === 'false' || !this.previewElement) { 344 return; 345 } // Reset preview 346 347 348 if (this.preview) { 349 const { 350 value 351 } = this.inputElement; 352 const { 353 supportedExtensions 354 } = this; 355 356 if (!value) { 357 this.buttonClearEl.style.display = 'none'; 358 this.previewElement.innerHTML = Joomla.sanitizeHtml('<span class="field-media-preview-icon"></span>'); 359 } else { 360 let type; 361 this.buttonClearEl.style.display = ''; 362 this.previewElement.innerHTML = ''; 363 const ext = getExtension(value); 364 if (supportedExtensions.images.includes(ext)) type = 'images'; 365 if (supportedExtensions.audios.includes(ext)) type = 'audios'; 366 if (supportedExtensions.videos.includes(ext)) type = 'videos'; 367 if (supportedExtensions.documents.includes(ext)) type = 'documents'; 368 let previewElement; 369 const mediaType = { 370 images: () => { 371 if (supportedExtensions.images.includes(ext)) { 372 previewElement = new Image(); 373 previewElement.src = /http/.test(value) ? value : Joomla.getOptions('system.paths').rootFull + value; 374 previewElement.setAttribute('alt', ''); 375 } 376 }, 377 audios: () => { 378 if (supportedExtensions.audios.includes(ext)) { 379 previewElement = document.createElement('audio'); 380 previewElement.src = /http/.test(value) ? value : Joomla.getOptions('system.paths').rootFull + value; 381 previewElement.setAttribute('controls', ''); 382 } 383 }, 384 videos: () => { 385 if (supportedExtensions.videos.includes(ext)) { 386 previewElement = document.createElement('video'); 387 const previewElementSource = document.createElement('source'); 388 previewElementSource.src = /http/.test(value) ? value : Joomla.getOptions('system.paths').rootFull + value; 389 previewElementSource.type = `video/$ext}`; 390 previewElement.setAttribute('controls', ''); 391 previewElement.setAttribute('width', this.previewWidth); 392 previewElement.setAttribute('height', this.previewHeight); 393 previewElement.appendChild(previewElementSource); 394 } 395 }, 396 documents: () => { 397 if (supportedExtensions.documents.includes(ext)) { 398 previewElement = document.createElement('object'); 399 previewElement.data = /http/.test(value) ? value : Joomla.getOptions('system.paths').rootFull + value; 400 previewElement.type = `application/$ext}`; 401 previewElement.setAttribute('width', this.previewWidth); 402 previewElement.setAttribute('height', this.previewHeight); 403 } 404 } 405 }; // @todo more checks 406 407 if (this.givenType && ['images', 'audios', 'videos', 'documents'].includes(this.givenType)) { 408 mediaType[this.givenType](); 409 } else if (type && ['images', 'audios', 'videos', 'documents'].includes(type)) { 410 mediaType[type](); 411 } else { 412 return; 413 } 414 415 this.previewElement.style.width = this.previewWidth; 416 this.previewElement.appendChild(previewElement); 417 } 418 } 419 } 420 421 } 422 423 customElements.define('joomla-field-media', JoomlaFieldMedia);
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |