Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5.2] Media field: selectable folders #3223

Closed
jgerman-bot opened this issue Jul 24, 2024 · 0 comments · Fixed by #3226
Closed

[5.2] Media field: selectable folders #3223

jgerman-bot opened this issue Jul 24, 2024 · 0 comments · Fixed by #3226

Comments

@jgerman-bot
Copy link

New language relevant PR in upstream repo: joomla/joomla-cms#43579 Here are the upstream changes:

Click to expand the diff!
diff --git a/administrator/components/com_media/resources/scripts/components/breadcrumb/breadcrumb.vue b/administrator/components/com_media/resources/scripts/components/breadcrumb/breadcrumb.vue
index 25cddeca8c4e6..87e7945939b69 100644
--- a/administrator/components/com_media/resources/scripts/components/breadcrumb/breadcrumb.vue
+++ b/administrator/components/com_media/resources/scripts/components/breadcrumb/breadcrumb.vue
@@ -78,7 +78,10 @@ export default {
           {
             bubbles: true,
             cancelable: false,
-            detail: {},
+            detail: {
+              type: 'dir',
+              path: destination.path,
+            },
           },
         ),
       );
diff --git a/administrator/components/com_media/resources/scripts/components/browser/items/directory.vue b/administrator/components/com_media/resources/scripts/components/browser/items/directory.vue
index f78a9b6b47ed6..82f02863690ef 100644
--- a/administrator/components/com_media/resources/scripts/components/browser/items/directory.vue
+++ b/administrator/components/com_media/resources/scripts/components/browser/items/directory.vue
@@ -51,6 +51,17 @@ export default {
     /* Handle the on preview double click event */
     onPreviewDblClick() {
       this.navigateTo(this.item.path);
+
+      window.parent.document.dispatchEvent(
+        new CustomEvent('onMediaFileSelected', {
+          bubbles: true,
+          cancelable: false,
+          detail: {
+            type: this.item.type,
+            path: this.item.path,
+          },
+        }),
+      );
     },
     /* Hide actions dropdown */
     hideActions() {
diff --git a/administrator/components/com_media/resources/scripts/components/browser/items/item.es6.js b/administrator/components/com_media/resources/scripts/components/browser/items/item.es6.js
index 9ca4be5a3b7ad..0c8d1f20c27d5 100644
--- a/administrator/components/com_media/resources/scripts/components/browser/items/item.es6.js
+++ b/administrator/components/com_media/resources/scripts/components/browser/items/item.es6.js
@@ -126,6 +126,7 @@ export default {
             bubbles: true,
             cancelable: false,
             detail: {
+              type: this.item.type,
               path: this.item.path,
               thumb: this.item.thumb,
               fileType: this.item.mime_type ? this.item.mime_type : false,
@@ -142,7 +143,10 @@ export default {
           new CustomEvent('onMediaFileSelected', {
             bubbles: true,
             cancelable: false,
-            detail: {},
+            detail: {
+              type: this.item.type,
+              path: this.item.path,
+            },
           }),
         );
       }
diff --git a/administrator/components/com_media/resources/scripts/components/browser/table/row.vue b/administrator/components/com_media/resources/scripts/components/browser/table/row.vue
index 32d1c68157f0c..aff5df71ff2b8 100644
--- a/administrator/components/com_media/resources/scripts/components/browser/table/row.vue
+++ b/administrator/components/com_media/resources/scripts/components/browser/table/row.vue
@@ -136,32 +136,31 @@ export default {
      * @param event
      */
     onClick(event) {
-      const path = false;
       const data = {
-        path,
+        path: this.item.path,
+        type: this.item.type,
         thumb: false,
         fileType: this.item.mime_type ? this.item.mime_type : false,
         extension: this.item.extension ? this.item.extension : false,
       };
 
       if (this.item.type === 'file') {
-        data.path = this.item.path;
         data.thumb = this.item.thumb ? this.item.thumb : false;
         data.width = this.item.width ? this.item.width : 0;
         data.height = this.item.height ? this.item.height : 0;
-
-        window.parent.document.dispatchEvent(
-          new CustomEvent(
-            'onMediaFileSelected',
-            {
-              bubbles: true,
-              cancelable: false,
-              detail: data,
-            },
-          ),
-        );
       }
 
+      window.parent.document.dispatchEvent(
+        new CustomEvent(
+          'onMediaFileSelected',
+          {
+            bubbles: true,
+            cancelable: false,
+            detail: data,
+          },
+        ),
+      );
+
       // Handle clicks when the item was not selected
       if (!this.isSelected()) {
         // Unselect all other selected items,
diff --git a/administrator/components/com_media/resources/scripts/components/tree/drive.vue b/administrator/components/com_media/resources/scripts/components/tree/drive.vue
index e330d003acaee..d025e4fdbcc63 100644
--- a/administrator/components/com_media/resources/scripts/components/tree/drive.vue
+++ b/administrator/components/com_media/resources/scripts/components/tree/drive.vue
@@ -77,6 +77,17 @@ export default {
     /* Handle the on drive click event */
     onDriveClick() {
       this.navigateTo(this.drive.root);
+
+      window.parent.document.dispatchEvent(
+        new CustomEvent('onMediaFileSelected', {
+          bubbles: true,
+          cancelable: false,
+          detail: {
+            type: 'dir',
+            path: this.drive.root,
+          },
+        }),
+      );
     },
     moveFocusToChildElement(nextRoot) {
       this.$refs[nextRoot].setFocusToFirstChild();
diff --git a/administrator/components/com_media/resources/scripts/components/tree/tree.vue b/administrator/components/com_media/resources/scripts/components/tree/tree.vue
index 1f14eddff439c..21ae3df7104b7 100644
--- a/administrator/components/com_media/resources/scripts/components/tree/tree.vue
+++ b/administrator/components/com_media/resources/scripts/components/tree/tree.vue
@@ -88,7 +88,10 @@ export default {
           {
             bubbles: true,
             cancelable: false,
-            detail: {},
+            detail: {
+              type: item.type,
+              path: item.path,
+            },
           },
         ),
       );
diff --git a/administrator/language/en-GB/plg_editors_tinymce.ini b/administrator/language/en-GB/plg_editors_tinymce.ini
index 88033c39615ca..b48d32e3326df 100644
--- a/administrator/language/en-GB/plg_editors_tinymce.ini
+++ b/administrator/language/en-GB/plg_editors_tinymce.ini
@@ -11,6 +11,7 @@ PLG_TINY_CORE_BUTTONS="CMS Content"
 PLG_TINY_DND_ADDITIONALDATA="Additional Data"
 PLG_TINY_DND_ALTTEXT="Image Description (Alt Text)"
 PLG_TINY_DND_EMPTY_ALT="No Description"
+PLG_TINY_DND_FILE_EXISTS_ERROR="File \"%s\" already exists."
 PLG_TINY_DND_LAZYLOADED="Image will be lazyloaded"
 PLG_TINY_ERR_CUSTOMCSSFILENOTPRESENT="The file name %s was entered in the TinyMCE Custom CSS field. This file could not be found in the default template folder. No styles are available."
 PLG_TINY_ERR_EDITORCSSFILENOTPRESENT="Could not find the file 'editor.css' in the template or templates/system folder. No styles are available."
diff --git a/build/media_source/plg_editors_tinymce/js/plugins/dragdrop/plugin.es6.js b/build/media_source/plg_editors_tinymce/js/plugins/dragdrop/plugin.es6.js
index 0c866a890ae66..0929f0ef19dcb 100644
--- a/build/media_source/plg_editors_tinymce/js/plugins/dragdrop/plugin.es6.js
+++ b/build/media_source/plg_editors_tinymce/js/plugins/dragdrop/plugin.es6.js
@@ -26,9 +26,7 @@ function readFile(file, callback) {
 window.tinymce.PluginManager.add('jdragndrop', (editor) => {
   const registerOption = editor.options.register;
   registerOption('uploadUri', { processor: 'string' });
-  registerOption('comMediaAdapter', { processor: 'string' });
   registerOption('parentUploadFolder', { processor: 'string' });
-  registerOption('csrfToken', { processor: 'string' });
 
   // Reset the drop area border
   const dragleaveCallback = (e) => {
@@ -61,10 +59,9 @@ window.tinymce.PluginManager.add('jdragndrop', (editor) => {
     const settings = editor.options.get;
 
     Joomla.request({
-      url: `${settings('uploadUri')}&path=${settings('comMediaAdapter')}${settings('parentUploadFolder')}`,
+      url: `${settings('uploadUri')}&path=${settings('parentUploadFolder')}`,
       method: 'POST',
       data: JSON.stringify({
-        [settings('csrfToken')]: 1,
         name,
         content,
         parent: settings('parentUploadFolder'),
@@ -72,11 +69,13 @@ window.tinymce.PluginManager.add('jdragndrop', (editor) => {
       headers: {
         'Content-Type': 'application/json',
       },
-      onSuccess: (resp) => {
+      promise: true,
+    })
+      .then((resp) => {
         let response;
 
         try {
-          response = JSON.parse(resp);
+          response = JSON.parse(resp.responseText);
         } catch (e) {
           editor.windowManager.alert(`${Joomla.Text._('ERROR')}: {${e}}`);
         }
@@ -145,9 +144,14 @@ window.tinymce.PluginManager.add('jdragndrop', (editor) => {
             onCancel: (api) => dialogClose(api),
           });
         }
-      },
-      onError: (xhr) => editor.windowManager.alert(`Error: ${xhr.statusText}`),
-    });
+      })
+      .catch((xhr) => {
+        let message = `Error: ${xhr.statusText}`;
+        if (xhr.status === 409) {
+          message = Joomla.Text._('PLG_TINY_DND_FILE_EXISTS_ERROR').replace('%s', `${settings('parentUploadFolder')}/${name}`);
+        }
+        editor.windowManager.alert(message);
+      });
   }
 
   // Logic for the dropped file
diff --git a/build/media_source/system/js/fields/joomla-field-media.w-c.es6.js b/build/media_source/system/js/fields/joomla-field-media.w-c.es6.js
index ec499cef94a97..e004ec2075db5 100644
--- a/build/media_source/system/js/fields/joomla-field-media.w-c.es6.js
+++ b/build/media_source/system/js/fields/joomla-field-media.w-c.es6.js
@@ -39,12 +39,12 @@ class JoomlaFieldMedia extends HTMLElement {
   }
 
   static get observedAttributes() {
-    return ['type', 'base-path', 'root-folder', 'url', 'modal-title', 'modal-width', 'modal-height', 'input', 'button-select', 'button-clear', 'preview', 'preview-width', 'preview-height'];
+    return ['base-path', 'root-folder', 'url', 'modal-title', 'modal-width', 'modal-height', 'input', 'button-select', 'button-clear', 'preview', 'preview-width', 'preview-height'];
   }
 
-  get type() { return this.getAttribute('type'); }
+  get types() { return this.getAttribute('types') || ''; }
 
-  set type(value) { this.setAttribute('type', value); }
+  set types(value) { this.setAttribute('types', value); }
 
   get basePath() { return this.getAttribute('base-path'); }
 
@@ -175,7 +175,13 @@ class JoomlaFieldMedia extends HTMLElement {
 
   async modalClose() {
     try {
-      await Joomla.getMedia(Joomla.selectedMediaFile, this.inputElement, this);
+      const item = Joomla.selectedMediaFile;
+      if (item && item.type === 'dir') {
+        // Set directory path as value only when the field is configured to support of directories
+        this.setValue(this.types.includes('directories') ? item.path : '');
+      } else {
+        await Joomla.getMedia(item, this.inputElement, this);
+      }
     } catch (err) {
       Joomla.renderMessages({
         error: [Joomla.Text._('JLIB_APPLICATION_ERROR_SERVER')],
diff --git a/build/media_source/system/js/fields/joomla-media-select.w-c.es6.js b/build/media_source/system/js/fields/joomla-media-select.w-c.es6.js
index 8e8864d80f811..70facf109fb16 100644
--- a/build/media_source/system/js/fields/joomla-media-select.w-c.es6.js
+++ b/build/media_source/system/js/fields/joomla-media-select.w-c.es6.js
@@ -48,7 +48,7 @@ document.addEventListener('onMediaFileSelected', async (e) => {
     images, audios, videos, documents,
   } = supportedExtensions;
 
-  if (Joomla.selectedMediaFile.path) {
+  if (Joomla.selectedMediaFile.path && Joomla.selectedMediaFile.type === 'file') {
     let type;
     if (images.includes(Joomla.selectedMediaFile.extension.toLowerCase())) {
       type = 'images';
diff --git a/layouts/joomla/form/field/media.php b/layouts/joomla/form/field/media.php
index 6e10e2e4dd5ea..c5a5dc4a170d4 100644
--- a/layouts/joomla/form/field/media.php
+++ b/layouts/joomla/form/field/media.php
@@ -40,7 +40,8 @@
  * @var  integer  $size            The size text
  * @var  string   $value           The value text
  * @var  string   $src             The path and filename of the image
- * @var  array    $mediaTypes      The supported media types for the Media Manager
+ * @var  string   $mediaTypes      The ids of supported media types for the Media Manager
+ * @var  array    $mediaTypeNames  The names of supported media types for the Media Manager
  * @var  array    $imagesExt       The supported extensions for images
  * @var  array    $audiosExt       The supported extensions for audios
  * @var  array    $videosExt       The supported extensions for videos
@@ -155,7 +156,8 @@
 }
 
 ?>
-<joomla-field-media class="field-media-wrapper" type="image" <?php // @TODO add this attribute to the field in order to use it for all media types ?>
+<joomla-field-media class="field-media-wrapper"
+    types="<?php echo $this->escape(implode(',', $mediaTypeNames)); ?>"
     base-path="<?php echo $this->escape(Uri::root()); ?>"
     root-folder="<?php echo $this->escape(ComponentHelper::getParams('com_media')->get('file_path', 'images')); ?>"
     url="<?php echo $url; ?>"
diff --git a/libraries/src/Form/Field/MediaField.php b/libraries/src/Form/Field/MediaField.php
index 8bf57a45b40e0..b4cd1ad5842b8 100644
--- a/libraries/src/Form/Field/MediaField.php
+++ b/libraries/src/Form/Field/MediaField.php
@@ -382,6 +382,9 @@ public function getLayoutData()
         array_map(
             function ($mediaType) use (&$types, &$imagesAllowedExt, &$audiosAllowedExt, &$videosAllowedExt, &$documentsAllowedExt, $imagesExt, $audiosExt, $videosExt, $documentsExt) {
                 switch ($mediaType) {
+                    case 'directories':
+                        $types[] = '-1';
+                        break;
                     case 'images':
                         $types[]          = '0';
                         $imagesAllowedExt = $imagesExt;
@@ -417,6 +420,7 @@ function ($mediaType) use (&$types, &$imagesAllowedExt, &$audiosAllowedExt, &$vi
             'previewHeight'       => $this->previewHeight,
             'previewWidth'        => $this->previewWidth,
             'mediaTypes'          => implode(',', $types),
+            'mediaTypeNames'      => $mediaTypes,
             'imagesExt'           => $imagesExt,
             'audiosExt'           => $audiosExt,
             'videosExt'           => $videosExt,
diff --git a/plugins/editors/tinymce/forms/setoptions.xml b/plugins/editors/tinymce/forms/setoptions.xml
index 8830ace3f7723..6a3533d2d3e84 100644
--- a/plugins/editors/tinymce/forms/setoptions.xml
+++ b/plugins/editors/tinymce/forms/setoptions.xml
@@ -85,9 +85,11 @@
 
 		<field
 			name="path"
-			type="uploaddirs"
+			type="media"
 			label="PLG_TINY_FIELD_CUSTOM_PATH_LABEL"
 			showon="drag_drop:1"
+			preview="false"
+			types="directories"
 		/>
 
 		<field
diff --git a/plugins/editors/tinymce/src/Field/UploaddirsField.php b/plugins/editors/tinymce/src/Field/UploaddirsField.php
index c47655c4cc3ef..c2a85a12e5f3e 100644
--- a/plugins/editors/tinymce/src/Field/UploaddirsField.php
+++ b/plugins/editors/tinymce/src/Field/UploaddirsField.php
@@ -24,6 +24,9 @@
  * @package     Joomla.Plugin
  * @subpackage  Editors.tinymce
  * @since       3.7.0
+ *
+ * @deprecated  __DEPLOY_VERSION__ will be removed in 7.0
+ *               Use Joomla\CMS\Form\Field\FolderlistField.
  */
 class UploaddirsField extends FolderlistField
 {
@@ -52,6 +55,11 @@ public function setup(\SimpleXMLElement $element, $value, $group = null)
         $this->recursive   = true;
         $this->hideDefault = true;
 
+        @trigger_error(
+            __CLASS__ . ' is deprecated, use Joomla\CMS\Form\Field\FolderlistField instead. Will be removed in 7.0.',
+            \E_USER_DEPRECATED
+        );
+
         return $return;
     }
 
diff --git a/plugins/editors/tinymce/src/PluginTraits/DisplayTrait.php b/plugins/editors/tinymce/src/PluginTraits/DisplayTrait.php
index 07e5ba327e46a..f3063e6c8c6ad 100644
--- a/plugins/editors/tinymce/src/PluginTraits/DisplayTrait.php
+++ b/plugins/editors/tinymce/src/PluginTraits/DisplayTrait.php
@@ -15,6 +15,7 @@
 use Joomla\CMS\Layout\LayoutHelper;
 use Joomla\CMS\Session\Session;
 use Joomla\CMS\Uri\Uri;
+use Joomla\Component\Media\Administrator\Provider\ProviderManagerHelperTrait;
 use Joomla\Registry\Registry;
 
 // phpcs:disable PSR1.Files.SideEffects
@@ -324,8 +325,21 @@ public function display(string $name, string $content = '', array $attributes =
 
         if ($dragdrop && $user->authorise('core.create', 'com_media')) {
             $wa->useScript('plg_editors_tinymce.jdragndrop');
-            $plugins[] = 'jdragndrop';
-            $uploadUrl = Uri::base(true) . '/index.php?option=com_media&format=json&url=1&task=api.files';
+            $plugins[]  = 'jdragndrop';
+            $uploadUrl  = Uri::base(true) . '/index.php?option=com_media&format=json&url=1&task=api.files';
+            $uploadPath = $levelParams->get('path', '');
+
+            // Make sure the path is full, and contain the media adapter in it.
+            $mediaHelper = new class () {
+                use ProviderManagerHelperTrait;
+
+                public function prepareTinyMCEUploadPath(string $path): string
+                {
+                    $result = $this->resolveAdapterAndPath($path);
+
+                    return implode(':', $result);
+                }
+            };
 
             Text::script('PLG_TINY_ERR_UNSUPPORTEDBROWSER');
             Text::script('ERROR');
@@ -333,13 +347,10 @@ public function display(string $name, string $content = '', array $attributes =
             Text::script('PLG_TINY_DND_ALTTEXT');
             Text::script('PLG_TINY_DND_LAZYLOADED');
             Text::script('PLG_TINY_DND_EMPTY_ALT');
+            Text::script('PLG_TINY_DND_FILE_EXISTS_ERROR');
 
-            $scriptOptions['parentUploadFolder'] = $levelParams->get('path', '');
-            $scriptOptions['csrfToken']          = $csrf;
+            $scriptOptions['parentUploadFolder'] = $mediaHelper->prepareTinyMCEUploadPath($uploadPath);
             $scriptOptions['uploadUri']          = $uploadUrl;
-
-            // @TODO have a way to select the adapter, similar to $levelParams->get('path', '');
-            $scriptOptions['comMediaAdapter']    = 'local-images:';
         }
 
         // Convert pt to px in dropdown
diff --git a/plugins/fields/media/media.xml b/plugins/fields/media/media.xml
index d6fd173941ac9..9102996c0e5f0 100644
--- a/plugins/fields/media/media.xml
+++ b/plugins/fields/media/media.xml
@@ -25,11 +25,10 @@
 			<fieldset name="basic">
 				<field
 					name="directory"
-					type="folderlist"
+					type="media"
 					label="PLG_FIELDS_MEDIA_PARAMS_DIRECTORY_LABEL"
-					directory="images"
-					hide_none="true"
-					recursive="true"
+					preview="false"
+					types="directories"
 				/>
 
 				<field
diff --git a/plugins/fields/media/params/media.xml b/plugins/fields/media/params/media.xml
index 875cf5c78dce5..8096f6cd07a03 100644
--- a/plugins/fields/media/params/media.xml
+++ b/plugins/fields/media/params/media.xml
@@ -4,12 +4,10 @@
 		<fieldset name="fieldparams">
 			<field
 				name="directory"
-				type="folderlist"
+				type="media"
 				label="PLG_FIELDS_MEDIA_PARAMS_DIRECTORY_LABEL"
-				directory="images"
-				hide_none="true"
-				recursive="true"
-				validate="options"
+				preview="false"
+				types="directories"
 			/>
 
 			<field
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging a pull request may close this issue.

4 participants