From 5c484bda7f3969d0e558fabc3070e23322e10ea9 Mon Sep 17 00:00:00 2001 From: Fedir Zinchuk Date: Sat, 15 Oct 2022 11:14:04 +0300 Subject: [PATCH 01/10] TinyMCE fix text dragging (#38900) --- .../js/plugins/dragdrop/plugin.es5.js | 80 ++++++++++--------- 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/build/media_source/plg_editors_tinymce/js/plugins/dragdrop/plugin.es5.js b/build/media_source/plg_editors_tinymce/js/plugins/dragdrop/plugin.es5.js index f5d65d5be32..5104b965c74 100644 --- a/build/media_source/plg_editors_tinymce/js/plugins/dragdrop/plugin.es5.js +++ b/build/media_source/plg_editors_tinymce/js/plugins/dragdrop/plugin.es5.js @@ -3,21 +3,31 @@ /* eslint-disable no-undef */ tinymce.PluginManager.add('jdragndrop', function (editor) { - var responseData; // Reset the drop area border - - tinyMCE.DOM.bind(document, 'dragleave', function (e) { + // Reset the drop area border + var dragleaveCallback = function (e) { + if (!e.dataTransfer.types.includes('Files')) return; e.stopPropagation(); e.preventDefault(); - editor.contentAreaContainer.style.borderWidth = '1px 0 0'; + editor.contentAreaContainer.style.borderWidth = '0'; return false; - }); // Fix for Chrome + } + tinyMCE.DOM.bind(document, 'dragleave', dragleaveCallback); + // Remove listener when editor are removed + editor.on('remove', function () { + tinyMCE.DOM.unbind(document, 'dragleave', dragleaveCallback); + }); + + // Fix for Chrome editor.on('dragenter', function (e) { + if (!e.dataTransfer.types.includes('Files')) return; e.stopPropagation(); return false; - }); // Notify user when file is over the drop area + }); + // Notify user when file is over the drop area editor.on('dragover', function (e) { + if (!e.dataTransfer.types.includes('Files')) return; e.preventDefault(); editor.contentAreaContainer.style.borderStyle = 'dashed'; editor.contentAreaContainer.style.borderWidth = '5px'; @@ -46,7 +56,7 @@ } if (response.data && response.data.path) { - responseData = response.data; + var responseData = response.data; var urlPath; // For local adapters use relative paths var _Joomla$getOptions = Joomla.getOptions('system.paths'), @@ -119,47 +129,39 @@ function readFile(file) { // Create a new file reader instance - var reader = new FileReader(); // Add the on load callback + var reader = new FileReader(); + // Add the on load callback reader.onload = function (progressEvent) { var result = progressEvent.target.result; var splitIndex = result.indexOf('base64') + 7; - var content = result.slice(splitIndex, result.length); // Upload the file + var content = result.slice(splitIndex, result.length); + // Upload the file uploadFile(file.name, content); }; reader.readAsDataURL(file); - } // Listeners for drag and drop - - - if (typeof FormData !== 'undefined') { - // Logic for the dropped file - editor.on('drop', function (e) { - e.preventDefault(); // We override only for files - - if (e.dataTransfer && e.dataTransfer.files && e.dataTransfer.files.length > 0) { - var files = [].slice.call(e.dataTransfer.files); - files.forEach(function (file) { - // Only images allowed - if (file.name.toLowerCase().match(/\.(jpg|jpeg|png|gif)$/)) { - // Upload the file(s) - readFile(file); - } - }); - } - - editor.contentAreaContainer.style.borderWidth = '1px 0 0'; - }); - } else { - Joomla.renderMessages({ - error: [Joomla.Text._('PLG_TINY_ERR_UNSUPPORTEDBROWSER')] - }); - editor.on('drop', function (e) { - e.preventDefault(); - return false; - }); } - }); + // Logic for the dropped file + editor.on('drop', function (e) { + if (!e.dataTransfer.types.includes('Files')) return; + e.preventDefault(); + + // Read and upload files + if (e.dataTransfer.files.length > 0) { + var files = [].slice.call(e.dataTransfer.files); + files.forEach(function (file) { + // Only images allowed + if (file.name.toLowerCase().match(/\.(jpg|jpeg|png|gif|webp)$/)) { + // Upload the file(s) + readFile(file); + } + }); + } + + editor.contentAreaContainer.style.borderWidth = '0'; + }); + }); }()); From 98eca9e4da4e749e97b4518e8b2b69e3d84769ac Mon Sep 17 00:00:00 2001 From: Fedir Zinchuk Date: Sat, 15 Oct 2022 11:18:33 +0300 Subject: [PATCH 02/10] Fix order of items not always saved (#38935) --- build/media_source/system/js/draggable.es6.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/build/media_source/system/js/draggable.es6.js b/build/media_source/system/js/draggable.es6.js index 8d8a17cf954..ff4d4515105 100644 --- a/build/media_source/system/js/draggable.es6.js +++ b/build/media_source/system/js/draggable.es6.js @@ -54,19 +54,17 @@ if (container) { // Element is moved down if (dragIndex < dropIndex) { - rows[dropIndex].setAttribute('value', rows[dropIndex - 1].value); + rows[dropIndex].value = rows[dropIndex - 1].value; for (i = dragIndex; i < dropIndex; i += 1) { if (direction === 'asc') { - rows[i].setAttribute('value', parseInt(rows[i].value, 10) - 1); + rows[i].value = parseInt(rows[i].value, 10) - 1; } else { - rows[i].setAttribute('value', parseInt(rows[i].value, 10) + 1); + rows[i].value = parseInt(rows[i].value, 10) + 1; } } } else { // Element is moved up - - rows[dropIndex].setAttribute('value', rows[dropIndex + 1].value); rows[dropIndex].value = rows[dropIndex + 1].value; for (i = dropIndex + 1; i <= dragIndex; i += 1) { From 5dc0b46c15a694cf394cb5ca41576c0c43991f8c Mon Sep 17 00:00:00 2001 From: Fedir Zinchuk Date: Sat, 15 Oct 2022 11:21:55 +0300 Subject: [PATCH 03/10] Fix Automatic conversion of false to array, php8.1 (#38948) --- libraries/src/Document/HtmlDocument.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/src/Document/HtmlDocument.php b/libraries/src/Document/HtmlDocument.php index f4bf65ae23d..ee4c33e9267 100644 --- a/libraries/src/Document/HtmlDocument.php +++ b/libraries/src/Document/HtmlDocument.php @@ -542,7 +542,7 @@ class HtmlDocument extends Document implements CacheControllerFactoryAwareInterf ] ) ); - $cbuffer = $cache->get('cbuffer_' . $type); + $cbuffer = $cache->get('cbuffer_' . $type) ?: []; if (isset($cbuffer[$hash])) { return Cache::getWorkarounds($cbuffer[$hash], array('mergehead' => 1)); From e7e074a69c5c5cc98296f9f8587ca18cd9aa237c Mon Sep 17 00:00:00 2001 From: Christiane Maier-Stadtherr Date: Sat, 15 Oct 2022 10:23:16 +0200 Subject: [PATCH 04/10] Fix empty table in users permissions (#38960) --- .../com_users/tmpl/debuguser/default.php | 248 +++++++++--------- 1 file changed, 126 insertions(+), 122 deletions(-) diff --git a/administrator/components/com_users/tmpl/debuguser/default.php b/administrator/components/com_users/tmpl/debuguser/default.php index 659a5056bd2..a0bd46b1b7f 100644 --- a/administrator/components/com_users/tmpl/debuguser/default.php +++ b/administrator/components/com_users/tmpl/debuguser/default.php @@ -20,136 +20,140 @@ $listDirn = $this->escape($this->state->get('list.direction')); $loginActions = []; $actions = []; - -// Split the actions table -foreach ($this->actions as $action) : - $name = $action[0]; - if (in_array($name, ['core.login.site', 'core.login.admin', 'core.login.offline', 'core.login.api', 'core.admin'])) : - $loginActions[] = $action; - else : - $actions[] = $action; - endif; -endforeach; ?>
$this)); ?> -
- items[0]->checks[$name]; - if ($check === true) : - $class = 'text-success icon-check'; - $button = 'btn-success'; - $text = Text::_('COM_USERS_DEBUG_EXPLICIT_ALLOW'); - elseif ($check === false) : - $class = 'text-danger icon-times'; - $button = 'btn-danger'; - $text = Text::_('COM_USERS_DEBUG_EXPLICIT_DENY'); - elseif ($check === null) : - $class = 'text-danger icon-minus-circle'; - $button = 'btn-warning'; - $text = Text::_('COM_USERS_DEBUG_IMPLICIT_DENY'); - else : - $class = ''; - $button = ''; - $text = ''; - endif; - ?> -
- - - + items)) : ?> +
+ +
- -
- - - - - - - - $action) : ?> - - - - - - - - items as $i => $item) :?> - - - - - checks[$name]; - if ($check === true) : - $class = 'text-success icon-check'; - $button = 'btn-success'; - $text = Text::_('COM_USERS_DEBUG_EXPLICIT_ALLOW'); - elseif ($check === false) : - $class = 'text-danger icon-times'; - $button = 'btn-danger'; - $text = Text::_('COM_USERS_DEBUG_EXPLICIT_DENY'); - elseif ($check === null) : - $class = 'text-danger icon-minus-circle'; - $button = 'btn-warning'; - $text = Text::_('COM_USERS_DEBUG_IMPLICIT_DENY'); - else : - $class = ''; - $button = ''; - $text = ''; - endif; - ?> - - - - - + + actions as $action) : + $name = $action[0]; + if (in_array($name, ['core.login.site', 'core.login.admin', 'core.login.offline', 'core.login.api', 'core.admin'])) : + $loginActions[] = $action; + else : + $actions[] = $action; + endif; + endforeach; + ?> +
+ items[0]->checks[$name]; + if ($check === true) : + $class = 'text-success icon-check'; + $button = 'btn-success'; + $text = Text::_('COM_USERS_DEBUG_EXPLICIT_ALLOW'); + elseif ($check === false) : + $class = 'text-danger icon-times'; + $button = 'btn-danger'; + $text = Text::_('COM_USERS_DEBUG_EXPLICIT_DENY'); + elseif ($check === null) : + $class = 'text-danger icon-minus-circle'; + $button = 'btn-warning'; + $text = Text::_('COM_USERS_DEBUG_IMPLICIT_DENY'); + endif; + ?> +
+ + + +
-
-
- , - , - -
- - - - - - - - - -
- escape(Text::_($item->title)); ?> - - $item->level + 1)) . $this->escape($item->name); ?> - - - - - lft; ?> - - rgt; ?> - - id; ?> -
+
-
-    -    - -
+ + + + + + + $action) : ?> + + + + + + + + items as $i => $item) :?> + + + + + checks[$name]; + if ($check === true) : + $class = 'text-success icon-check'; + $button = 'btn-success'; + $text = Text::_('COM_USERS_DEBUG_EXPLICIT_ALLOW'); + elseif ($check === false) : + $class = 'text-danger icon-times'; + $button = 'btn-danger'; + $text = Text::_('COM_USERS_DEBUG_EXPLICIT_DENY'); + elseif ($check === null) : + $class = 'text-danger icon-minus-circle'; + $button = 'btn-warning'; + $text = Text::_('COM_USERS_DEBUG_IMPLICIT_DENY'); + else : + $class = ''; + $button = ''; + $text = ''; + endif; + ?> + + + + + + + +
+ , + , + +
+ + + + + + + + + +
+ escape(Text::_($item->title)); ?> + + $item->level + 1)) . $this->escape($item->name); ?> + + + + + lft; ?> + - rgt; ?> + + id; ?> +
- - pagination->getListFooter(); ?> +
+    +    + +
- - - + + pagination->getListFooter(); ?> + + + + +
From 75469abb8e8d3fdc584655144a60fff547abe4ba Mon Sep 17 00:00:00 2001 From: Brian Teeman Date: Sat, 15 Oct 2022 11:23:36 +0300 Subject: [PATCH 05/10] Updated link (#38944) --- .../components/com_templates/tmpl/template/default.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/administrator/components/com_templates/tmpl/template/default.php b/administrator/components/com_templates/tmpl/template/default.php index 79858960737..02b81f389f8 100644 --- a/administrator/components/com_templates/tmpl/template/default.php +++ b/administrator/components/com_templates/tmpl/template/default.php @@ -117,7 +117,7 @@ if ($this->type == 'font') {

- +

From 4388c1f64bf04d784b4fee8ce0fabd4014e86fe0 Mon Sep 17 00:00:00 2001 From: Brian Teeman Date: Sat, 15 Oct 2022 11:36:19 +0300 Subject: [PATCH 06/10] [4.2] form placeholder (#38827) make the font a little smaller and italics for the placeholder. This addresses a usability issue where it was not possible to visually determine a difference between placeholder text and input text --- .../templates/administrator/atum/scss/blocks/_form.scss | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build/media_source/templates/administrator/atum/scss/blocks/_form.scss b/build/media_source/templates/administrator/atum/scss/blocks/_form.scss index 2c9a947a16c..6b20321f9a2 100644 --- a/build/media_source/templates/administrator/atum/scss/blocks/_form.scss +++ b/build/media_source/templates/administrator/atum/scss/blocks/_form.scss @@ -10,6 +10,11 @@ border-color: $focuscolor; box-shadow: $focusshadow; } + + &::placeholder { + font-size: .8rem; + font-style: italic; + } } .control-group { From 73abc86f6ae44110fa4377a3776e3c9fc055ad75 Mon Sep 17 00:00:00 2001 From: Allon Moritz Date: Sat, 15 Oct 2022 10:40:34 +0200 Subject: [PATCH 07/10] [4.2] Do not checkout a record when the user is not logged in (#38796) * Do not checkout a record when the user is not logged in * do not load early * correct return * add test --- libraries/src/MVC/Model/FormModel.php | 8 +++- .../Libraries/Cms/MVC/Model/FormModelTest.php | 45 +++++++++++++++++-- 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/libraries/src/MVC/Model/FormModel.php b/libraries/src/MVC/Model/FormModel.php index e9a14c3ce47..ffb80a6c3e1 100644 --- a/libraries/src/MVC/Model/FormModel.php +++ b/libraries/src/MVC/Model/FormModel.php @@ -150,7 +150,13 @@ abstract class FormModel extends BaseDatabaseModel implements FormFactoryAwareIn return true; } - $user = $this->getCurrentUser(); + $user = $this->getCurrentUser(); + + // When the user is a guest, don't do a checkout + if (!$user->id) { + return false; + } + $checkedOutField = $table->getColumnAlias('checked_out'); // Check if this is the user having previously checked out the row. diff --git a/tests/Unit/Libraries/Cms/MVC/Model/FormModelTest.php b/tests/Unit/Libraries/Cms/MVC/Model/FormModelTest.php index b49f143e7b5..ccc582c4a26 100644 --- a/tests/Unit/Libraries/Cms/MVC/Model/FormModelTest.php +++ b/tests/Unit/Libraries/Cms/MVC/Model/FormModelTest.php @@ -244,7 +244,7 @@ class FormModelTest extends UnitTestCase * * @since 4.2.0 */ - public function testSucessfullCheckout() + public function testSuccessfulCheckout() { $table = $this->createStub(Table::class); $table->checked_out = 0; @@ -263,7 +263,11 @@ class FormModelTest extends UnitTestCase return null; } }; - $model->setCurrentUser(new User()); + + // Must be a valid user + $user = new User(); + $user->id = 1; + $model->setCurrentUser($user); $this->assertTrue($model->checkout(1)); } @@ -275,7 +279,7 @@ class FormModelTest extends UnitTestCase * * @since 4.2.0 */ - public function testSucessfullCheckoutWithEmptyRecord() + public function testSuccessfulCheckoutWithEmptyRecord() { $model = new class (['dbo' => $this->createStub(DatabaseInterface::class)], $this->createStub(MVCFactoryInterface::class)) extends FormModel { @@ -307,6 +311,41 @@ class FormModelTest extends UnitTestCase $mvcFactory = $this->createStub(MVCFactoryInterface::class); $mvcFactory->method('createTable')->willReturn($table); + $model = new class (['dbo' => $this->createStub(DatabaseInterface::class)], $mvcFactory) extends FormModel + { + public function getForm($data = array(), $loadData = true) + { + return null; + } + }; + + // Must be a valid user + $user = new User(); + $user->id = 1; + $model->setCurrentUser($user); + + $this->assertFalse($model->checkout(1)); + } + + /** + * @testdox can't checkout a record when the current user is a guest + * + * @return void + * + * @since 4.2.0 + */ + public function testFailedCheckoutAsGuest() + { + $table = $this->createStub(Table::class); + $table->checked_out = 0; + $table->method('load')->willReturn(true); + $table->method('hasField')->willReturn(true); + $table->method('checkIn')->willReturn(false); + $table->method('getColumnAlias')->willReturn('checked_out'); + + $mvcFactory = $this->createStub(MVCFactoryInterface::class); + $mvcFactory->method('createTable')->willReturn($table); + $model = new class (['dbo' => $this->createStub(DatabaseInterface::class)], $mvcFactory) extends FormModel { public function getForm($data = array(), $loadData = true) From d13c2b01feeb139e33effbf72efdc8b45f6565ba Mon Sep 17 00:00:00 2001 From: Jonathan Brain <3941269+BrainforgeUK@users.noreply.github.com> Date: Sat, 15 Oct 2022 09:42:36 +0100 Subject: [PATCH 08/10] Ignore PHP warnings raised by simplexml_load_file() (#38907) * Now uses LIBXML_NOERROR --- libraries/namespacemap.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/namespacemap.php b/libraries/namespacemap.php index c47fcdb9694..2123fc563e0 100644 --- a/libraries/namespacemap.php +++ b/libraries/namespacemap.php @@ -228,7 +228,7 @@ class JNamespacePsr4Map } // Load the manifest file - $xml = simplexml_load_file($file); + $xml = simplexml_load_file($file, 'SimpleXMLElement', LIBXML_NOERROR); // When invalid, ignore if (!$xml) { From a8f965e0c6c1513e008f252c061868abf2e7f675 Mon Sep 17 00:00:00 2001 From: Brian Teeman Date: Sat, 15 Oct 2022 16:38:18 +0300 Subject: [PATCH 09/10] [4.2] The alias is already being used - updates (#37017) * [4.2] RFC alias error link No idea if this is the _best_ way to do this so feedback appreciated. If/when accepted it can be applied to may similar use cases. pr for #37013 create a menu item called test Try to create a second menu item also called test Before After And the link opens the existing menu item * trashed or not trashed * category trashed check. No link * cs * contact trashed check. no link * cs * cs * cs * newsfeed trashed check, no link * filters can't be trashed or in categories but the language string was wrong * tags trashed check, no link * article trashed check, no link * cs * underline links * simplify * Phase 1 convert BRANCH to PSR-12 * Phase 2 convert BRANCH to PSR-12 --- .../components/com_contact/src/Table/ContactTable.php | 5 +++++ .../components/com_finder/src/Table/FilterTable.php | 2 +- .../com_newsfeeds/src/Table/NewsfeedTable.php | 5 +++++ .../components/com_tags/src/Table/TagTable.php | 5 +++++ administrator/language/en-GB/com_contact.ini | 3 ++- administrator/language/en-GB/com_content.ini | 2 ++ administrator/language/en-GB/com_finder.ini | 1 + administrator/language/en-GB/com_newsfeeds.ini | 3 ++- administrator/language/en-GB/com_tags.ini | 3 ++- administrator/language/en-GB/lib_joomla.ini | 6 ++++-- libraries/src/Table/Category.php | 5 +++++ libraries/src/Table/Content.php | 7 ++++++- libraries/src/Table/Menu.php | 10 +++++++++- 13 files changed, 49 insertions(+), 8 deletions(-) diff --git a/administrator/components/com_contact/src/Table/ContactTable.php b/administrator/components/com_contact/src/Table/ContactTable.php index 85c248abbd2..95f74cabab5 100644 --- a/administrator/components/com_contact/src/Table/ContactTable.php +++ b/administrator/components/com_contact/src/Table/ContactTable.php @@ -119,8 +119,13 @@ class ContactTable extends Table implements VersionableTableInterface, TaggableT $table = Table::getInstance('ContactTable', __NAMESPACE__ . '\\', array('dbo' => $this->getDbo())); if ($table->load(array('alias' => $this->alias, 'catid' => $this->catid)) && ($table->id != $this->id || $this->id == 0)) { + // Is the existing contact trashed? $this->setError(Text::_('COM_CONTACT_ERROR_UNIQUE_ALIAS')); + if ($table->published === -2) { + $this->setError(Text::_('COM_CONTACT_ERROR_UNIQUE_ALIAS_TRASHED')); + } + return false; } diff --git a/administrator/components/com_finder/src/Table/FilterTable.php b/administrator/components/com_finder/src/Table/FilterTable.php index 621076fa65c..932fb30caf8 100644 --- a/administrator/components/com_finder/src/Table/FilterTable.php +++ b/administrator/components/com_finder/src/Table/FilterTable.php @@ -157,7 +157,7 @@ class FilterTable extends Table $table = new static($this->getDbo()); if ($table->load(array('alias' => $this->alias)) && ($table->filter_id != $this->filter_id || $this->filter_id == 0)) { - $this->setError(Text::_('JLIB_DATABASE_ERROR_ARTICLE_UNIQUE_ALIAS')); + $this->setError(Text::_('COM_FINDER_FILTER_ERROR_UNIQUE_ALIAS')); return false; } diff --git a/administrator/components/com_newsfeeds/src/Table/NewsfeedTable.php b/administrator/components/com_newsfeeds/src/Table/NewsfeedTable.php index 0695082ad25..1765b9e6db3 100644 --- a/administrator/components/com_newsfeeds/src/Table/NewsfeedTable.php +++ b/administrator/components/com_newsfeeds/src/Table/NewsfeedTable.php @@ -173,8 +173,13 @@ class NewsfeedTable extends Table implements VersionableTableInterface, Taggable $table = Table::getInstance('NewsfeedTable', __NAMESPACE__ . '\\', array('dbo' => $this->_db)); if ($table->load(array('alias' => $this->alias, 'catid' => $this->catid)) && ($table->id != $this->id || $this->id == 0)) { + // Is the existing newsfeed trashed? $this->setError(Text::_('COM_NEWSFEEDS_ERROR_UNIQUE_ALIAS')); + if ($table->published === -2) { + $this->setError(Text::_('COM_NEWSFEEDS_ERROR_UNIQUE_ALIAS_TRASHED')); + } + return false; } diff --git a/administrator/components/com_tags/src/Table/TagTable.php b/administrator/components/com_tags/src/Table/TagTable.php index ec039287a02..5f69e8c0935 100644 --- a/administrator/components/com_tags/src/Table/TagTable.php +++ b/administrator/components/com_tags/src/Table/TagTable.php @@ -192,8 +192,13 @@ class TagTable extends Nested implements VersionableTableInterface $table = new static($this->getDbo()); if ($table->load(array('alias' => $this->alias)) && ($table->id != $this->id || $this->id == 0)) { + // Is the existing tag trashed? $this->setError(Text::_('COM_TAGS_ERROR_UNIQUE_ALIAS')); + if ($table->published === -2) { + $this->setError(Text::_('COM_TAGS_ERROR_UNIQUE_ALIAS_TRASHED')); + } + return false; } diff --git a/administrator/language/en-GB/com_contact.ini b/administrator/language/en-GB/com_contact.ini index 5a5a2a1eaa4..463614f5168 100644 --- a/administrator/language/en-GB/com_contact.ini +++ b/administrator/language/en-GB/com_contact.ini @@ -20,7 +20,8 @@ COM_CONTACT_EMPTYSTATE_BUTTON_ADD="Add your first contact" COM_CONTACT_EMPTYSTATE_CONTENT="Contacts can be as simple as a contact form or as complex as a staff directory. You can use this component to create and manage your contacts." COM_CONTACT_EMPTYSTATE_TITLE="No Contacts have been created yet." COM_CONTACT_ERROR_ALL_LANGUAGE_ASSOCIATED="A contact item set to All languages can't be associated. Associations have not been set." -COM_CONTACT_ERROR_UNIQUE_ALIAS="Another Contact from this category has the same alias (remember it may be a trashed item)." +COM_CONTACT_ERROR_UNIQUE_ALIAS="Another Contact in this category has the same alias." +COM_CONTACT_ERROR_UNIQUE_ALIAS_TRASHED="A trashed Contact in this category has the same alias." COM_CONTACT_FIELD_ARTICLES_DISPLAY_NUM_LABEL="# Articles to List" COM_CONTACT_FIELD_ARTICLES_SHOW_LABEL="User Articles" COM_CONTACT_FIELD_CAPTCHA_LABEL="Allow Captcha on Contact" diff --git a/administrator/language/en-GB/com_content.ini b/administrator/language/en-GB/com_content.ini index e7186424eee..a733b70e7cd 100644 --- a/administrator/language/en-GB/com_content.ini +++ b/administrator/language/en-GB/com_content.ini @@ -44,6 +44,8 @@ COM_CONTENT_ERROR_CANNOT_ARCHIVE="One or more of the selected articles can't be COM_CONTENT_ERROR_CANNOT_PUBLISH="One or more of the selected articles can't be set to published." COM_CONTENT_ERROR_CANNOT_TRASH="One or more of the selected articles can't be set to trashed." COM_CONTENT_ERROR_CANNOT_UNPUBLISH="One or more of the selected articles can't be set to unpublished." +COM_CONTENT_ERROR_UNIQUE_ALIAS="Another Article in this category has the same alias." +COM_CONTENT_ERROR_UNIQUE_ALIAS_TRASHED="A trashed Article in this category has the same alias." COM_CONTENT_ERROR_UPDATE_STAGE="You cannot execute this transition and update the stage." COM_CONTENT_FEATURED_ARTICLES="Featured Articles" COM_CONTENT_FEATURED_CATEGORIES_LABEL="Select Categories" diff --git a/administrator/language/en-GB/com_finder.ini b/administrator/language/en-GB/com_finder.ini index 2251edd00a8..ce5e0df1d17 100644 --- a/administrator/language/en-GB/com_finder.ini +++ b/administrator/language/en-GB/com_finder.ini @@ -75,6 +75,7 @@ COM_FINDER_FIELDSET_SEARCH_OPTIONS_LABEL="Smart Search" COM_FINDER_FILTER_BRANCH_LABEL="Search by %s" COM_FINDER_FILTER_EDIT_TOOLBAR_TITLE="Smart Search: Edit Filter" COM_FINDER_FILTER_END_DATE_LABEL="End Date" +COM_FINDER_FILTER_ERROR_UNIQUE_ALIAS="Another Filter has the same alias." COM_FINDER_FILTER_FIELDSET_PARAMS="Filter Timeline" COM_FINDER_FILTER_FORM_TITLE_EDIT="Edit Filter" COM_FINDER_FILTER_FORM_TITLE_NEW="New Filter" diff --git a/administrator/language/en-GB/com_newsfeeds.ini b/administrator/language/en-GB/com_newsfeeds.ini index 77d88995838..2536bf402e5 100644 --- a/administrator/language/en-GB/com_newsfeeds.ini +++ b/administrator/language/en-GB/com_newsfeeds.ini @@ -17,7 +17,8 @@ COM_NEWSFEEDS_EMPTYSTATE_BUTTON_ADD="Add your first news feed" COM_NEWSFEEDS_EMPTYSTATE_CONTENT="Adding News Feeds to your sites is a way of integrating content from other web sites." COM_NEWSFEEDS_EMPTYSTATE_TITLE="No News Feeds have been created yet." COM_NEWSFEEDS_ERROR_ALL_LANGUAGE_ASSOCIATED="A news feed item set to All languages can't be associated. Associations have not been set." -COM_NEWSFEEDS_ERROR_UNIQUE_ALIAS="Another News feed from this category has the same alias (remember it may be a trashed item)." +COM_NEWSFEEDS_ERROR_UNIQUE_ALIAS="Another News feed from this category has the same alias." +COM_NEWSFEEDS_ERROR_UNIQUE_ALIAS_TRASHED="A trashed News feed in this category has the same alias." COM_NEWSFEEDS_FIELD_CACHETIME_LABEL="Cache Time" COM_NEWSFEEDS_FIELD_CHARACTER_COUNT_DESC="0 will show all the text." COM_NEWSFEEDS_FIELD_CHARACTER_COUNT_LABEL="Characters Count" diff --git a/administrator/language/en-GB/com_tags.ini b/administrator/language/en-GB/com_tags.ini index d2c361c4ad4..ca9196afc39 100644 --- a/administrator/language/en-GB/com_tags.ini +++ b/administrator/language/en-GB/com_tags.ini @@ -37,7 +37,8 @@ COM_TAGS_COUNT_UNPUBLISHED_ITEMS="Unpublished items" COM_TAGS_EMPTYSTATE_BUTTON_ADD="Add your first tag" COM_TAGS_EMPTYSTATE_CONTENT="Tags in Joomla! provide a flexible way of organizing content. The same tag can be applied to many different content items across content types." COM_TAGS_EMPTYSTATE_TITLE="No Tags have been created yet." -COM_TAGS_ERROR_UNIQUE_ALIAS="Another Tag has the same alias (remember it may be a trashed item)." +COM_TAGS_ERROR_UNIQUE_ALIAS="Another Tag has the same alias." +COM_TAGS_ERROR_UNIQUE_ALIAS_TRASHED="A trashed Tag has the same alias." COM_TAGS_EXCLUDE="Exclude" COM_TAGS_FIELD_CONTENT_TYPE_LABEL="Content types" COM_TAGS_FIELD_FULL_LABEL="Full Image" diff --git a/administrator/language/en-GB/lib_joomla.ini b/administrator/language/en-GB/lib_joomla.ini index 4c6f31ee5d5..acf419e7af3 100644 --- a/administrator/language/en-GB/lib_joomla.ini +++ b/administrator/language/en-GB/lib_joomla.ini @@ -111,7 +111,8 @@ JLIB_DATABASE_ERROR_ADAPTER_MYSQLI="The MySQL adapter 'mysqli' is not available. JLIB_DATABASE_ERROR_ARTICLE_UNIQUE_ALIAS="Another article from this category has the same alias (remember it may be a trashed item)." JLIB_DATABASE_ERROR_BIND_FAILED_INVALID_SOURCE_ARGUMENT="%s: :bind failed. Invalid source argument." JLIB_DATABASE_ERROR_CATEGORY_REQUIRED="Category is required." -JLIB_DATABASE_ERROR_CATEGORY_UNIQUE_ALIAS="Another category with the same parent category has the same alias (remember it may be a trashed item)." +JLIB_DATABASE_ERROR_CATEGORY_UNIQUE_ALIAS="Another category with the same parent category has the same alias." +JLIB_DATABASE_ERROR_CATEGORY_UNIQUE_ALIAS_TRASHED="A trashed category with the same parent category has the same alias." JLIB_DATABASE_ERROR_CHECK_FAILED="%s: :check Failed - %s" JLIB_DATABASE_ERROR_CHECKIN_FAILED="%s: :check-in failed - %s" JLIB_DATABASE_ERROR_CHECKOUT_FAILED="%s: :check-out failed - %s" @@ -149,8 +150,9 @@ JLIB_DATABASE_ERROR_MENU_HOME_NOT_COMPONENT="The home menu item must be a compon JLIB_DATABASE_ERROR_MENU_HOME_NOT_UNIQUE_IN_MENU="A menu should have only one Default home." JLIB_DATABASE_ERROR_MENU_ROOT_ALIAS_COMPONENT="A first level menu item alias can't be 'component'." JLIB_DATABASE_ERROR_MENU_ROOT_ALIAS_FOLDER="A first level menu item alias can't be '%s' because '%s' is a sub-folder of your Joomla installation folder." -JLIB_DATABASE_ERROR_MENU_UNIQUE_ALIAS="The alias %1$s is already being used by %2$s menu item in the %3$s menu (remember it may be a trashed item)." +JLIB_DATABASE_ERROR_MENU_UNIQUE_ALIAS="The alias %1$s is already being used by the %2$s menu item in the %3$s menu." JLIB_DATABASE_ERROR_MENU_UNIQUE_ALIAS_ROOT="Another menu item has the same alias in Root (remember it may be a trashed item). Root is the top level parent." +JLIB_DATABASE_ERROR_MENU_UNIQUE_ALIAS_TRASHED="The alias %1$s is already being used by the trashed %2$s menu item in the %3$s menu." JLIB_DATABASE_ERROR_MENU_UNPUBLISH_DEFAULT_HOME="Can't unpublish default home." JLIB_DATABASE_ERROR_MENUTYPE="Some menu items or some menu modules related to this menutype are checked out by another user or the default menu item is in this menu." JLIB_DATABASE_ERROR_MENUTYPE_CHECKOUT="The user checking out does not match the user who checked out this menu and/or its linked menu module." diff --git a/libraries/src/Table/Category.php b/libraries/src/Table/Category.php index 3c97183efa1..b207680887c 100644 --- a/libraries/src/Table/Category.php +++ b/libraries/src/Table/Category.php @@ -257,8 +257,13 @@ class Category extends Nested implements VersionableTableInterface, TaggableTabl $table->load(array('alias' => $this->alias, 'parent_id' => (int) $this->parent_id, 'extension' => $this->extension)) && ($table->id != $this->id || $this->id == 0) ) { + // Is the existing category trashed? $this->setError(Text::_('JLIB_DATABASE_ERROR_CATEGORY_UNIQUE_ALIAS')); + if ($table->published === -2) { + $this->setError(Text::_('JLIB_DATABASE_ERROR_CATEGORY_UNIQUE_ALIAS_TRASHED')); + } + return false; } diff --git a/libraries/src/Table/Content.php b/libraries/src/Table/Content.php index 9d9f6c71b90..8af5739afe6 100644 --- a/libraries/src/Table/Content.php +++ b/libraries/src/Table/Content.php @@ -346,7 +346,12 @@ class Content extends Table implements VersionableTableInterface, TaggableTableI $table = Table::getInstance('Content', 'JTable', array('dbo' => $this->getDbo())); if ($table->load(array('alias' => $this->alias, 'catid' => $this->catid)) && ($table->id != $this->id || $this->id == 0)) { - $this->setError(Text::_('JLIB_DATABASE_ERROR_ARTICLE_UNIQUE_ALIAS')); + // Is the existing article trashed? + $this->setError(Text::_('COM_CONTENT_ERROR_UNIQUE_ALIAS')); + + if ($table->published === -2) { + $this->setError(Text::_('COM_CONTENT_ERROR_UNIQUE_ALIAS_TRASHED')); + } return false; } diff --git a/libraries/src/Table/Menu.php b/libraries/src/Table/Menu.php index 2c2d69aa847..bb0f45a77fa 100644 --- a/libraries/src/Table/Menu.php +++ b/libraries/src/Table/Menu.php @@ -14,6 +14,7 @@ use Joomla\CMS\Factory; use Joomla\CMS\Filesystem\Folder; use Joomla\CMS\Language\Multilanguage; use Joomla\CMS\Language\Text; +use Joomla\CMS\Router\Route; use Joomla\Database\DatabaseDriver; use Joomla\Database\ParameterType; use Joomla\Registry\Registry; @@ -241,7 +242,14 @@ class Menu extends Nested if ($error) { $menuTypeTable = Table::getInstance('MenuType', 'JTable', array('dbo' => $db)); $menuTypeTable->load(array('menutype' => $table->menutype)); - $this->setError(Text::sprintf('JLIB_DATABASE_ERROR_MENU_UNIQUE_ALIAS', $this->alias, $table->title, $menuTypeTable->title)); + $url = Route::_('index.php?option=com_menus&task=item.edit&id=' . (int) $table->id); + + // Is the existing menu item trashed? + $this->setError(Text::sprintf('JLIB_DATABASE_ERROR_MENU_UNIQUE_ALIAS', $this->alias, $table->title, $menuTypeTable->title, $url)); + + if ($table->published === -2) { + $this->setError(Text::sprintf('JLIB_DATABASE_ERROR_MENU_UNIQUE_ALIAS_TRASHED', $this->alias, $table->title, $menuTypeTable->title, $url)); + } return false; } From 8f684f1ff8591d9f6e69d687db936ec2b98e958c Mon Sep 17 00:00:00 2001 From: Crystal Dionysopoulos <9141288+crystalenka@users.noreply.github.com> Date: Sat, 15 Oct 2022 19:47:33 +0300 Subject: [PATCH 10/10] Media Actions - Better UX (#38771) * Media Actions - Better UX * fixing order of properties, hopefully this is correct * fixing order of properties, again. * Removing redundant 'item' from media action language strings * Removing redundant 'item' from media action language strings in frontend * Spelling error * CSS display tweaks Helping the actions menu work with longer strings; minor CSS tweaks to the media browser for easier future maintenance. * fixing order of properties again.... * Aria-label and title are unnecessary when there is accessible text in the DOM. * Fixing layering when items are close together. * Adding aria-describedby to buttons to make it clear which item is being managed * Mobile compatibility this is not perfect, but it's better. * Switching to aria-details and moving the span so it doesn't always get read out by screen readers * fixing css property order * Cleaning up aria/a11y attributes and html structure * cleaning up formatting * adding aria-orientation vertical JS looks like it's hooking into the up and down keys; toolbar roles inherit horizontal orientation so we have to specify. * Fix grid item size * fixing javascript keybindings * adding focus style to toggle * ACTUALLy adding focus styles... for real this time * Removing transition delay and making icons have the same transition * making delete hover more clear * Thumbnail size tweaks Making it work more like before by using auto-fill instead of auto-fit. * Codestyle fixes * Capitalizing 'get link' * Update administrator/components/com_media/resources/scripts/components/browser/actionItems/toggle.vue Co-authored-by: Allon Moritz * Update administrator/components/com_media/resources/scripts/components/browser/actionItems/toggle.vue Co-authored-by: Allon Moritz * Removing unnecessary newline * Switching to new language string for the item actions toggle. * Removing empty block * Adding deprecation notices to language files Co-authored-by: Allon Moritz --- .../actionItems/actionItemsContainer.vue | 285 ++++++++++++------ .../components/browser/actionItems/delete.vue | 7 +- .../browser/actionItems/download.vue | 7 +- .../components/browser/actionItems/edit.vue | 7 +- .../browser/actionItems/preview.vue | 7 +- .../components/browser/actionItems/rename.vue | 9 +- .../components/browser/actionItems/share.vue | 7 +- .../components/browser/actionItems/toggle.vue | 5 +- .../components/browser/items/item.es6.js | 10 + .../com_media/tmpl/media/default_texts.php | 2 + administrator/language/en-GB/com_media.ini | 16 +- .../com_media/scss/_variables.scss | 8 +- .../scss/components/_media-browser.scss | 109 ++++--- language/en-GB/com_media.ini | 16 +- 14 files changed, 319 insertions(+), 176 deletions(-) diff --git a/administrator/components/com_media/resources/scripts/components/browser/actionItems/actionItemsContainer.vue b/administrator/components/com_media/resources/scripts/components/browser/actionItems/actionItemsContainer.vue index f22bb8daa26..0694262cab8 100644 --- a/administrator/components/com_media/resources/scripts/components/browser/actionItems/actionItemsContainer.vue +++ b/administrator/components/com_media/resources/scripts/components/browser/actionItems/actionItemsContainer.vue @@ -17,107 +17,129 @@ @on-focused="focused" @keyup.up="openLastActions()" @keyup.down="openActions()" + @keyup.end="openLastActions()" + @keyup.home="openActions()" + @keydown.up.prevent + @keydown.down.prevent + @keydown.home.prevent + @keydown.end.prevent /> @@ -170,6 +192,7 @@ export default { /* Hide actions dropdown */ hideActions() { this.showActions = false; + this.$parent.$parent.$data.actionsActive = false; }, /* Preview an item */ openPreview() { @@ -200,19 +223,89 @@ export default { /* Open actions dropdown */ openActions() { this.showActions = true; + this.$parent.$parent.$data.actionsActive = true; const buttons = [...this.$el.parentElement.querySelectorAll('.media-browser-actions-list button')]; if (buttons.length) { + buttons.forEach((button, i) => { + if (i === (0)) { + button.tabIndex = 0; + } else { + button.tabIndex = -1; + } + }); buttons[0].focus(); } }, /* Open actions dropdown and focus on last element */ openLastActions() { this.showActions = true; + this.$parent.$parent.$data.actionsActive = true; const buttons = [...this.$el.parentElement.querySelectorAll('.media-browser-actions-list button')]; if (buttons.length) { + buttons.forEach((button, i) => { + if (i === (buttons.length)) { + button.tabIndex = 0; + } else { + button.tabIndex = -1; + } + }); this.$nextTick(() => buttons[buttons.length - 1].focus()); } }, + /* Focus on the next item or go to the beginning again */ + focusNext(event) { + const active = event.target; + const buttons = [...active.parentElement.querySelectorAll('button')]; + const lastchild = buttons[buttons.length - 1]; + active.tabIndex = -1; + if (active === lastchild) { + buttons[0].focus(); + buttons[0].tabIndex = 0; + } else { + active.nextElementSibling.focus(); + active.nextElementSibling.tabIndex = 0; + } + }, + /* Focus on the previous item or go to the end again */ + focusPrev(event) { + const active = event.target; + const buttons = [...active.parentElement.querySelectorAll('button')]; + const firstchild = buttons[0]; + active.tabIndex = -1; + if (active === firstchild) { + buttons[buttons.length - 1].focus(); + buttons[buttons.length - 1].tabIndex = 0; + } else { + active.previousElementSibling.focus(); + active.previousElementSibling.tabIndex = 0; + } + }, + /* Focus on the first item */ + focusFirst(event) { + const active = event.target; + const buttons = [...active.parentElement.querySelectorAll('button')]; + buttons[0].focus(); + buttons.forEach((button, i) => { + if (i === 0) { + button.tabIndex = 0; + } else { + button.tabIndex = -1; + } + }); + }, + /* Focus on the last item */ + focusLast(event) { + const active = event.target; + const buttons = [...active.parentElement.querySelectorAll('button')]; + buttons[buttons.length - 1].focus(); + buttons.forEach((button, i) => { + if (i === (buttons.length)) { + button.tabIndex = 0; + } else { + button.tabIndex = -1; + } + }); + }, editItem() { this.edit(); }, diff --git a/administrator/components/com_media/resources/scripts/components/browser/actionItems/delete.vue b/administrator/components/com_media/resources/scripts/components/browser/actionItems/delete.vue index 70008116b1b..ceb05b83e2d 100644 --- a/administrator/components/com_media/resources/scripts/components/browser/actionItems/delete.vue +++ b/administrator/components/com_media/resources/scripts/components/browser/actionItems/delete.vue @@ -2,19 +2,20 @@ diff --git a/administrator/components/com_media/resources/scripts/components/browser/actionItems/download.vue b/administrator/components/com_media/resources/scripts/components/browser/actionItems/download.vue index 914964d1d57..dc973f93333 100644 --- a/administrator/components/com_media/resources/scripts/components/browser/actionItems/download.vue +++ b/administrator/components/com_media/resources/scripts/components/browser/actionItems/download.vue @@ -2,10 +2,9 @@ diff --git a/administrator/components/com_media/resources/scripts/components/browser/actionItems/edit.vue b/administrator/components/com_media/resources/scripts/components/browser/actionItems/edit.vue index ca796ea12c5..0c82cf4bf0b 100644 --- a/administrator/components/com_media/resources/scripts/components/browser/actionItems/edit.vue +++ b/administrator/components/com_media/resources/scripts/components/browser/actionItems/edit.vue @@ -2,10 +2,9 @@ diff --git a/administrator/components/com_media/resources/scripts/components/browser/actionItems/preview.vue b/administrator/components/com_media/resources/scripts/components/browser/actionItems/preview.vue index db29e51b300..e74f3ec8459 100644 --- a/administrator/components/com_media/resources/scripts/components/browser/actionItems/preview.vue +++ b/administrator/components/com_media/resources/scripts/components/browser/actionItems/preview.vue @@ -2,8 +2,7 @@ diff --git a/administrator/components/com_media/resources/scripts/components/browser/actionItems/rename.vue b/administrator/components/com_media/resources/scripts/components/browser/actionItems/rename.vue index b2ef7221c88..bf89a55886c 100644 --- a/administrator/components/com_media/resources/scripts/components/browser/actionItems/rename.vue +++ b/administrator/components/com_media/resources/scripts/components/browser/actionItems/rename.vue @@ -3,8 +3,7 @@ ref="actionRenameButton" type="button" class="action-rename" - :aria-label="translate('COM_MEDIA_ACTION_RENAME')" - :title="translate('COM_MEDIA_ACTION_RENAME')" + @click.stop="openRenameModal()" @keyup.enter="openRenameModal()" @keyup.space="openRenameModal()" @focus="focused(true)" @@ -12,10 +11,12 @@ @keyup.esc="hideActions()" >