diff --git a/build/media_source/system/js/fields/joomla-image-select.w-c.es6.js b/build/media_source/system/js/fields/joomla-image-select.w-c.es6.js index 09444086a15f7..d04a7f5cc4fd1 100644 --- a/build/media_source/system/js/fields/joomla-image-select.w-c.es6.js +++ b/build/media_source/system/js/fields/joomla-image-select.w-c.es6.js @@ -68,35 +68,6 @@ : o && typeof o === 'object' && o.nodeType === 1 && typeof o.nodeName === 'string' ); - /** - * Method to safely append parameters to a URL string - * - * @param url {string} The URL - * @param key {string} The key of the parameter - * @param value {string} The value of the parameter - * - * @returns {string} - */ - const appendParam = (url, key, value) => { - const newKey = encodeURIComponent(key); - const newValue = encodeURIComponent(value); - const r = new RegExp(`(&|\\?)${key}=[^&]*`); - let s = url; - const param = `${newKey}=${newValue}`; - - s = s.replace(r, `$1${param}`); - - if (!RegExp.$1 && s.includes('?')) { - return `${s}&${param}`; - } - - if (!RegExp.$1 && !s.includes('?')) { - return `${s}?${param}`; - } - - return s; - }; - /** * Method to append the image in an editor or a field * @@ -106,19 +77,20 @@ */ const execTransform = (resp, editor, fieldClass) => { if (resp.success === true) { - if (resp.data[0].url) { - if (/local-/.test(resp.data[0].adapter)) { + const media = resp.data[0]; + if (media.url) { + if (/local-/.test(media.adapter)) { const { rootFull } = Joomla.getOptions('system.paths'); - // eslint-disable-next-line prefer-destructuring - Joomla.selectedMediaFile.url = resp.data[0].url.split(rootFull)[1]; - if (resp.data[0].thumb_path) { - Joomla.selectedMediaFile.thumb = resp.data[0].thumb_path; + Joomla.selectedMediaFile.url = media.url.split(rootFull)[1]; + if (media.thumb_path) { + Joomla.selectedMediaFile.thumb = media.thumb_path; } else { Joomla.selectedMediaFile.thumb = false; } - } else if (resp.data[0].thumb_path) { - Joomla.selectedMediaFile.thumb = resp.data[0].thumb_path; + } else if (media.thumb_path) { + Joomla.selectedMediaFile.url = media.url; + Joomla.selectedMediaFile.thumb = media.thumb_path; } } else { Joomla.selectedMediaFile.url = false; @@ -162,8 +134,7 @@ Joomla.editors.instances[editor].replaceSelection(imageElement); } else { - const val = appendParam(Joomla.selectedMediaFile.url, 'joomla_image_width', Joomla.selectedMediaFile.width); - editor.value = appendParam(val, 'joomla_image_height', Joomla.selectedMediaFile.height); + editor.value = `${Joomla.selectedMediaFile.url}#joomlaImage://${media.path.replace(':', '')}?width=${Joomla.selectedMediaFile.width}&height=${Joomla.selectedMediaFile.height}`; fieldClass.updatePreview(); } } diff --git a/layouts/joomla/form/field/media.php b/layouts/joomla/form/field/media.php index 3046fce3865aa..9a3ef56414cf7 100644 --- a/layouts/joomla/form/field/media.php +++ b/layouts/joomla/form/field/media.php @@ -101,10 +101,10 @@ } // The url for the modal -$url = ($readonly ? '' +$url = ($readonly ? '' : ($link ?: 'index.php?option=com_media&view=media&tmpl=component&asset=' . $asset . '&author=' . $authorId) - . '&fieldid={field-media-id}&path=local-images:/' . $folder); + . '&fieldid={field-media-id}&path=' . $folder); // Correctly route the url to ensure it's correctly using sef modes and subfolders $url = Route::_($url); diff --git a/libraries/src/Form/Field/MediaField.php b/libraries/src/Form/Field/MediaField.php index 3764eb6ea7e68..40cd77fa12386 100644 --- a/libraries/src/Form/Field/MediaField.php +++ b/libraries/src/Form/Field/MediaField.php @@ -13,6 +13,8 @@ use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; use Joomla\CMS\Form\FormField; +use Joomla\CMS\Helper\MediaHelper; +use Joomla\CMS\Uri\Uri; /** * Provides a modal media selector including upload mechanism @@ -250,15 +252,69 @@ public function getLayoutData() $asset = Factory::getApplication()->input->get('option'); } - if ($this->value && is_file(JPATH_ROOT . '/' . $this->value)) + // Value in new format such as images/headers/blue-flower.jpg#joomlaImage://local-images/headers/blue-flower.jpg?width=700&height=180 + if ($this->value && strpos($this->value, '#') !== false) { - $this->folder = explode('/', $this->value); - $this->folder = array_diff_assoc($this->folder, explode('/', ComponentHelper::getParams('com_media')->get('image_path', 'images'))); - array_pop($this->folder); - $this->folder = implode('/', $this->folder); + $uri = new Uri(explode('#', $this->value)[1]); + $adapter = $uri->getHost(); + $path = $uri->getPath(); + + // Remove filename from stored path to get the path to the folder which file is stored + $pos = strrpos($path, '/'); + + if ($pos !== false) + { + $path = substr($path, 0, $pos); + } + + if ($path === '') + { + $path = '/'; + } + + $this->folder = $adapter . ':' . $path; + } + elseif ($this->value && is_file(JPATH_ROOT . '/' . $this->value)) + { + /** + * Local image, for example images/sampledata/cassiopeia/nasa2-640.jpg . We need to validate and make sure + * the top level folder is one of the directory configured in filesystem local plugin to avoid error message + * displayed in manage when users click on Select button to select a new image + */ + $paths = explode('/', $this->value); + + // Remove filename from $paths array + array_pop($paths); + + if (MediaHelper::isValidLocalDirectory($paths[0])) + { + $adapterName = array_shift($paths); + $this->folder = 'local-' . $adapterName . ':/' . implode('/', $paths); + } + } + elseif ($this->directory && is_dir(JPATH_ROOT . '/' . ComponentHelper::getParams('com_media')->get('image_path', 'images') . '/' . $this->directory)) + { + /** + * This is the case where a folder is configured in directory attribute of the form field. The directory needs + * to be a relative folder of the folder configured in Path to Images Folder config option of Media component. + * Same with a already stored local image above, we need to validate and make sure top level folder is one of the directory + * configured in filesystem local plugin + */ + $path = ComponentHelper::getParams('com_media')->get('image_path', 'images') . '/' . $this->directory; + $paths = explode('/', $path); + + if (MediaHelper::isValidLocalDirectory($paths[0])) + { + $adapterName = array_shift($paths); + $this->folder = 'local-' . $adapterName . '/' . implode('/', $paths); + } } - elseif (is_dir(JPATH_ROOT . '/' . ComponentHelper::getParams('com_media')->get('image_path', 'images') . '/' . $this->directory)) + elseif ($this->directory && strpos(':', $this->directory)) { + /** + * Directory contains adapter information and path, for example via programming or directly defined in xml + * via directory attribute + */ $this->folder = $this->directory; } else diff --git a/libraries/src/HTML/HTMLHelper.php b/libraries/src/HTML/HTMLHelper.php index ea74af1b21c29..19bab2245660e 100644 --- a/libraries/src/HTML/HTMLHelper.php +++ b/libraries/src/HTML/HTMLHelper.php @@ -684,40 +684,45 @@ public static function cleanImageURL($url) return $obj; } - $url = preg_replace('#&#', '&', $url); - $pieces = explode('?', $url); + $mediaUri = new Uri($url); - parse_str($pieces[1], $urlParams); - - if (isset($urlParams['joomla_image_height']) && $urlParams['joomla_image_height'] !== 'null') + // Old image URL format + if ($mediaUri->hasVar('joomla_image_height')) { - if ((int) $urlParams['joomla_image_height'] > 0) - { - $obj->attributes['height'] = $urlParams['joomla_image_height']; - } - else - { - unset($obj->attributes['height']); - } + $height = (int) $mediaUri->getVar('joomla_image_height'); + $width = (int) $mediaUri->getVar('joomla_image_width'); - unset($urlParams['joomla_image_height']); + $mediaUri->delVar('joomla_image_height'); + $mediaUri->delVar('joomla_image_width'); + } + else + { + // New Image URL format + $fragmentUri = new Uri($mediaUri->getFragment()); + $width = (int) $fragmentUri->getVar('width', 0); + $height = (int) $fragmentUri->getVar('height', 0); } - if (isset($urlParams['joomla_image_width']) && $urlParams['joomla_image_width'] !== 'null') + if ($width > 0) { - if ((int) $urlParams['joomla_image_width'] > 0) - { - $obj->attributes['width'] = $urlParams['joomla_image_width']; - } - else - { - unset($obj->attributes['width']); - } + $obj->attributes['width'] = $width; + } + else + { + unset($obj->attributes['width']); + } - unset($urlParams['joomla_image_width']); + if ($height > 0) + { + $obj->attributes['height'] = $height; + } + else + { + unset($obj->attributes['height']); } - $obj->url = $pieces[0] . (count($urlParams) ? '?' . http_build_query($urlParams) : ''); + $mediaUri->setFragment(''); + $obj->url = $mediaUri->toString(); return $obj; } diff --git a/libraries/src/Helper/MediaHelper.php b/libraries/src/Helper/MediaHelper.php index c9e81a9485c94..e7f8d4764cf09 100644 --- a/libraries/src/Helper/MediaHelper.php +++ b/libraries/src/Helper/MediaHelper.php @@ -14,6 +14,8 @@ use Joomla\CMS\Factory; use Joomla\CMS\Filesystem\File; use Joomla\CMS\Language\Text; +use Joomla\CMS\Plugin\PluginHelper; +use Joomla\Registry\Registry; /** * Media helper class @@ -422,4 +424,42 @@ public function toBytes($val) return $val; } } + + /** + * Method to check if the given directory is a directory configured in FileSystem - Local plugin + * + * @param string $directory + * + * @return boolean + * + * @since __DEPLOY_VERSION__ + */ + public static function isValidLocalDirectory($directory) + { + $plugin = PluginHelper::getPlugin('filesystem', 'local'); + + if ($plugin) + { + $params = new Registry($plugin->params); + + $directories = $params->get('directories', '[{"directory": "images"}]'); + + // Do a check if default settings are not saved by user + // If not initialize them manually + if (is_string($directories)) + { + $directories = json_decode($directories); + } + + foreach ($directories as $directoryEntity) + { + if ($directoryEntity->directory === $directory) + { + return true; + } + } + } + + return false; + } }