Click to expand the diff!
```diff
diff --git a/administrator/components/com_media/resources/scripts/store/state.es6.js b/administrator/components/com_media/resources/scripts/store/state.es6.js
index 7299979521a4..e161fe390fd5 100644
--- a/administrator/components/com_media/resources/scripts/store/state.es6.js
+++ b/administrator/components/com_media/resources/scripts/store/state.es6.js
@@ -14,32 +14,49 @@ if (options.providers === undefined || options.providers.length === 0) {
*
* @return {Array}
*/
-const getDrives = (adapterNames, provider) => {
- const drives = [];
- adapterNames.map((name) => drives.push({ root: `${provider}-${name}:/`, displayName: name }));
-
- return drives;
-};
+const getDrives = (adapterNames, provider) => adapterNames.map((name) => ({ root: `${provider}-${name}:/`, displayName: name }));
// Load disks from options
const loadedDisks = options.providers.map((disk) => ({
displayName: disk.displayName,
drives: getDrives(disk.adapterNames, disk.name),
}));
-const defaultDisk = loadedDisks.find((disk) => disk.drives.length > 0
- && disk.drives[0] !== undefined);
+
+const defaultDisk = loadedDisks.find((disk) => disk.drives.length > 0 && disk.drives[0] !== undefined);
+
if (!defaultDisk) {
throw new TypeError('No default media drive was found');
}
-// Override the storage if we have a path
+let currentPath;
+const storedState = JSON.parse(persistedStateOptions.storage.getItem(persistedStateOptions.key));
+
+// Gracefully use the given path, the session storage state or fall back to sensible default
if (options.currentPath) {
- const storedState = JSON.parse(persistedStateOptions.storage.getItem(persistedStateOptions.key));
- if (storedState && storedState.selectedDirectory
- && (storedState.selectedDirectory !== options.currentPath)) {
- storedState.selectedDirectory = options.currentPath;
- persistedStateOptions.storage.setItem(persistedStateOptions.key, JSON.stringify(storedState));
+ let useDrive = false;
+ Object.values(loadedDisks).forEach((drive) => drive.drives.forEach((curDrive) => {
+ if (options.currentPath.indexOf(curDrive.root) === 0) {
+ useDrive = true;
+ }
+ }));
+
+ if (useDrive) {
+ if ((storedState && storedState.selectedDirectory && storedState.selectedDirectory !== options.currentPath)) {
+ storedState.selectedDirectory = options.currentPath;
+ persistedStateOptions.storage.setItem(persistedStateOptions.key, JSON.stringify(storedState));
+ currentPath = options.currentPath;
+ } else {
+ currentPath = options.currentPath;
+ }
+ } else {
+ currentPath = defaultDisk.drives[0].root;
}
+} else if (storedState && storedState.selectedDirectory) {
+ currentPath = storedState.selectedDirectory;
+}
+
+if (!currentPath) {
+ currentPath = defaultDisk.drives[0].root;
}
// The initial state
@@ -60,7 +77,7 @@ export default {
files: [],
// The selected disk. Providers are ordered by plugin ordering, so we set the first provider
// in the list as the default provider and load first drive on it as default
- selectedDirectory: options.currentPath || defaultDisk.drives[0].root,
+ selectedDirectory: currentPath,
// The currently selected items
selectedItems: [],
// The state of the infobar
diff --git a/administrator/components/com_templates/src/View/Template/HtmlView.php b/administrator/components/com_templates/src/View/Template/HtmlView.php
index ebe575d3b22c..071238e8145e 100644
--- a/administrator/components/com_templates/src/View/Template/HtmlView.php
+++ b/administrator/components/com_templates/src/View/Template/HtmlView.php
@@ -28,7 +28,7 @@
// phpcs:enable PSR1.Files.SideEffects
/**
- * View to edit a template style.
+ * View to edit a template.
*
* @since 1.6
*/
diff --git a/administrator/components/com_templates/src/View/Templates/HtmlView.php b/administrator/components/com_templates/src/View/Templates/HtmlView.php
index ceef57d206b4..fa3bfbc64169 100644
--- a/administrator/components/com_templates/src/View/Templates/HtmlView.php
+++ b/administrator/components/com_templates/src/View/Templates/HtmlView.php
@@ -23,7 +23,7 @@
// phpcs:enable PSR1.Files.SideEffects
/**
- * View class for a list of template styles.
+ * View class for a list of templates.
*
* @since 1.6
*/
diff --git a/administrator/language/en-GB/plg_twofactorauth_totp.sys.ini b/administrator/language/en-GB/plg_twofactorauth_totp.sys.ini
index 1735c300a106..d8d618252874 100644
--- a/administrator/language/en-GB/plg_twofactorauth_totp.sys.ini
+++ b/administrator/language/en-GB/plg_twofactorauth_totp.sys.ini
@@ -5,4 +5,4 @@
; Obsolete since 4.2.0 -- The entire file must be removed in Joomla 5.0
PLG_TWOFACTORAUTH_TOTP="Two Factor Authentication - Google Authenticator"
-PLG_TWOFACTORAUTH_TOTP_XML_DESCRIPTION="Allows users on your site to use two factor authentication using Google Authenticator or other compatible time-based One Time Password generators such as FreeOTP. To use two factor authentication please edit the user profile and enable two factor authentication."
+PLG_TWOFACTORAUTH_TOTP_XML_DESCRIPTION="Allows users on your site to use two factor authentication using Google Authenticator or other compatible time-based One Time Password generators such as FreeOTP. To use two factor authentication please edit the user profile and enable two factor authentication."
diff --git a/build/media_source/com_media/scss/components/_media-toolbar.scss b/build/media_source/com_media/scss/components/_media-toolbar.scss
index 0691c82366c5..9cb0b9fceffe 100644
--- a/build/media_source/com_media/scss/components/_media-toolbar.scss
+++ b/build/media_source/com_media/scss/components/_media-toolbar.scss
@@ -1,7 +1,7 @@
.media-toolbar {
position: sticky;
top: 67px;
- z-index: 1;
+ z-index: 10;
display: flex;
flex-wrap: wrap;
padding: 0;
diff --git a/build/media_source/legacy/js/tabs-state.es5.js b/build/media_source/legacy/js/tabs-state.es5.js
index 56946759cdd0..0ee8bd82123d 100644
--- a/build/media_source/legacy/js/tabs-state.es5.js
+++ b/build/media_source/legacy/js/tabs-state.es5.js
@@ -4,7 +4,7 @@
*/
/**
- * JavaScript behavior to allow selected tab to be remained after save or page reload
+ * JavaScript behavior to allow selected tab to be remembered after save or page reload
* keeping state in sessionStorage with better handling of multiple tab widgets per page
* and not saving the state if there is no id in the url (like on the CREATE page of content)
*/
@@ -125,7 +125,7 @@ jQuery(function ($) {
var activeTabsHrefs = JSON.parse(sessionStorage.getItem(getStorageKey()));
// jQuery object with all tabs links
- var alltabs = $("a[data-toggle='tab']");
+ var alltabs = $("a[data-bs-toggle='tab']");
// When a tab is clicked, save its state!
alltabs.on("click", function (e) {
@@ -150,7 +150,7 @@ jQuery(function ($) {
// Click the tab
var parts = tabFakexPath.split("|");
- $.findXpath(parts[0]).find("a[data-toggle='tab'][href='" + parts[1] + "']").click();
+ $.findXpath(parts[0]).find("a[data-bs-toggle='tab'][href='" + parts[1] + "']").get(0).click();
});
diff --git a/build/media_source/plg_editors_codemirror/js/joomla-editor-codemirror.w-c.es6.js b/build/media_source/plg_editors_codemirror/js/joomla-editor-codemirror.w-c.es6.js
index ddb2ded4c233..5ca43dc8b9dc 100644
--- a/build/media_source/plg_editors_codemirror/js/joomla-editor-codemirror.w-c.es6.js
+++ b/build/media_source/plg_editors_codemirror/js/joomla-editor-codemirror.w-c.es6.js
@@ -63,6 +63,8 @@ class CodemirrorEditor extends HTMLElement {
// Fix the x-php error
if (['text/x-php', 'application/x-httpd-php', 'application/x-httpd-php-open'].includes(mode.mime)) {
editor.setOption('mode', 'php');
+ } else if (mode.mime === 'text/html') {
+ editor.setOption('mode', mode.mode);
} else {
editor.setOption('mode', mode.mime);
}
diff --git a/build/media_source/system/css/fields/calendar-rtl.css b/build/media_source/system/css/fields/calendar-rtl.css
index 258d48464999..d22f9db4d6c5 100644
--- a/build/media_source/system/css/fields/calendar-rtl.css
+++ b/build/media_source/system/css/fields/calendar-rtl.css
@@ -171,3 +171,8 @@ div.calendar-container table td.title { /* This holds the current "month, year"
background-repeat: no-repeat;
background-position: center;
}
+/* Fix cursor on js-btn and time select */
+.calendar-container select,
+.calendar-container .js-btn {
+ cursor: pointer;
+}
diff --git a/build/media_source/system/css/fields/calendar.css b/build/media_source/system/css/fields/calendar.css
index e04be321dc64..70dc7aa09bac 100644
--- a/build/media_source/system/css/fields/calendar.css
+++ b/build/media_source/system/css/fields/calendar.css
@@ -172,3 +172,8 @@ div.calendar-container table td.title { /* This holds the current "month, year"
background-repeat: no-repeat;
background-position: center;
}
+/* Fix cursor on js-btn and time select */
+.calendar-container select,
+.calendar-container .js-btn {
+ cursor: pointer;
+}
diff --git a/build/media_source/system/js/joomla-hidden-mail.w-c.es6.js b/build/media_source/system/js/joomla-hidden-mail.w-c.es6.js
index f45a709163bc..37a8b30751da 100644
--- a/build/media_source/system/js/joomla-hidden-mail.w-c.es6.js
+++ b/build/media_source/system/js/joomla-hidden-mail.w-c.es6.js
@@ -53,6 +53,10 @@ window.customElements.define('joomla-hidden-mail', class extends HTMLElement {
this.newElement.innerText = `${window.atob(this.getAttribute('first'))}@${window.atob(this.getAttribute('last'))}`;
}
+ // Remove class and style Attributes
+ this.removeAttribute('class');
+ this.removeAttribute('style');
+
// Remove the noscript message
this.innerText = '';
diff --git a/components/com_users/src/Controller/UserController.php b/components/com_users/src/Controller/UserController.php
index e29b33401c7e..ff814437d67f 100644
--- a/components/com_users/src/Controller/UserController.php
+++ b/components/com_users/src/Controller/UserController.php
@@ -144,10 +144,11 @@ public function logout()
// Check for a simple menu item id
if (is_numeric($return)) {
- $return = 'index.php?Itemid=' . $return;
+ $itemId = (int) $return;
+ $return = 'index.php?Itemid=' . $itemId;
if (Multilanguage::isEnabled()) {
- $language = $this->getModel('Login', 'Site')->getMenuLanguage($return);
+ $language = $this->getModel('Login', 'Site')->getMenuLanguage($itemId);
if ($language !== '*') {
$return .= '&lang=' . $language;
diff --git a/components/com_users/tmpl/profile/default_custom.php b/components/com_users/tmpl/profile/default_custom.php
index 6bf103ecd34b..1c0f0b5dc437 100644
--- a/components/com_users/tmpl/profile/default_custom.php
+++ b/components/com_users/tmpl/profile/default_custom.php
@@ -30,6 +30,8 @@
$customFields[$customField->name] = $customField;
}
+unset($tmp);
+
?>
$fieldset) : ?>
form->getFieldset($group); ?>
@@ -43,6 +45,11 @@
PR w związku ze zmianą oryginału https://github.com/joomla/joomla-cms/pull/39345 Poniżej zmiany w oryginale:
Click to expand the diff!
```diff diff --git a/administrator/components/com_media/resources/scripts/store/state.es6.js b/administrator/components/com_media/resources/scripts/store/state.es6.js index 7299979521a4..e161fe390fd5 100644 --- a/administrator/components/com_media/resources/scripts/store/state.es6.js +++ b/administrator/components/com_media/resources/scripts/store/state.es6.js @@ -14,32 +14,49 @@ if (options.providers === undefined || options.providers.length === 0) { * * @return {Array} */ -const getDrives = (adapterNames, provider) => { - const drives = []; - adapterNames.map((name) => drives.push({ root: `${provider}-${name}:/`, displayName: name })); - - return drives; -}; +const getDrives = (adapterNames, provider) => adapterNames.map((name) => ({ root: `${provider}-${name}:/`, displayName: name })); // Load disks from options const loadedDisks = options.providers.map((disk) => ({ displayName: disk.displayName, drives: getDrives(disk.adapterNames, disk.name), })); -const defaultDisk = loadedDisks.find((disk) => disk.drives.length > 0 - && disk.drives[0] !== undefined); + +const defaultDisk = loadedDisks.find((disk) => disk.drives.length > 0 && disk.drives[0] !== undefined); + if (!defaultDisk) { throw new TypeError('No default media drive was found'); } -// Override the storage if we have a path +let currentPath; +const storedState = JSON.parse(persistedStateOptions.storage.getItem(persistedStateOptions.key)); + +// Gracefully use the given path, the session storage state or fall back to sensible default if (options.currentPath) { - const storedState = JSON.parse(persistedStateOptions.storage.getItem(persistedStateOptions.key)); - if (storedState && storedState.selectedDirectory - && (storedState.selectedDirectory !== options.currentPath)) { - storedState.selectedDirectory = options.currentPath; - persistedStateOptions.storage.setItem(persistedStateOptions.key, JSON.stringify(storedState)); + let useDrive = false; + Object.values(loadedDisks).forEach((drive) => drive.drives.forEach((curDrive) => { + if (options.currentPath.indexOf(curDrive.root) === 0) { + useDrive = true; + } + })); + + if (useDrive) { + if ((storedState && storedState.selectedDirectory && storedState.selectedDirectory !== options.currentPath)) { + storedState.selectedDirectory = options.currentPath; + persistedStateOptions.storage.setItem(persistedStateOptions.key, JSON.stringify(storedState)); + currentPath = options.currentPath; + } else { + currentPath = options.currentPath; + } + } else { + currentPath = defaultDisk.drives[0].root; } +} else if (storedState && storedState.selectedDirectory) { + currentPath = storedState.selectedDirectory; +} + +if (!currentPath) { + currentPath = defaultDisk.drives[0].root; } // The initial state @@ -60,7 +77,7 @@ export default { files: [], // The selected disk. Providers are ordered by plugin ordering, so we set the first provider // in the list as the default provider and load first drive on it as default - selectedDirectory: options.currentPath || defaultDisk.drives[0].root, + selectedDirectory: currentPath, // The currently selected items selectedItems: [], // The state of the infobar diff --git a/administrator/components/com_templates/src/View/Template/HtmlView.php b/administrator/components/com_templates/src/View/Template/HtmlView.php index ebe575d3b22c..071238e8145e 100644 --- a/administrator/components/com_templates/src/View/Template/HtmlView.php +++ b/administrator/components/com_templates/src/View/Template/HtmlView.php @@ -28,7 +28,7 @@ // phpcs:enable PSR1.Files.SideEffects /** - * View to edit a template style. + * View to edit a template. * * @since 1.6 */ diff --git a/administrator/components/com_templates/src/View/Templates/HtmlView.php b/administrator/components/com_templates/src/View/Templates/HtmlView.php index ceef57d206b4..fa3bfbc64169 100644 --- a/administrator/components/com_templates/src/View/Templates/HtmlView.php +++ b/administrator/components/com_templates/src/View/Templates/HtmlView.php @@ -23,7 +23,7 @@ // phpcs:enable PSR1.Files.SideEffects /** - * View class for a list of template styles. + * View class for a list of templates. * * @since 1.6 */ diff --git a/administrator/language/en-GB/plg_twofactorauth_totp.sys.ini b/administrator/language/en-GB/plg_twofactorauth_totp.sys.ini index 1735c300a106..d8d618252874 100644 --- a/administrator/language/en-GB/plg_twofactorauth_totp.sys.ini +++ b/administrator/language/en-GB/plg_twofactorauth_totp.sys.ini @@ -5,4 +5,4 @@ ; Obsolete since 4.2.0 -- The entire file must be removed in Joomla 5.0 PLG_TWOFACTORAUTH_TOTP="Two Factor Authentication - Google Authenticator" -PLG_TWOFACTORAUTH_TOTP_XML_DESCRIPTION="Allows users on your site to use two factor authentication using Google Authenticator or other compatible time-based One Time Password generators such as FreeOTP. To use two factor authentication please edit the user profile and enable two factor authentication." +PLG_TWOFACTORAUTH_TOTP_XML_DESCRIPTION="Allows users on your site to use two factor authentication using Google Authenticator or other compatible time-based One Time Password generators such as FreeOTP. To use two factor authentication please edit the user profile and enable two factor authentication." diff --git a/build/media_source/com_media/scss/components/_media-toolbar.scss b/build/media_source/com_media/scss/components/_media-toolbar.scss index 0691c82366c5..9cb0b9fceffe 100644 --- a/build/media_source/com_media/scss/components/_media-toolbar.scss +++ b/build/media_source/com_media/scss/components/_media-toolbar.scss @@ -1,7 +1,7 @@ .media-toolbar { position: sticky; top: 67px; - z-index: 1; + z-index: 10; display: flex; flex-wrap: wrap; padding: 0; diff --git a/build/media_source/legacy/js/tabs-state.es5.js b/build/media_source/legacy/js/tabs-state.es5.js index 56946759cdd0..0ee8bd82123d 100644 --- a/build/media_source/legacy/js/tabs-state.es5.js +++ b/build/media_source/legacy/js/tabs-state.es5.js @@ -4,7 +4,7 @@ */ /** - * JavaScript behavior to allow selected tab to be remained after save or page reload + * JavaScript behavior to allow selected tab to be remembered after save or page reload * keeping state in sessionStorage with better handling of multiple tab widgets per page * and not saving the state if there is no id in the url (like on the CREATE page of content) */ @@ -125,7 +125,7 @@ jQuery(function ($) { var activeTabsHrefs = JSON.parse(sessionStorage.getItem(getStorageKey())); // jQuery object with all tabs links - var alltabs = $("a[data-toggle='tab']"); + var alltabs = $("a[data-bs-toggle='tab']"); // When a tab is clicked, save its state! alltabs.on("click", function (e) { @@ -150,7 +150,7 @@ jQuery(function ($) { // Click the tab var parts = tabFakexPath.split("|"); - $.findXpath(parts[0]).find("a[data-toggle='tab'][href='" + parts[1] + "']").click(); + $.findXpath(parts[0]).find("a[data-bs-toggle='tab'][href='" + parts[1] + "']").get(0).click(); }); diff --git a/build/media_source/plg_editors_codemirror/js/joomla-editor-codemirror.w-c.es6.js b/build/media_source/plg_editors_codemirror/js/joomla-editor-codemirror.w-c.es6.js index ddb2ded4c233..5ca43dc8b9dc 100644 --- a/build/media_source/plg_editors_codemirror/js/joomla-editor-codemirror.w-c.es6.js +++ b/build/media_source/plg_editors_codemirror/js/joomla-editor-codemirror.w-c.es6.js @@ -63,6 +63,8 @@ class CodemirrorEditor extends HTMLElement { // Fix the x-php error if (['text/x-php', 'application/x-httpd-php', 'application/x-httpd-php-open'].includes(mode.mime)) { editor.setOption('mode', 'php'); + } else if (mode.mime === 'text/html') { + editor.setOption('mode', mode.mode); } else { editor.setOption('mode', mode.mime); } diff --git a/build/media_source/system/css/fields/calendar-rtl.css b/build/media_source/system/css/fields/calendar-rtl.css index 258d48464999..d22f9db4d6c5 100644 --- a/build/media_source/system/css/fields/calendar-rtl.css +++ b/build/media_source/system/css/fields/calendar-rtl.css @@ -171,3 +171,8 @@ div.calendar-container table td.title { /* This holds the current "month, year" background-repeat: no-repeat; background-position: center; } +/* Fix cursor on js-btn and time select */ +.calendar-container select, +.calendar-container .js-btn { + cursor: pointer; +} diff --git a/build/media_source/system/css/fields/calendar.css b/build/media_source/system/css/fields/calendar.css index e04be321dc64..70dc7aa09bac 100644 --- a/build/media_source/system/css/fields/calendar.css +++ b/build/media_source/system/css/fields/calendar.css @@ -172,3 +172,8 @@ div.calendar-container table td.title { /* This holds the current "month, year" background-repeat: no-repeat; background-position: center; } +/* Fix cursor on js-btn and time select */ +.calendar-container select, +.calendar-container .js-btn { + cursor: pointer; +} diff --git a/build/media_source/system/js/joomla-hidden-mail.w-c.es6.js b/build/media_source/system/js/joomla-hidden-mail.w-c.es6.js index f45a709163bc..37a8b30751da 100644 --- a/build/media_source/system/js/joomla-hidden-mail.w-c.es6.js +++ b/build/media_source/system/js/joomla-hidden-mail.w-c.es6.js @@ -53,6 +53,10 @@ window.customElements.define('joomla-hidden-mail', class extends HTMLElement { this.newElement.innerText = `${window.atob(this.getAttribute('first'))}@${window.atob(this.getAttribute('last'))}`; } + // Remove class and style Attributes + this.removeAttribute('class'); + this.removeAttribute('style'); + // Remove the noscript message this.innerText = ''; diff --git a/components/com_users/src/Controller/UserController.php b/components/com_users/src/Controller/UserController.php index e29b33401c7e..ff814437d67f 100644 --- a/components/com_users/src/Controller/UserController.php +++ b/components/com_users/src/Controller/UserController.php @@ -144,10 +144,11 @@ public function logout() // Check for a simple menu item id if (is_numeric($return)) { - $return = 'index.php?Itemid=' . $return; + $itemId = (int) $return; + $return = 'index.php?Itemid=' . $itemId; if (Multilanguage::isEnabled()) { - $language = $this->getModel('Login', 'Site')->getMenuLanguage($return); + $language = $this->getModel('Login', 'Site')->getMenuLanguage($itemId); if ($language !== '*') { $return .= '&lang=' . $language; diff --git a/components/com_users/tmpl/profile/default_custom.php b/components/com_users/tmpl/profile/default_custom.php index 6bf103ecd34b..1c0f0b5dc437 100644 --- a/components/com_users/tmpl/profile/default_custom.php +++ b/components/com_users/tmpl/profile/default_custom.php @@ -30,6 +30,8 @@ $customFields[$customField->name] = $customField; } +unset($tmp); + ?> $fieldset) : ?> form->getFieldset($group); ?> @@ -43,6 +45,11 @@+ + type === 'Subform' && $field->fieldname === 'row') : ?> + name, $matches); ?> + fieldname = $matches[1]; ?> + hidden && $field->type !== 'Spacer') : ?>-
title; ?>
diff --git a/installation/language/de-AT/langmetadata.xml b/installation/language/de-AT/langmetadata.xml
index 1ebe6c62faa4..e4ee75bfe055 100644
--- a/installation/language/de-AT/langmetadata.xml
+++ b/installation/language/de-AT/langmetadata.xml
@@ -1,8 +1,8 @@
German (Austria)
- 4.2.2
- September 2022
+ 4.2.5
+ 2022-11
J!German
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/de-CH/langmetadata.xml b/installation/language/de-CH/langmetadata.xml
index f79192ae58c3..7c37d15b84b8 100644
--- a/installation/language/de-CH/langmetadata.xml
+++ b/installation/language/de-CH/langmetadata.xml
@@ -1,8 +1,8 @@
German (Switzerland)
- 4.2.2
- September 2022
+ 4.2.5
+ 2022-11
J!German
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/de-DE/langmetadata.xml b/installation/language/de-DE/langmetadata.xml
index 0a0464f7153b..8bedf01a60cf 100644
--- a/installation/language/de-DE/langmetadata.xml
+++ b/installation/language/de-DE/langmetadata.xml
@@ -1,8 +1,8 @@
German (Germany)
- 4.2.2
- September 2022
+ 4.2.5
+ 2022-11
J!German
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/de-LI/langmetadata.xml b/installation/language/de-LI/langmetadata.xml
index b0c204481a85..0bdc0c52fb43 100644
--- a/installation/language/de-LI/langmetadata.xml
+++ b/installation/language/de-LI/langmetadata.xml
@@ -1,8 +1,8 @@
German (Lichtenstein)
- 4.2.2
- September 2022
+ 4.2.5
+ 2022-11
J!German
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/de-LU/langmetadata.xml b/installation/language/de-LU/langmetadata.xml
index e91ddc46697b..f7cba790deb5 100644
--- a/installation/language/de-LU/langmetadata.xml
+++ b/installation/language/de-LU/langmetadata.xml
@@ -1,8 +1,8 @@
German (Luxembourg)
- 4.2.2
- September 2022
+ 4.2.5
+ 2022-11
J!German
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/layouts/joomla/editors/buttons/button.php b/layouts/joomla/editors/buttons/button.php
index c7a0712f6d17..32a31ab3af0f 100644
--- a/layouts/joomla/editors/buttons/button.php
+++ b/layouts/joomla/editors/buttons/button.php
@@ -18,7 +18,7 @@
$class = 'btn btn-secondary';
$class .= ($button->get('class')) ? ' ' . $button->get('class') : null;
$class .= ($button->get('modal')) ? ' modal-button' : null;
- $href = '#' . strtolower($button->get('name')) . '_modal';
+ $href = '#' . $button->get('editor') . '_' . strtolower($button->get('name')) . '_modal';
$link = ($button->get('link')) ? Uri::base() . $button->get('link') : null;
$onclick = ($button->get('onclick')) ? ' onclick="' . $button->get('onclick') . '"' : '';
$title = ($button->get('title')) ? $button->get('title') : $button->get('text');
diff --git a/layouts/joomla/editors/buttons/modal.php b/layouts/joomla/editors/buttons/modal.php
index 771de06474f0..fd0c06c21ee6 100644
--- a/layouts/joomla/editors/buttons/modal.php
+++ b/layouts/joomla/editors/buttons/modal.php
@@ -22,7 +22,7 @@
$class = ($button->get('class')) ? $button->get('class') : null;
$class .= ($button->get('modal')) ? ' modal-button' : null;
-$href = '#' . strtolower($button->get('name')) . '_modal';
+$href = '#' . $button->get('editor') . '_' . strtolower($button->get('name')) . '_modal';
$link = ($button->get('link')) ? Uri::base() . $button->get('link') : null;
$onclick = ($button->get('onclick')) ? ' onclick="' . $button->get('onclick') . '"' : '';
$title = ($button->get('title')) ? $button->get('title') : $button->get('text');
@@ -38,7 +38,7 @@
if (null !== $button->get('id')) {
$id = str_replace(' ', '', $button->get('id'));
} else {
- $id = strtolower($button->get('name')) . '_modal';
+ $id = $button->get('editor') . '_' . strtolower($button->get('name')) . '_modal';
}
// @todo: J4: Move Make buttons fullscreen on smaller devices per https://github.com/joomla/joomla-cms/pull/23091
diff --git a/libraries/src/Editor/Editor.php b/libraries/src/Editor/Editor.php
index 17c23a733bd8..9f9d0e504f48 100644
--- a/libraries/src/Editor/Editor.php
+++ b/libraries/src/Editor/Editor.php
@@ -251,6 +251,8 @@ public function getButtons($editor, $buttons = true)
continue;
}
+ $button->editor = $editor;
+
$result[] = $button;
}
diff --git a/libraries/src/Form/Field/TagField.php b/libraries/src/Form/Field/TagField.php
index f572a9cc73ab..2561b55c36f1 100644
--- a/libraries/src/Form/Field/TagField.php
+++ b/libraries/src/Form/Field/TagField.php
@@ -193,8 +193,7 @@ protected function getOptions()
// Merge the used values into the most used tags
if (!empty($this->value) && is_array($this->value)) {
- $topIds = array_merge($topIds, $this->value);
- $topIds = array_keys(array_flip($topIds));
+ $topIds = array_unique(array_merge($topIds, $this->value));
}
// Set the default limit for the main query
@@ -203,7 +202,8 @@ protected function getOptions()
if (!empty($topIds)) {
// Filter the ids to the most used tags and the selected tags
$preQuery = clone $query;
- $preQuery->whereIn($db->quoteName('a.id'), $topIds);
+ $preQuery->clear('limit')
+ ->whereIn($db->quoteName('a.id'), $topIds);
$db->setQuery($preQuery);
diff --git a/libraries/src/Installer/Adapter/ModuleAdapter.php b/libraries/src/Installer/Adapter/ModuleAdapter.php
index 6e02fb5c182c..06030931dda6 100644
--- a/libraries/src/Installer/Adapter/ModuleAdapter.php
+++ b/libraries/src/Installer/Adapter/ModuleAdapter.php
@@ -246,12 +246,11 @@ protected function finaliseUninstall(): bool
if (\count($modules)) {
// Ensure the list is sane
$modules = ArrayHelper::toInteger($modules);
- $modID = implode(',', $modules);
// Wipe out any items assigned to menus
$query = $db->getQuery(true)
->delete($db->quoteName('#__modules_menu'))
- ->where($db->quoteName('moduleid') . ' IN (' . $modID . ')');
+ ->whereIn($db->quoteName('moduleid'), $modules);
$db->setQuery($query);
try {
@@ -560,7 +559,7 @@ protected function storeExtension()
// Install failed, roll back changes
throw new \RuntimeException(
Text::sprintf(
- 'JLIB_INSTALLER_ABORT_MOD_INSTALL_ALLREADY_EXISTS',
+ 'JLIB_INSTALLER_ABORT_ALREADY_EXISTS',
Text::_('JLIB_INSTALLER_' . $this->route),
$this->name
)
diff --git a/libraries/src/Log/DelegatingPsrLogger.php b/libraries/src/Log/DelegatingPsrLogger.php
index 5c775c07b456..aa91fd7f8ded 100644
--- a/libraries/src/Log/DelegatingPsrLogger.php
+++ b/libraries/src/Log/DelegatingPsrLogger.php
@@ -79,7 +79,7 @@ public function log($level, $message, array $context = array())
{
// Make sure the log level is valid
if (!\array_key_exists($level, $this->priorityMap)) {
- throw new \InvalidArgumentException('An invalid log level has been given.');
+ throw new InvalidArgumentException('An invalid log level has been given.');
}
// Map the level to Joomla's priority
@@ -101,7 +101,7 @@ public function log($level, $message, array $context = array())
// Joomla's logging API will only process a string or a LogEntry object, if $message is an object without __toString() we can't use it
if (!\is_string($message) && !($message instanceof LogEntry)) {
if (!\is_object($message) || !method_exists($message, '__toString')) {
- throw new \InvalidArgumentException(
+ throw new InvalidArgumentException(
'The message must be a string, a LogEntry object, or an object implementing the __toString() method.'
);
}
diff --git a/libraries/src/MVC/View/FormView.php b/libraries/src/MVC/View/FormView.php
index 37abe48a38ec..e7afeb9a8eb2 100644
--- a/libraries/src/MVC/View/FormView.php
+++ b/libraries/src/MVC/View/FormView.php
@@ -13,6 +13,7 @@
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Object\CMSObject;
+use Joomla\CMS\Table\TableInterface;
use Joomla\CMS\Toolbar\ToolbarHelper;
// phpcs:disable PSR1.Files.SideEffects
@@ -42,6 +43,13 @@ class FormView extends HtmlView
*/
protected $item;
+ /**
+ * The item primary key name
+ *
+ * @var string
+ */
+ protected $keyName;
+
/**
* The model state
*
@@ -142,13 +150,13 @@ protected function initializeView()
$this->form = $this->get('Form');
$this->item = $this->get('Item');
$this->state = $this->get('State');
+ $table = $this->get('Table');
+
+ $this->keyName = $table instanceof TableInterface ? $table->getKeyName() : 'id';
+ $action = empty($this->item->{$this->keyName}) ? '_NEW' : '_EDIT';
// Set default toolbar title
- if ($this->item->id) {
- $this->toolbarTitle = Text::_(strtoupper($this->option . '_MANAGER_' . $this->getName() . '_EDIT'));
- } else {
- $this->toolbarTitle = Text::_(strtoupper($this->option . '_MANAGER_' . $this->getName() . '_NEW'));
- }
+ $this->toolbarTitle = Text::_(strtoupper($this->option . '_MANAGER_' . $this->getName() . $action));
}
/**
@@ -164,7 +172,7 @@ protected function addToolbar()
$user = Factory::getUser();
$userId = $user->id;
- $isNew = ($this->item->id == 0);
+ $isNew = empty($this->item->{$this->keyName});
$viewName = $this->getName();
$checkedOut = $this->getModel()->isCheckedOut($this->item);
$canDo = $this->canDo;
diff --git a/package.json b/package.json
index ac747c36b658..02af4dd92578 100644
--- a/package.json
+++ b/package.json
@@ -25,12 +25,13 @@
"update": "node build/build.js --copy-assets && node build/build.js --build-pages && node build/build.js --compile-js && node build/build.js --compile-css && node build/build.js --compile-bs && node build/build.js --com-media",
"gzip": "node build/build.js --gzip",
"versioning": "node build/build.js --versioning",
+ "browserlist:update": "npx browserslist@latest --update-db",
"cypress:install": "cypress install",
"cypress:open": "cypress open",
"cypress:run": "cypress run"
},
"browserslist": [
- "last 1 version",
+ "last 2 major version",
"not ie < 11"
],
"dependencies": {
diff --git a/plugins/content/emailcloak/emailcloak.php b/plugins/content/emailcloak/emailcloak.php
index 449d71e4eea5..41f00ef8358a 100644
--- a/plugins/content/emailcloak/emailcloak.php
+++ b/plugins/content/emailcloak/emailcloak.php
@@ -126,14 +126,16 @@ protected function _cloak(&$text, &$params)
* the mailto: prefix...
*/
$pattern = $this->_getPattern($searchEmail, $searchEmail);
- $pattern = str_replace('"mailto:', '"http://mce_host([\x20-\x7f][^<>]+/)', $pattern);
+ $pattern = str_replace('"mailto:', '"([\x20-\x7f][^<>]+/)', $pattern);
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[3][0];
$mailText = $regs[5][0];
+ $attribsBefore = $regs[1][0];
+ $attribsAfter = $regs[4][0];
// Check to see if mail text is different from mail addy
- $replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText);
+ $replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 1, $attribsBefore, $attribsAfter);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0]));
@@ -145,14 +147,16 @@ protected function _cloak(&$text, &$params)
* the mailto: prefix...
*/
$pattern = $this->_getPattern($searchEmail, $searchText);
- $pattern = str_replace('"mailto:', '"http://mce_host([\x20-\x7f][^<>]+/)', $pattern);
+ $pattern = str_replace('"mailto:', '"([\x20-\x7f][^<>]+/)', $pattern);
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[3][0];
$mailText = $regs[5][0];
+ $attribsBefore = $regs[1][0];
+ $attribsAfter = $regs[4][0];
// Check to see if mail text is different from mail addy
- $replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 0);
+ $replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 0, $attribsBefore, $attribsAfter);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0]));
@@ -167,9 +171,11 @@ protected function _cloak(&$text, &$params)
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[2][0];
$mailText = $regs[4][0];
+ $attribsBefore = $regs[1][0];
+ $attribsAfter = $regs[3][0];
// Check to see if mail text is different from mail addy
- $replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText);
+ $replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 1, $attribsBefore, $attribsAfter);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0]));
@@ -184,9 +190,11 @@ protected function _cloak(&$text, &$params)
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[2][0];
$mailText = $regs[4][0] . $regs[5][0] . $regs[6][0];
+ $attribsBefore = $regs[1][0];
+ $attribsAfter = $regs[3][0];
// Check to see if mail text is different from mail addy
- $replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText);
+ $replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 1, $attribsBefore, $attribsAfter);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0]));
@@ -201,8 +209,10 @@ protected function _cloak(&$text, &$params)
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[2][0];
$mailText = $regs[4][0] . $regs[5][0] . $regs[6][0];
+ $attribsBefore = $regs[1][0];
+ $attribsAfter = $regs[3][0];
- $replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 0);
+ $replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 0, $attribsBefore, $attribsAfter);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0]));
@@ -217,8 +227,10 @@ protected function _cloak(&$text, &$params)
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[2][0];
$mailText = $regs[4][0];
+ $attribsBefore = $regs[1][0];
+ $attribsAfter = $regs[3][0];
- $replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 0);
+ $replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 0, $attribsBefore, $attribsAfter);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0]));
@@ -233,8 +245,10 @@ protected function _cloak(&$text, &$params)
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[2][0];
$mailText = $regs[4][0];
+ $attribsBefore = $regs[1][0];
+ $attribsAfter = $regs[3][0];
- $replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 0);
+ $replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 0, $attribsBefore, $attribsAfter);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0]));
@@ -249,8 +263,10 @@ protected function _cloak(&$text, &$params)
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[2][0];
$mailText = $regs[4][0] . $regs[5][0];
+ $attribsBefore = $regs[1][0];
+ $attribsAfter = $regs[3][0];
- $replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText);
+ $replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 1, $attribsBefore, $attribsAfter);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0]));
@@ -265,8 +281,10 @@ protected function _cloak(&$text, &$params)
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[2][0];
$mailText = $regs[4][0] . $regs[5][0];
+ $attribsBefore = $regs[1][0];
+ $attribsAfter = $regs[3][0];
- $replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 0);
+ $replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 0, $attribsBefore, $attribsAfter);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0]));
@@ -281,12 +299,14 @@ protected function _cloak(&$text, &$params)
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[2][0] . $regs[3][0];
$mailText = $regs[5][0];
+ $attribsBefore = $regs[1][0];
+ $attribsAfter = $regs[4][0];
// Needed for handling of Body parameter
$mail = str_replace('&', '&', $mail);
// Check to see if mail text is different from mail addy
- $replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText);
+ $replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 1, $attribsBefore, $attribsAfter);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0]));
@@ -301,11 +321,13 @@ protected function _cloak(&$text, &$params)
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[2][0] . $regs[3][0];
$mailText = $regs[5][0];
+ $attribsBefore = $regs[1][0];
+ $attribsAfter = $regs[4][0];
// Needed for handling of Body parameter
$mail = str_replace('&', '&', $mail);
- $replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 0);
+ $replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 0, $attribsBefore, $attribsAfter);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0]));
@@ -320,9 +342,11 @@ protected function _cloak(&$text, &$params)
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[2][0] . $regs[3][0];
$mailText = $regs[5][0] . $regs[6][0] . $regs[7][0];
+ $attribsBefore = $regs[1][0];
+ $attribsAfter = $regs[4][0];
// Check to see if mail text is different from mail addy
- $replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText);
+ $replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 1, $attribsBefore, $attribsAfter);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0]));
@@ -337,8 +361,10 @@ protected function _cloak(&$text, &$params)
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[2][0] . $regs[3][0];
$mailText = $regs[5][0] . $regs[6][0] . $regs[7][0];
+ $attribsBefore = $regs[1][0];
+ $attribsAfter = $regs[4][0];
- $replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 0);
+ $replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 0, $attribsBefore, $attribsAfter);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0]));
@@ -351,14 +377,16 @@ protected function _cloak(&$text, &$params)
$pattern = $this->_getPattern($searchEmailLink, $searchImage);
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
- $mail = $regs[1][0] . $regs[2][0] . $regs[3][0];
+ $mail = $regs[2][0] . $regs[3][0];
$mailText = $regs[5][0];
+ $attribsBefore = $regs[1][0];
+ $attribsAfter = $regs[4][0];
// Needed for handling of Body parameter
$mail = str_replace('&', '&', $mail);
// Check to see if mail text is different from mail addy
- $replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 0);
+ $replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 0, $attribsBefore, $attribsAfter);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0]));
@@ -371,14 +399,16 @@ protected function _cloak(&$text, &$params)
$pattern = $this->_getPattern($searchEmailLink, $searchImage . $searchEmail);
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
- $mail = $regs[1][0] . $regs[2][0] . $regs[3][0];
- $mailText = $regs[4][0] . $regs[5][0] . $regs[6][0];
+ $mail = $regs[2][0] . $regs[3][0];
+ $mailText = $regs[5][0] . $regs[6][0];
+ $attribsBefore = $regs[1][0];
+ $attribsAfter = $regs[4][0];
// Needed for handling of Body parameter
$mail = str_replace('&', '&', $mail);
// Check to see if mail text is different from mail addy
- $replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText);
+ $replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 1, $attribsBefore, $attribsAfter);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0]));
@@ -391,14 +421,16 @@ protected function _cloak(&$text, &$params)
$pattern = $this->_getPattern($searchEmailLink, $searchImage . $searchText);
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
- $mail = $regs[1][0] . $regs[2][0] . $regs[3][0];
- $mailText = $regs[4][0] . $regs[5][0] . $regs[6][0];
+ $mail = $regs[2][0] . $regs[3][0];
+ $mailText = $regs[5][0] . $regs[6][0];
+ $attribsBefore = $regs[1][0];
+ $attribsAfter = $regs[4][0];
// Needed for handling of Body parameter
$mail = str_replace('&', '&', $mail);
// Check to see if mail text is different from mail addy
- $replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 0);
+ $replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 0, $attribsBefore, $attribsAfter);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0]));
@@ -409,11 +441,11 @@ protected function _cloak(&$text, &$params)
* or
* The '<[^<]*>(*SKIP)(*F)|' trick is used to exclude this kind of occurrences
*/
- $pattern = '~<[^<]*>(*SKIP)(*F)|' . $searchEmail . '~i';
+ $pattern = '~<[^<]*(?(*SKIP)(*F)|(<\w.*\"' . $searchEmail . '\".*\/\>)~i';
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[1][0];
- $replacement = HTMLHelper::_('email.cloak', $mail, $mode);
+ $replacement = HTMLHelper::_('email.cloak', $mail, 0, $mail);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[1][1], strlen($mail));
diff --git a/plugins/content/fields/fields.php b/plugins/content/fields/fields.php
index 7068c1e1cef3..8dd061f12296 100644
--- a/plugins/content/fields/fields.php
+++ b/plugins/content/fields/fields.php
@@ -63,7 +63,7 @@ public function onContentPrepare($context, &$item, &$params, $page = 0)
}
// Prepare the intro text
- if (property_exists($item, 'introtext') && strpos($item->introtext, 'field') !== false) {
+ if (property_exists($item, 'introtext') && is_string($item->introtext) && strpos($item->introtext, 'field') !== false) {
$item->introtext = $this->prepare($item->introtext, $context, $item);
}
}
```