/** * @copyright (C) 2021 Open Source Matters, Inc. * @license GNU General Public License version 2 or later; see LICENSE.txt */ if (!Joomla) { throw new Error('Joomla API is not properly initiated'); } /** * An object holding all the information of the selected image in media manager * eg: * { * extension: "png" * fileType: "image/png" * height: 44 * path: "local-images:/powered_by.png" * thumb: undefined * width: 294 * } */ Joomla.selectedMediaFile = {}; const supportedExtensions = Joomla.getOptions('media-picker', {}); if (!Object.keys(supportedExtensions).length) { throw new Error('No supported extensions provided'); } /** * Event Listener that updates the Joomla.selectedMediaFile * to the selected file in the media manager */ document.addEventListener('onMediaFileSelected', async e => { Joomla.selectedMediaFile = e.detail; const currentModal = Joomla.Modal.getCurrent(); const container = currentModal.querySelector('.modal-body'); if (!container) { return; } const optionsEl = container.querySelector('joomla-field-mediamore'); if (optionsEl) { optionsEl.parentNode.removeChild(optionsEl); } // No extra attributes (lazy, alt) for fields if (container.closest('joomla-field-media')) { return; } const { images, audios, videos, documents } = supportedExtensions; if (Joomla.selectedMediaFile.path) { let type; if (images.includes(Joomla.selectedMediaFile.extension.toLowerCase())) { type = 'images'; } else if (audios.includes(Joomla.selectedMediaFile.extension.toLowerCase())) { type = 'audios'; } else if (videos.includes(Joomla.selectedMediaFile.extension.toLowerCase())) { type = 'videos'; } else if (documents.includes(Joomla.selectedMediaFile.extension.toLowerCase())) { type = 'documents'; } if (type) { container.insertAdjacentHTML('afterbegin', ` `); } } }); /** * Method to check if passed param is HTMLElement * * @param o {string|HTMLElement} Element to be checked * * @returns {boolean} */ const isElement = o => typeof HTMLElement === 'object' ? o instanceof HTMLElement : o && typeof o === 'object' && o.nodeType === 1 && typeof o.nodeName === 'string'; /** * Method to return the image size * * @param url {string} * * @returns {bool} */ const getImageSize = url => new Promise((resolve, reject) => { const img = new Image(); img.src = url; img.onload = () => { Joomla.selectedMediaFile.width = img.width; Joomla.selectedMediaFile.height = img.height; resolve(true); }; img.onerror = () => { // eslint-disable-next-line prefer-promise-reject-errors reject(false); }; }); const insertAsImage = async (media, editor, fieldClass) => { if (media.url) { const { rootFull } = Joomla.getOptions('system.paths'); const parts = media.url.split(rootFull); if (parts.length > 1) { // eslint-disable-next-line prefer-destructuring Joomla.selectedMediaFile.url = parts[1]; if (media.thumb_path) { Joomla.selectedMediaFile.thumb = media.thumb_path; } else { Joomla.selectedMediaFile.thumb = false; } } else if (media.thumb_path) { Joomla.selectedMediaFile.url = media.url; Joomla.selectedMediaFile.thumb = media.thumb_path; } } else { Joomla.selectedMediaFile.url = false; } if (Joomla.selectedMediaFile.url) { let attribs; let isLazy = ''; let alt = ''; let appendAlt = ''; let classes = ''; let figClasses = ''; let figCaption = ''; let imageElement = ''; if (!isElement(editor)) { const currentModal = fieldClass.closest('.modal-content'); attribs = currentModal.querySelector('joomla-field-mediamore'); if (attribs) { if (attribs.getAttribute('alt-check') === 'true') { appendAlt = ' alt=""'; } alt = attribs.getAttribute('alt-value') ? ` alt="${attribs.getAttribute('alt-value')}"` : appendAlt; classes = attribs.getAttribute('img-classes') ? ` class="${attribs.getAttribute('img-classes')}"` : ''; figClasses = attribs.getAttribute('fig-classes') ? ` class="image ${attribs.getAttribute('fig-classes')}"` : ' class="image"'; figCaption = attribs.getAttribute('fig-caption') ? `${attribs.getAttribute('fig-caption')}` : ''; if (attribs.getAttribute('is-lazy') === 'true') { isLazy = ` loading="lazy" width="${Joomla.selectedMediaFile.width}" height="${Joomla.selectedMediaFile.height}"`; if (Joomla.selectedMediaFile.width === 0 || Joomla.selectedMediaFile.height === 0) { try { await getImageSize(Joomla.selectedMediaFile.url); isLazy = ` loading="lazy" width="${Joomla.selectedMediaFile.width}" height="${Joomla.selectedMediaFile.height}"`; } catch (err) { isLazy = ''; } } } } if (figCaption) { imageElement = `
${figCaption}
`; } else { imageElement = ``; } if (attribs) { attribs.parentNode.removeChild(attribs); } Joomla.editors.instances[editor].replaceSelection(imageElement); } else { if (Joomla.selectedMediaFile.width === 0 || Joomla.selectedMediaFile.height === 0) { try { await getImageSize(Joomla.selectedMediaFile.url); // eslint-disable-next-line no-empty } catch (err) { Joomla.selectedMediaFile.height = 0; Joomla.selectedMediaFile.width = 0; } } fieldClass.markValid(); fieldClass.setValue(`${Joomla.selectedMediaFile.url}#joomlaImage://${media.path.replace(':', '')}?width=${Joomla.selectedMediaFile.width}&height=${Joomla.selectedMediaFile.height}`); } } }; const insertAsOther = (media, editor, fieldClass, type) => { if (media.url) { const { rootFull } = Joomla.getOptions('system.paths'); const parts = media.url.split(rootFull); if (parts.length > 1) { // eslint-disable-next-line prefer-destructuring Joomla.selectedMediaFile.url = parts[1]; } else { Joomla.selectedMediaFile.url = media.url; } } else { Joomla.selectedMediaFile.url = false; } let attribs; if (Joomla.selectedMediaFile.url) { // Available Only inside an editor if (!isElement(editor)) { let outputText; const currentModal = fieldClass.closest('.modal-content'); attribs = currentModal.querySelector('joomla-field-mediamore'); if (attribs) { const embedable = attribs.getAttribute('embed-it'); if (embedable && embedable === 'true') { if (type === 'audios') { outputText = ``; } if (type === 'documents') { // @todo use ${Joomla.selectedMediaFile.filetype} in type const title = attribs.getAttribute('title'); outputText = ` ${Joomla.Text._('JFIELD_MEDIA_UNSUPPORTED').replace('{tag}', ``).replace(/{extension}/g, Joomla.selectedMediaFile.extension)} `; } if (type === 'videos') { outputText = ``; } } else if (Joomla.editors.instances[editor].getSelection() !== '') { outputText = `${Joomla.editors.instances[editor].getSelection()}`; } else { const name = /([\w-]+)\./.exec(Joomla.selectedMediaFile.url); outputText = `${Joomla.Text._('JFIELD_MEDIA_DOWNLOAD_FILE').replace('{file}', name[1])}`; } } if (attribs) { attribs.parentNode.removeChild(attribs); } Joomla.editors.instances[editor].replaceSelection(outputText); } else { fieldClass.markValid(); fieldClass.givenType = type; fieldClass.setValue(Joomla.selectedMediaFile.url); } } }; /** * Method to append the image in an editor or a field * * @param {{}} resp * @param {string|HTMLElement} editor * @param {string} fieldClass */ const execTransform = async (resp, editor, fieldClass) => { if (resp.success === true) { const media = resp.data[0]; const { images, audios, videos, documents } = supportedExtensions; if (Joomla.selectedMediaFile.extension && images.includes(media.extension.toLowerCase())) { return insertAsImage(media, editor, fieldClass); } if (Joomla.selectedMediaFile.extension && audios.includes(media.extension.toLowerCase())) { return insertAsOther(media, editor, fieldClass, 'audios'); } if (Joomla.selectedMediaFile.extension && documents.includes(media.extension.toLowerCase())) { return insertAsOther(media, editor, fieldClass, 'documents'); } if (Joomla.selectedMediaFile.extension && videos.includes(media.extension.toLowerCase())) { return insertAsOther(media, editor, fieldClass, 'videos'); } return ''; } return ''; }; /** * Method that resolves the real url for the selected media file * * @param data {object} The data for the detail * @param editor {string|object} The data for the detail * @param fieldClass {HTMLElement} The fieldClass for the detail * * @returns {void} */ Joomla.getMedia = (data, editor, fieldClass) => new Promise((resolve, reject) => { if (!data || typeof data === 'object' && (!data.path || data.path === '')) { Joomla.selectedMediaFile = {}; resolve({ resp: { success: false } }); return; } const url = `${Joomla.getOptions('system.paths').baseFull}index.php?option=com_media&task=api.files&url=true&path=${data.path}&mediatypes=0,1,2,3&${Joomla.getOptions('csrf.token')}=1&format=json`; fetch(url, { method: 'GET', headers: { 'Content-Type': 'application/json' } }).then(response => response.json()).then(async response => resolve(await execTransform(response, editor, fieldClass))).catch(error => reject(error)); }); // For B/C purposes Joomla.getImage = Joomla.getMedia; /** * A simple Custom Element for adding alt text and controlling * the lazy loading on a selected image * * Will be rendered only for editor content images * Attributes: * - parent-id: the id of the parent media field {string} * - lazy-label: The text for the checkbox label {string} * - alt-label: The text for the alt label {string} * - is-lazy: The value for the lazyloading (calculated, defaults to 'true') {string} * - alt-value: The value for the alt text (calculated, defaults to '') {string} */ class JoomlaFieldMediaOptions extends HTMLElement { get type() { return this.getAttribute('type'); } get parentId() { return this.getAttribute('parent-id'); } get lazytext() { return this.getAttribute('lazy-label'); } get alttext() { return this.getAttribute('alt-label'); } get altchecktext() { return this.getAttribute('alt-check-label'); } get altcheckdesctext() { return this.getAttribute('alt-check-desc-label'); } get embedchecktext() { return this.getAttribute('embed-check-label'); } get embedcheckdesctext() { return this.getAttribute('embed-check-desc-label'); } get downloadchecktext() { return this.getAttribute('download-check-label'); } get downloadcheckdesctext() { return this.getAttribute('download-check-desc-label'); } get classestext() { return this.getAttribute('classes-label'); } get figclassestext() { return this.getAttribute('figure-classes-label'); } get figcaptiontext() { return this.getAttribute('figure-caption-label'); } get summarytext() { return this.getAttribute('summary-label'); } get widthtext() { return this.getAttribute('width-label'); } get heighttext() { return this.getAttribute('height-label'); } get titletext() { return this.getAttribute('title-label'); } connectedCallback() { if (this.type === 'images') { this.innerHTML = `
${this.summarytext}
${this.altcheckdesctext}
`; this.lazyInputFn = this.lazyInputFn.bind(this); this.altCheckFn = this.altCheckFn.bind(this); this.inputFn = this.inputFn.bind(this); // Add event listeners this.lazyInput = this.querySelector(`#${this.parentId}-lazy`); this.lazyInput.addEventListener('change', this.lazyInputFn); this.altCheck = this.querySelector(`#${this.parentId}-alt-check`); this.altCheck.addEventListener('input', this.altCheckFn); [].slice.call(this.querySelectorAll('input[type="text"]')).map(el => { el.addEventListener('input', this.inputFn); const { is } = el.dataset; if (is) { this.setAttribute(is, el.value.replace(/"/g, '"')); } return el; }); // Set initial values this.setAttribute('is-lazy', !!this.lazyInput.checked); this.setAttribute('alt-check', false); } else if (['audios', 'videos', 'documents'].includes(this.type)) { this.innerHTML = `
${this.summarytext}
`; this.embedInputFn = this.embedInputFn.bind(this); this.inputFn = this.inputFn.bind(this); [].slice.call(this.querySelectorAll('.form-check-input.radio')).map(el => el.addEventListener('input', this.embedInputFn)); this.setAttribute('embed-it', false); [].slice.call(this.querySelectorAll('input[type="text"]')).map(el => { el.addEventListener('input', this.inputFn); const { is } = el.dataset; if (is) { this.setAttribute(is, el.value.replace(/"/g, '"')); } return el; }); } } disconnectedCallback() { if (this.type === 'image') { this.lazyInput.removeEventListener('input', this.lazyInputFn); this.altInput.removeEventListener('input', this.inputFn); this.altCheck.removeEventListener('input', this.altCheckFn); } if (['audio', 'video', 'document'].includes(this.type)) { [].slice.call(this.querySelectorAll('.form-check-input.radio')).map(el => el.removeEventListener('input', this.embedInputFn)); [].slice.call(this.querySelectorAll('input[type="text"]')).map(el => el.removeEventListener('input', this.embedInputFn)); } this.innerHTML = ''; } lazyInputFn(e) { this.setAttribute('is-lazy', !!e.target.checked); } altCheckFn(e) { this.setAttribute('alt-check', !!e.target.checked); } inputFn(e) { const { is } = e.target.dataset; if (is) { this.setAttribute(is, e.target.value.replace(/"/g, '"')); } } embedInputFn(e) { const { value } = e.target; this.setAttribute('embed-it', value !== '0'); const toggable = this.querySelector('.toggable-parts'); if (toggable) { if (toggable.style.display !== 'block') { toggable.style.display = 'block'; } else { toggable.style.display = 'none'; } } } } customElements.define('joomla-field-mediamore', JoomlaFieldMediaOptions);