diff --git a/administrator/components/com_users/tmpl/users/default.php b/administrator/components/com_users/tmpl/users/default.php
index e1c4c55b378ea..4d65a2aea2f30 100644
--- a/administrator/components/com_users/tmpl/users/default.php
+++ b/administrator/components/com_users/tmpl/users/default.php
@@ -103,7 +103,7 @@
- id); ?>
+ id, false, 'cid', 'cb', Text::_($item->title)); ?>
|
%2s)"
-COM_ASSOCIATIONS_TITLE_LIST="Multilingual Associations (%1s > %2s)"
+COM_ASSOCIATIONS_TITLE_EDIT="Multilingual Associations: Edit Associations (%1$s > %2$s)"
+COM_ASSOCIATIONS_TITLE_LIST="Multilingual Associations (%1$s > %2$s)"
COM_ASSOCIATIONS_TITLE_LIST_SELECT="Multilingual Associations: Select Item Type and Language"
COM_ASSOCIATIONS_XML_DESCRIPTION="Improved multilingual content management component"
COM_ASSOCIATIONS_YOU_ARE_NOT_ALLOWED_TO_CHECKIN_THIS_ITEM="You can't check in this item"
diff --git a/administrator/language/en-GB/com_config.ini b/administrator/language/en-GB/com_config.ini
index d0108e2fc99bb..81bf14c4af751 100644
--- a/administrator/language/en-GB/com_config.ini
+++ b/administrator/language/en-GB/com_config.ini
@@ -19,17 +19,21 @@ COM_CONFIG_ERROR_CONFIG_EXTENSION_NOT_FOUND="The Global Configuration extension
COM_CONFIG_ERROR_CONFIGURATION_PHP_NOTUNWRITABLE="Could not make configuration.php unwritable."
COM_CONFIG_ERROR_CONFIGURATION_PHP_NOTWRITABLE="Could not make configuration.php writable."
COM_CONFIG_ERROR_CUSTOM_CACHE_PATH_NOTWRITABLE_USING_DEFAULT="The folder at %1$s is not writable and cannot be used for the cache, using the default %2$s instead."
+COM_CONFIG_ERROR_CUSTOM_LOG_PATH_NOTWRITABLE_USING_DEFAULT="The folder at %1$s is not writable and cannot be used for the log folder, using the default %2$s instead."
COM_CONFIG_ERROR_CUSTOM_SESSION_FILESYSTEM_PATH_NOTWRITABLE_USING_DEFAULT="The folder at %s is not writable and cannot be used to store session data, the default PHP path will be used instead."
+COM_CONFIG_ERROR_CUSTOM_TEMP_PATH_NOTWRITABLE_USING_DEFAULT="The folder at %1$s is not writable and cannot be used for the temp folder, using the default %2$s instead."
COM_CONFIG_ERROR_DATABASE_ENCRYPTION_CONN_NOT_ENCRYPT="You have selected database connection encryption to be used, and a connection could be established, but it was not encrypted. The reason might be that the database server is configured to fall back to an unencrypted connection in case of bad encryption parameters. Either check and correct the database encryption parameters, or change field \"Connection Encryption\" back to \"Default (server controlled)\"."
COM_CONFIG_ERROR_DATABASE_ENCRYPTION_FILE_FIELD_BAD="The file entered in field \"%s\" does not exist or is not accessible."
COM_CONFIG_ERROR_DATABASE_ENCRYPTION_FILE_FIELD_EMPTY="Field \"%s\" is empty or doesn't contain a valid path."
COM_CONFIG_ERROR_DATABASE_ENCRYPTION_LOCALHOST="You have entered \"localhost\" as host name. Connecting to the database with connection encryption might fail with this. Either change \"localhost\" to \"127.0.0.1\" or \"::1\" or a different host name, or change field \"Connection Encryption\" back to \"Default (server controlled)\"."
COM_CONFIG_ERROR_DATABASE_ENCRYPTION_SRV_NOT_SUPPORTS="The database server doesn't support connection encryption. Either enable TLS (often called SSL in docs) support on your database server, or change field \"Connection Encryption\" back to \"Default (server controlled)\"."
COM_CONFIG_ERROR_DATABASE_NOT_AVAILABLE="Database connection test failed with the following error: %s: %s Database connection settings changes were not saved."
+COM_CONFIG_ERROR_LOG_PATH_NOTWRITABLE="The log folder is not writable: %s"
COM_CONFIG_ERROR_REMOVING_SUPER_ADMIN="You can't remove your own Super User permissions."
COM_CONFIG_ERROR_ROOT_ASSET_NOT_FOUND="The asset for global configuration could not be found. Permissions have not been saved."
COM_CONFIG_ERROR_SSL_NOT_AVAILABLE="HTTPS has not been enabled as it is not available on this server. HTTPS connection test failed with the following error: %s"
COM_CONFIG_ERROR_SSL_NOT_AVAILABLE_HTTP_CODE="HTTPS version of the site returned an invalid HTTP status code."
+COM_CONFIG_ERROR_TMP_PATH_NOTWRITABLE="The temp folder is not writable: %s"
COM_CONFIG_ERROR_UNKNOWN_BEFORE_SAVING="A plugin reported an unknown error before saving the configuration."
COM_CONFIG_ERROR_WRITE_FAILED="Could not write to the configuration file"
COM_CONFIG_FIELD_BODY_LABEL="Body"
@@ -72,11 +76,11 @@ COM_CONFIG_FIELD_ERROR_REPORTING_LABEL="Error Reporting"
COM_CONFIG_FIELD_FEED_EMAIL_LABEL="Feed Email Address"
COM_CONFIG_FIELD_FILESYSTEM_PATH_DESC="The filesystem path where session data will be stored. If empty, the system's temporary directory will be used."
COM_CONFIG_FIELD_FILESYSTEM_PATH_LABEL="Session Save Path"
-COM_CONFIG_FIELD_FILTERS_CUSTOM_BLACK_LIST="Custom Blacklist"
-COM_CONFIG_FIELD_FILTERS_DEFAULT_BLACK_LIST="Default Blacklist"
+COM_CONFIG_FIELD_FILTERS_CUSTOM_FORBIDDEN_LIST="Custom Forbidden List"
+COM_CONFIG_FIELD_FILTERS_DEFAULT_FORBIDDEN_LIST="Default Forbidden List"
COM_CONFIG_FIELD_FILTERS_NO_FILTER="No Filtering"
COM_CONFIG_FIELD_FILTERS_NO_HTML="No HTML"
-COM_CONFIG_FIELD_FILTERS_WHITE_LIST="Whitelist"
+COM_CONFIG_FIELD_FILTERS_ALLOWED_LIST="Allowed List"
COM_CONFIG_FIELD_FORCE_SSL_LABEL="Force HTTPS"
COM_CONFIG_FIELD_FTP_ENABLE_LABEL="Enable FTP"
COM_CONFIG_FIELD_FTP_HOST_LABEL="FTP Host"
@@ -177,6 +181,10 @@ COM_CONFIG_FIELD_VALUE_SMTP="SMTP"
COM_CONFIG_FIELD_VALUE_SSL="SSL/TLS"
COM_CONFIG_FIELD_VALUE_SYSTEM_DEFAULT="System Default"
COM_CONFIG_FIELD_VALUE_TLS="STARTTLS"
+COM_CONFIG_FIELD_WEBSERVICES_CORSOFFF_LABEL="Enable CORS"
+COM_CONFIG_FIELD_WEBSERVICES_CORS_ALLOW_HEADERS_DESC="Specifies the header(s) sent back in response to a preflight request. Default: Content-Type,X-Joomla-Token"
+COM_CONFIG_FIELD_WEBSERVICES_CORS_ALLOW_METHODS_DESC="Specifies the Web service method(s) allowed to access on this site, sent back in response to a preflight request. Default: all methods available for the requested route."
+COM_CONFIG_FIELD_WEBSERVICES_CORS_ALLOW_ORIGIN_DESC="Specifies the origin allowed to access Web services on this site, sent back in response to a preflight request. Default: * (=all)."
COM_CONFIG_FIELDSET_TAGS_LABEL="Tags"
COM_CONFIG_FILTER_OPTION_SELECT_EXTENSION="- Select Extension -"
COM_CONFIG_FRONTEDITING_LABEL="Inline Editing"
@@ -223,13 +231,8 @@ COM_CONFIG_TEXT_FILTERS="Text Filters"
COM_CONFIG_TEXT_FILTERS_DESC="These text filter settings will be applied to all text editor fields in the selected groups. These filtering options give more control over the HTML your content providers submit. You can be as strict or as liberal as you require to suit your site's needs. The filtering is opt-in and the default settings provide good protection against markup commonly associated with website attacks."
COM_CONFIG_TEXT_FILTERS_NOTE="WARNING: You have configured a parent group with the setting 'No Filtering' - this setting can't be overridden in child groups and any other configured filter will not be applied."
COM_CONFIG_TEXT_FILTERS_SUMMARY="Expand for notes about the text filters"
+COM_CONFIG_WEBSERVICES_SETTINGS="Web Services"
COM_CONFIG_XML_DESCRIPTION="Configuration Manager"
; Alternate language strings for the rules form field
JLIB_RULES_SETTING_NOTES_COM_CONFIG="If you change the setting, it will apply to this and all child groups, components and content. Note that: Inherited means that the permissions from the parent group will be used. Denied means that no matter what the parent group's setting is, the group being edited can't take this action. Allowed means that the group being edited will be able to take this action (but if this is in conflict with the parent group it will have no impact; a conflict will be indicated by Not Allowed (Locked) under Calculated Settings). Not Set is used only for the Public group in global configuration. The Public group is the parent of all other groups. If a permission is not set, it is treated as deny but can be changed for child groups, components, categories and items."
-
-COM_CONFIG_WEBSERVICES_SETTINGS="Webservices"
-COM_CONFIG_FIELD_WEBSERVICES_CORSOFFF_LABEL="Enable CORS"
-COM_CONFIG_FIELD_WEBSERVICES_CORS_ALLOW_ORIGIN_DESC="Specifies the origin allowed to access webservices on this site,sent back in response to a preflight request. Default: * (=all)."
-COM_CONFIG_FIELD_WEBSERVICES_CORS_ALLOW_HEADERS_DESC="Specifies the header(s) sent back in response to a preflight request. Default: Content-Type,X-Joomla-Token"
-COM_CONFIG_FIELD_WEBSERVICES_CORS_ALLOW_METHODS_DESC="Specifies the webservice method(s) allowed to access on this site, sent back in response to a preflight request. Default: all methods available for the requested route."
diff --git a/administrator/language/en-GB/com_cpanel.ini b/administrator/language/en-GB/com_cpanel.ini
index dc8df9ce65380..7b32132e63c0d 100644
--- a/administrator/language/en-GB/com_cpanel.ini
+++ b/administrator/language/en-GB/com_cpanel.ini
@@ -30,7 +30,7 @@ COM_CPANEL_MSG_STATS_COLLECTION_BODY="Since Joomla! 3.5 a statistics plugin w
COM_CPANEL_MSG_STATS_COLLECTION_TITLE="Stats Collection in Joomla"
COM_CPANEL_MSG_TEXTFILTER3919_BODY=" As part of our security team's review, we have made some changes to the default settings for the global text filters in a new Joomla installation. The default setting for the 'Public', 'Guest' and 'Registered' groups is now 'No HTML'. As these changes are only applied to new installations, we strongly recommend that you review these changes and update your site from: System -> Global Configuration -> Text Filters "
COM_CPANEL_MSG_TEXTFILTER3919_TITLE="Updated Text Filter Recommendations"
-COM_CPANEL_MSG_UPDATEDEFAULTSETTINGS_BODY="As part of our security team's review, we have made some changes to the default settings in a new Joomla installation. As these changes are only applied to new installations, we strongly recommend that you review these changes and update your site. The changed settings are: - Global Configuration > Text Filters: The default \"Administrator\" user group has changed from \"No Filtering\" to \"Default Blacklist\"
- Users > Send Password: The option to send a user their password in plain text when an account is created is now disabled by default
- Media Manager: Flash files (\"swf\" file extension and \"application/x-shockwave-flash\" MIME Type) are not allowed to be uploaded
- Articles > Show Email: The option to show an email icon with articles is disabled by default
We have created a dedicated documentation page explaining these changes. "
+COM_CPANEL_MSG_UPDATEDEFAULTSETTINGS_BODY="As part of our security team's review, we have made some changes to the default settings in a new Joomla installation. As these changes are only applied to new installations, we strongly recommend that you review these changes and update your site. The changed settings are: - Global Configuration > Text Filters: The default \"Administrator\" user group has changed from \"No Filtering\" to \"Default Forbidden List\"
- Users > Send Password: The option to send a user their password in plain text when an account is created is now disabled by default
- Media Manager: Flash files (\"swf\" file extension and \"application/x-shockwave-flash\" MIME Type) are not allowed to be uploaded
- Articles > Show Email: The option to show an email icon with articles is disabled by default
We have created a dedicated documentation page explaining these changes. "
COM_CPANEL_MSG_UPDATEDEFAULTSETTINGS_TITLE="Updated site security recommendations"
COM_CPANEL_TITLE_SYSTEM_PANEL="System Panel"
COM_CPANEL_UNPUBLISH_MODULE_ERROR="Error unpublishing the module"
diff --git a/administrator/language/en-GB/com_csp.ini b/administrator/language/en-GB/com_csp.ini
index abccdaf06c9d7..31f99e41fb63b 100644
--- a/administrator/language/en-GB/com_csp.ini
+++ b/administrator/language/en-GB/com_csp.ini
@@ -9,7 +9,7 @@ COM_CSP_AUTO_UNSAFE_INLINE_WARNING="You have configured a rule that still allows
COM_CSP_COLLECTING_TRASH_WARNING="The Content Security Policy is in detect mode. Items that have been trashed will not be detected again until they are removed from the trash."
COM_CSP_CONFIGURATION="Content Security Policy: Options"
; Please do not translate the following language string
-COM_CSP_CONTENTSECURITYPOLICY="Content Security Policy (CSP)"
+COM_CSP_CONTENTSECURITYPOLICY="Content Security Policy (CSP)"
COM_CSP_CONTENTSECURITYPOLICY_CLIENT="Client"
; Please do not translate the following language string
COM_CSP_CONTENTSECURITYPOLICY_FRAME_ANCESTORS_SELF_ENABLED="frame-ancestors 'self'"
@@ -19,7 +19,7 @@ COM_CSP_CONTENTSECURITYPOLICY_MODE_AUTO="Automatic"
COM_CSP_CONTENTSECURITYPOLICY_MODE_CUSTOM="Custom"
COM_CSP_CONTENTSECURITYPOLICY_MODE_DETECT="Detect"
; Please only change the URL in the following language string
-COM_CSP_CONTENTSECURITYPOLICY_NONCE_ENABLED="Nonce"
+COM_CSP_CONTENTSECURITYPOLICY_NONCE_ENABLED="Nonce"
COM_CSP_CONTENTSECURITYPOLICY_NONCE_ENABLED_DESC="Enable the whitelist for specific inline scripts using a cryptographic nonce (number used once) for all scripts and styles using the Joomla API. Specifying a nonce makes a modern browser ignore 'unsafe-inline' which should still be set for older browsers without nonce support."
; Please do not translate 'Content-Security-Policy' & 'Content-Security-Policy-Report-Only' in the following language string
COM_CSP_CONTENTSECURITYPOLICY_REPORT_ONLY_DESC="Use the header 'Content-Security-Policy-Report-Only' instead of 'Content-Security-Policy'."
@@ -27,12 +27,12 @@ COM_CSP_CONTENTSECURITYPOLICY_REPORT_ONLY_DESC="Use the header 'Content-Security
COM_CSP_CONTENTSECURITYPOLICY_REPORT_ONLY="Report-Only"
COM_CSP_CONTENTSECURITYPOLICY_STRICT_DYNAMIC_ENABLED="strict-dynamic"
; Please do not translate 'strict-dynamic', 'self' and 'unsafe-inline' in the following language string
-COM_CSP_CONTENTSECURITYPOLICY_STRICT_DYNAMIC_ENABLED_DESC="The strict-dynamic source expression specifies that the trust explicitly given to a script present in the markup, by accompanying it with a nonce or a hash, shall be propagated to all the scripts loaded by that root script. At the same time, any whitelist or source expressions such as 'self' or 'unsafe-inline' will be ignored."
+COM_CSP_CONTENTSECURITYPOLICY_STRICT_DYNAMIC_ENABLED_DESC="The strict-dynamic source expression specifies that the trust explicitly given to a script present in the markup, by accompanying it with a nonce or a hash, shall be propagated to all the scripts loaded by that root script. At the same time, any allowed or source expressions such as 'self' or 'unsafe-inline' will be ignored."
; Please only change the URL in the following language string
-COM_CSP_CONTENTSECURITYPOLICY_SCRIPT_HASHES_ENABLED="Script hashes"
+COM_CSP_CONTENTSECURITYPOLICY_SCRIPT_HASHES_ENABLED="Script hashes"
COM_CSP_CONTENTSECURITYPOLICY_SCRIPT_HASHES_ENABLED_DESC="Enable the optional hash based whitelist inline scripts using a cryptographic hash for all scripts using the Joomla API. Specifying hashes makes a modern browser ignore 'unsafe-inline' which should still be set for older browsers without hash support."
; Please only change the URL in the following language string
-COM_CSP_CONTENTSECURITYPOLICY_STYLE_HASHES_ENABLED="Style hashes"
+COM_CSP_CONTENTSECURITYPOLICY_STYLE_HASHES_ENABLED="Style hashes"
COM_CSP_CONTENTSECURITYPOLICY_STYLE_HASHES_ENABLED_DESC="Enable the optional hash based whitelist inline styles using a cryptographic hash for all styles using the Joomla API. Specifying hashes makes a modern browser ignore 'unsafe-inline' which should still be set for older browsers without hash support."
COM_CSP_CONTENTSECURITYPOLICY_VALUES="Add Directive"
COM_CSP_CONTENTSECURITYPOLICY_VALUES_DIRECTIVE="Policy Directive"
diff --git a/administrator/language/en-GB/com_finder.ini b/administrator/language/en-GB/com_finder.ini
index 312f16648dfeb..ab17f5ab8b9bb 100644
--- a/administrator/language/en-GB/com_finder.ini
+++ b/administrator/language/en-GB/com_finder.ini
@@ -151,7 +151,7 @@ COM_FINDER_INDEXER_MESSAGE_OPTIMIZE="The index tables are being optimised for th
COM_FINDER_INDEXER_MESSAGE_RUNNING="Your content is being indexed. Do not close this window."
COM_FINDER_ITEM_X_ONLY="%s Only"
COM_FINDER_ITEMS="Content"
-COM_FINDER_LOGGING_DISABLED="Gathering of statistics is disabled. Enable it in the Options."
+COM_FINDER_LOGGING_DISABLED="Gathering of statistics is disabled. Enable it in the %s."
COM_FINDER_MANAGER_SEARCHES="Smart Search: Search Term Analysis"
COM_FINDER_MAPS="Maps"
COM_FINDER_MAPS_CONFIRM_DELETE_PROMPT="Are you sure you want to delete the selected map(s)?"
diff --git a/administrator/language/en-GB/com_installer.ini b/administrator/language/en-GB/com_installer.ini
index ee3d5a8852a14..6b0e15a64e260 100644
--- a/administrator/language/en-GB/com_installer.ini
+++ b/administrator/language/en-GB/com_installer.ini
@@ -138,6 +138,7 @@ COM_INSTALLER_MSG_DISCOVER_PURGEDDISCOVEREDEXTENSIONS="Cleared discovered extens
COM_INSTALLER_MSG_ERROR_CANT_CONNECT_TO_UPDATESERVER="Can't connect to %s"
COM_INSTALLER_MSG_INSTALL_ENTER_A_URL="Please enter a URL"
COM_INSTALLER_MSG_INSTALL_INVALID_URL="Invalid URL"
+COM_INSTALLER_MSG_INSTALL_INVALID_URL_SCHEME="Please enter a valid URL starting with http or https."
COM_INSTALLER_MSG_INSTALL_NO_FILE_SELECTED="No file selected."
COM_INSTALLER_MSG_INSTALL_PATH_DOES_NOT_HAVE_A_VALID_PACKAGE="Path does not have a valid package."
COM_INSTALLER_MSG_INSTALL_PLEASE_ENTER_A_PACKAGE_DIRECTORY="Please enter a package folder."
@@ -249,7 +250,7 @@ COM_INSTALLER_TYPE_TYPE_TEMPLATE="template"
COM_INSTALLER_UNABLE_TO_FIND_INSTALL_PACKAGE="Unable to find install package."
COM_INSTALLER_UNABLE_TO_INSTALL_JOOMLA_PACKAGE="The Joomla package cannot be installed through the Extension Manager. Please use the Joomla! Update component to update Joomla."
COM_INSTALLER_UNINSTALL_ERROR="Error uninstalling %s."
-COM_INSTALLER_UNINSTALL_ERROR_LOCKED_EXTENSION="The extension \"%1s\" (ID %2s) is locked and cannot be uninstalled."
+COM_INSTALLER_UNINSTALL_ERROR_LOCKED_EXTENSION="The extension \"%1$s\" (ID %2$s) is locked and cannot be uninstalled."
COM_INSTALLER_UNINSTALL_SUCCESS="Uninstalling the %s was successful."
COM_INSTALLER_UNPACK_ERROR="Failed to extract file: %s"
COM_INSTALLER_UPDATE_FILTER_SEARCH_DESC="Search in extension name. Prefix with ID:, UID: or EID: to search for an update ID, update site ID or extension ID."
@@ -260,7 +261,7 @@ COM_INSTALLER_UPDATE_MISSING_DOWNLOADKEY_LABEL_N_1="One extension update cannot
COM_INSTALLER_UPDATE_TABLE_CAPTION="Table of Extensions with Updates"
COM_INSTALLER_UPDATESITE_DISABLE="Disable update site"
COM_INSTALLER_UPDATESITE_DISABLED="Disabled update site"
-COM_INSTALLER_UPDATESITE_EDIT_TIP="Edit the Update Site '%1s' for '%2s'"
+COM_INSTALLER_UPDATESITE_EDIT_TIP="Edit the Update Site '%1$s' for '%2$s'"
COM_INSTALLER_UPDATESITE_EDIT_TITLE="Edit Update Site"
COM_INSTALLER_UPDATESITE_ENABLE="Enable update site"
COM_INSTALLER_UPDATESITE_ENABLED="Enabled update site"
diff --git a/administrator/language/en-GB/com_joomlaupdate.ini b/administrator/language/en-GB/com_joomlaupdate.ini
index f9318f07f7ffa..dcdd2d2e8a79f 100644
--- a/administrator/language/en-GB/com_joomlaupdate.ini
+++ b/administrator/language/en-GB/com_joomlaupdate.ini
@@ -60,7 +60,7 @@ COM_JOOMLAUPDATE_VIEW_DEFAULT_EXTENSIONS_PROBABLY_COMPATIBLE_NOTES="The exten
COM_JOOMLAUPDATE_VIEW_DEFAULT_EXTENSIONS_REQUIRING_UPDATES_TO_BE_COMPATIBLE="Update Required"
COM_JOOMLAUPDATE_VIEW_DEFAULT_EXTENSIONS_REQUIRING_UPDATES_TO_BE_COMPATIBLE_NOTES=" Please update these extensions before updating Joomla. Please take extra care if this updated version of the extension is not also listed as compatible with your current version of Joomla. "
COM_JOOMLAUPDATE_VIEW_DEFAULT_EXTENSIONS_UPDATE_SERVER_OFFERS_NO_COMPATIBLE_VERSION="Update Information Unavailable"
-COM_JOOMLAUPDATE_VIEW_DEFAULT_EXTENSIONS_UPDATE_SERVER_OFFERS_NO_COMPATIBLE_VERSION_NOTES="Extension does not use the Joomla update system or the developer has provided no compatibility information."
+COM_JOOMLAUPDATE_VIEW_DEFAULT_EXTENSIONS_UPDATE_SERVER_OFFERS_NO_COMPATIBLE_VERSION_NOTES="Extension does not offer a compatible version for the selected target version of Joomla. This could mean the extension does not use the Joomla update system or the developer has not provided compatibility information for this Joomla version yet."
COM_JOOMLAUPDATE_VIEW_DEFAULT_SHOW_LESS_EXTENSION_COMPATIBILITY_INFORMATION="[ Less Detail %s ]"
COM_JOOMLAUPDATE_VIEW_DEFAULT_SHOW_MORE_EXTENSION_COMPATIBILITY_INFORMATION="[ More Detail %s ]"
COM_JOOMLAUPDATE_VIEW_DEFAULT_EXTENSION_COMPATIBLE="Compatible"
@@ -101,7 +101,7 @@ COM_JOOMLAUPDATE_VIEW_DEFAULT_PACKAGE="Update package URL"
COM_JOOMLAUPDATE_VIEW_DEFAULT_PACKAGE_REINSTALL="Reinstall package URL"
COM_JOOMLAUPDATE_VIEW_DEFAULT_PHP_VERSION_NOT_SUPPORTED="Your PHP version is not supported"
COM_JOOMLAUPDATE_VIEW_DEFAULT_PHP_VERSION_NOT_SUPPORTED_DESC="An update to Joomla %1$s was found, but your currently installed PHP version does not match the minimum requirements for Joomla %1$s."
-COM_JOOMLAUPDATE_VIEW_DEFAULT_PREUPDATE_CHECK="Pre-Update Check"
+COM_JOOMLAUPDATE_VIEW_DEFAULT_PREUPDATE_CHECK="Pre-Update Check for Joomla %s"
COM_JOOMLAUPDATE_VIEW_DEFAULT_RECOMMENDED="Recommended"
COM_JOOMLAUPDATE_VIEW_DEFAULT_RECOMMENDED_SETTINGS="Recommended PHP Settings"
COM_JOOMLAUPDATE_VIEW_DEFAULT_RECOMMENDED_SETTINGS_DESC="These settings are recommended for PHP in order to ensure full compatibility with Joomla. However, Joomla! will still operate if your settings do not quite match the recommended configuration."
@@ -115,7 +115,7 @@ COM_JOOMLAUPDATE_VIEW_DEFAULT_UPDATES_INFO_CUSTOM="You are on the "%s"
COM_JOOMLAUPDATE_VIEW_DEFAULT_UPDATES_INFO_DEFAULT="You are on the "%s" update channel. Through this channel you'll receive notifications for all updates of the current Joomla release (4.x)"
COM_JOOMLAUPDATE_VIEW_DEFAULT_UPDATES_INFO_NEXT="You are on the "%s" update channel. Through this channel you'll receive notifications for all updates of the current Joomla release (4.x) and you will also be notified when the future major release (5.x) will be available. Before upgrading to 5.x you'll need to assess its compatibility with your environment."
COM_JOOMLAUPDATE_VIEW_DEFAULT_UPDATES_INFO_TESTING="You are on the "%s" update channel. This channel is designed for testing new releases and fixes in Joomla. It is only intended for JBS (Joomla Bug Squad™) members and others within the Joomla community who are testing. Do not use this setting on a production site."
-COM_JOOMLAUPDATE_VIEW_DEFAULT_UPLOAD_INTRO="You can use this feature to update Joomla if your server is behind a firewall or otherwise unable to contact the update servers. First download the Joomla Upgrade Package in ZIP format from the official Joomla download page. Then use the fields below to upload and install it."
+COM_JOOMLAUPDATE_VIEW_DEFAULT_UPLOAD_INTRO="You can use this feature to update Joomla if your server is behind a firewall or otherwise unable to contact the update servers. First download the Joomla Upgrade Package in ZIP format from the official Joomla download page. Then use the fields below to upload and install it."
COM_JOOMLAUPDATE_VIEW_UPDATE_BYTESEXTRACTED="Bytes extracted"
COM_JOOMLAUPDATE_VIEW_UPDATE_BYTESREAD="Bytes read"
COM_JOOMLAUPDATE_VIEW_UPDATE_CHECKSUM_WRONG="File Checksum Failed"
diff --git a/administrator/language/en-GB/com_media.ini b/administrator/language/en-GB/com_media.ini
index cd04449687603..8eb37f1b8fe50 100644
--- a/administrator/language/en-GB/com_media.ini
+++ b/administrator/language/en-GB/com_media.ini
@@ -33,8 +33,8 @@ COM_MEDIA_FIELD_CHECK_MIME_DESC="Use MIME Magic or Fileinfo to attempt to verify
COM_MEDIA_FIELD_CHECK_MIME_LABEL="Check MIME Types"
COM_MEDIA_FIELD_IGNORED_EXTENSIONS_DESC="Ignored file extensions for MIME type checking and restricted uploads."
COM_MEDIA_FIELD_IGNORED_EXTENSIONS_LABEL="Ignored Extensions"
-COM_MEDIA_FIELD_ILLEGAL_MIME_TYPES_DESC="A comma separated list of illegal MIME types to upload (blacklist)."
-COM_MEDIA_FIELD_ILLEGAL_MIME_TYPES_LABEL="Illegal MIME Types"
+COM_MEDIA_FIELD_ILLEGAL_MIME_TYPES_DESC="A comma separated list of forbidden MIME types to upload."
+COM_MEDIA_FIELD_ILLEGAL_MIME_TYPES_LABEL="Forbidden MIME Types"
COM_MEDIA_FIELD_LEGAL_EXTENSIONS_DESC="Extensions (file types) you are allowed to upload (comma separated)."
COM_MEDIA_FIELD_LEGAL_EXTENSIONS_LABEL="Legal Extensions (File Types)"
COM_MEDIA_FIELD_LEGAL_IMAGE_EXTENSIONS_DESC="Image extensions (file types) you are allowed to upload (comma separated). These are used to check for valid image headers."
diff --git a/administrator/language/en-GB/com_privacy.ini b/administrator/language/en-GB/com_privacy.ini
index 69851230e9ee3..4b3f1a5da3a46 100644
--- a/administrator/language/en-GB/com_privacy.ini
+++ b/administrator/language/en-GB/com_privacy.ini
@@ -32,7 +32,7 @@ COM_PRIVACY_CONSENTS_TOOLBAR_INVALIDATE_ALL_CONFIRM_MSG="Do you really want to i
COM_PRIVACY_CONSENTS_TOOLBAR_INVALIDATE_CONFIRM_MSG="Do you really want to invalidate the selected consents? This will force users to have to give their consent again."
COM_PRIVACY_CORE_CAPABILITY_COMMUNICATION_WITH_JOOMLA_ORG="When a network connection is available, a Joomla installation will attempt to communicate with the joomla.org servers for various capabilities, to include:- Checking for updates for the Joomla application
- Help screens for core Joomla extensions
- The Install from Web service (opt-in)
- The statistics collection server (opt-in)
As with all HTTP requests, the IP address of your server will be transmitted as part of the request. For information on how Joomla processes data on its servers, please review our privacy policy."
; The placeholder for this key is the configured log path for the site.
-COM_PRIVACY_CORE_CAPABILITY_LOGGING_IP_ADDRESS="Joomla's logging system records the IP address of the visitor which led to a message being written to its log files. These log files are used to record various activity on a Joomla site, including information related to core updates, invalid login attempts, unhandled errors, and development information such as the use of deprecated APIs. The format of these log files may be customised by any extension which configures a logger, therefore you are encouraged to download and review the log files for your website which may be found at `%s`."
+COM_PRIVACY_CORE_CAPABILITY_LOGGING_IP_ADDRESS="Joomla's logging system records the IP address of the visitor which leads to a message being written to its log files. These log files are used to record various activity on a Joomla site, including information related to core updates, invalid login attempts, unhandled errors, and development information such as the use of deprecated APIs. The format of these log files may be customised by any extension which configures a logger, therefore you are encouraged to download and review the log files for your website which may be found at `%s`."
COM_PRIVACY_CORE_CAPABILITY_SESSION_IP_ADDRESS_AND_COOKIE="All requests to a Joomla website start a session which stores the IP address in the session data and creates a session cookie in the user's browser. The IP address is used as a security measure to help protect against potential session hijacking attacks and this information is deleted once the session has expired and its data purged. The session cookie's name is based on a randomly generated hash and therefore does not have a constant identifier. The session cookie is destroyed once the session has expired or the user has exited their browser."
COM_PRIVACY_DASHBOARD_BADGE_ACTIVE_REQUESTS_0="0 Active Requests"
COM_PRIVACY_DASHBOARD_BADGE_ACTIVE_REQUESTS_1="1 Active Request"
diff --git a/administrator/language/en-GB/com_templates.ini b/administrator/language/en-GB/com_templates.ini
index 2b2c92a7c7ed4..47cff0d49119f 100644
--- a/administrator/language/en-GB/com_templates.ini
+++ b/administrator/language/en-GB/com_templates.ini
@@ -187,7 +187,6 @@ COM_TEMPLATES_OVERRIDE_CREATED_DATE="Added to the list"
COM_TEMPLATES_OVERRIDE_FAILED="Failed to create override."
COM_TEMPLATES_OVERRIDE_MODIFIED_DATE="Last change via Update"
COM_TEMPLATES_OVERRIDE_SOURCE="Update Source"
-COM_TEMPLATES_OVERRIDE_SUCCESS="Override created."
COM_TEMPLATES_OVERRIDE_TEMPLATE_FILE="Template File"
COM_TEMPLATES_OVERRIDE_UPTODATE="Overridden files are up to date. Nothing has been changed in the last extension or Joomla update."
COM_TEMPLATES_OVERRIDES="Override Files"
diff --git a/administrator/language/en-GB/install.xml b/administrator/language/en-GB/install.xml
index ef96bcd63ba56..3824c23b558e1 100644
--- a/administrator/language/en-GB/install.xml
+++ b/administrator/language/en-GB/install.xml
@@ -3,7 +3,7 @@
English (en-GB)
en-GB
4.0.0
- January 2021
+ February 2021
Joomla! Project
admin@joomla.org
www.joomla.org
diff --git a/administrator/language/en-GB/joomla.ini b/administrator/language/en-GB/joomla.ini
index f8fb7c62733c9..f7cddb5954177 100644
--- a/administrator/language/en-GB/joomla.ini
+++ b/administrator/language/en-GB/joomla.ini
@@ -456,7 +456,7 @@ JGLOBAL_FILTER_GROUPS_DESC="This sets the user groups that you want filters appl
JGLOBAL_FILTER_GROUPS_LABEL="Filter Groups"
JGLOBAL_FILTER_TAGS_DESC="2. List additional tags, separating each tag name with a space or comma. For example: p,div,span."
JGLOBAL_FILTER_TAGS_LABEL="Filter Tags2"
-JGLOBAL_FILTER_TYPE_DESC="1. Blacklist allows all tags and attributes except for those in the blacklist. -- Tags for the Default Blacklist include: 'applet', 'body', 'bgsound', 'base', 'basefont', 'canvas', 'embed', 'frame', 'frameset', 'head', 'html', 'id', 'iframe', 'ilayer', 'layer', 'link', 'meta', 'name', 'object', 'script', 'style', 'title', 'xml' -- Attributes for the Default Blacklist include: 'action', 'background', 'codebase', 'dynsrc', 'lowsrc', 'formaction' -- You can blacklist additional tags and attributes by adding to the Filter Tags and Filter Attributes fields, separating each tag or attribute name with a comma. -- Custom Blacklist allows you to override the Default Blacklist. Add the tags and attributes to be blacklisted in the Filter Tags and Filter Attributes fields.Whitelist allows only the tags listed in the Filter Tags and Filter Attributes fields. No HTML removes all HTML tags from the content when it is saved. Please note that these settings work regardless of the editor that you are using. Even if you are using a WYSIWYG editor, the filtering settings may strip additional tags and attributes prior to saving information in the database."
+JGLOBAL_FILTER_TYPE_DESC="1. Forbidden List allows all tags and attributes except for those listed. -- Tags for the Default Forbidden List include: 'applet', 'body', 'bgsound', 'base', 'basefont', 'canvas', 'embed', 'frame', 'frameset', 'head', 'html', 'id', 'iframe', 'ilayer', 'layer', 'link', 'meta', 'name', 'object', 'script', 'style', 'title', 'xml' -- Attributes for the Default Forbidden List include: 'action', 'background', 'codebase', 'dynsrc', 'lowsrc', 'formaction' -- You can forbid additional tags and attributes by adding to the Filter Tags and Filter Attributes fields, separating each tag or attribute name with a comma. -- Custom Forbidden List allows you to override the Default Forbidden List. Add the tags and attributes to be forbidden in the Filter Tags and Filter Attributes fields. Allowed List allows only the tags listed in the Filter Tags and Filter Attributes fields. No HTML removes all HTML tags from the content when it is saved. Please note that these settings work regardless of the editor that you are using. Even if you are using a WYSIWYG editor, the filtering settings may strip additional tags and attributes prior to saving information in the database."
JGLOBAL_FILTER_TYPE_LABEL="Filter Type1"
JGLOBAL_FILTERED_BY="Filtered by:"
JGLOBAL_FULL_TEXT="Full Text"
@@ -1022,10 +1022,10 @@ JWARNING_UNPUBLISH_MUST_SELECT="You must select at least one item to unpublish."
JWORKFLOW="Workflow: %s"
JWORKFLOW_ENABLED_LABEL="Enable Workflow"
JWORKFLOW_EXECUTE_TRANSITION="Select the transition to execute on this item."
-JWORKFLOW_EXTENSION_BLACKLIST_DESCRIPTION="Disable this plugin for listed extensions."
-JWORKFLOW_EXTENSION_BLACKLIST_LABEL="Extension Blacklist"
-JWORKFLOW_EXTENSION_WHITELIST_DESCRIPTION="Activate this plugin only for listed extensions. If used all other extensions are disabled."
-JWORKFLOW_EXTENSION_WHITELIST_LABEL="Extension Whitelist"
+JWORKFLOW_EXTENSION_FORBIDDEN_DESCRIPTION="Disable this plugin for listed extensions."
+JWORKFLOW_EXTENSION_FORBIDDEN_LABEL="Forbidden Extensions"
+JWORKFLOW_EXTENSION_ALLOWED_DESCRIPTION="Activate this plugin only for listed extensions. If used all other extensions are disabled."
+JWORKFLOW_EXTENSION_ALLOWED_LABEL="Allowed Extensions"
JWORKFLOW_FIELD_COMPONENT_SECTIONS_TEXT="%1$s: %2$s"
JWORKFLOW_SHOW_TRANSITIONS_FOR_THIS_ITEM="Show the transition selection to execute a transition on this item."
JWORKFLOW_TITLE="Workflow"
diff --git a/administrator/language/en-GB/langmetadata.xml b/administrator/language/en-GB/langmetadata.xml
index 80e9d0ae125a0..6ba3a825b4279 100644
--- a/administrator/language/en-GB/langmetadata.xml
+++ b/administrator/language/en-GB/langmetadata.xml
@@ -2,7 +2,7 @@
English (en-GB)
4.0.0
- January 2021
+ February 2021
Joomla! Project
admin@joomla.org
www.joomla.org
diff --git a/administrator/language/en-GB/mod_version.ini b/administrator/language/en-GB/mod_version.ini
index 293cb0ee99d94..819acf768e97e 100644
--- a/administrator/language/en-GB/mod_version.ini
+++ b/administrator/language/en-GB/mod_version.ini
@@ -5,4 +5,4 @@
MOD_VERSION="Joomla! Version Information"
MOD_VERSION_CURRENT_VERSION_TEXT="The currently installed Joomla! version is \"%s\""
-MOD_VERSION_XML_DESCRIPTION="This module displays the Joomla! version."
+MOD_VERSION_XML_DESCRIPTION="This module displays the Joomla! version and is intended to be displayed in the 'status' position."
diff --git a/administrator/language/en-GB/mod_version.sys.ini b/administrator/language/en-GB/mod_version.sys.ini
index 43507fc71fbe9..8e14420661695 100644
--- a/administrator/language/en-GB/mod_version.sys.ini
+++ b/administrator/language/en-GB/mod_version.sys.ini
@@ -5,4 +5,4 @@
MOD_VERSION="Joomla! Version Information"
MOD_VERSION_LAYOUT_DEFAULT="Default"
-MOD_VERSION_XML_DESCRIPTION="This module displays the Joomla! version."
+MOD_VERSION_XML_DESCRIPTION="This module displays the Joomla! version and is intended to be displayed in the 'status' position."
diff --git a/administrator/language/en-GB/plg_api-authentication_basic.ini b/administrator/language/en-GB/plg_api-authentication_basic.ini
index c64e498e96975..2665ad7613be7 100644
--- a/administrator/language/en-GB/plg_api-authentication_basic.ini
+++ b/administrator/language/en-GB/plg_api-authentication_basic.ini
@@ -4,4 +4,4 @@
; Note : All ini files need to be saved as UTF-8
PLG_API-AUTHENTICATION_BASIC="API Authentication - Basic Auth"
-PLG_API-AUTHENTICATION_BASIC_XML_DESCRIPTION="Used to allow basic authentication to Web Services in Joomla."
+PLG_API-AUTHENTICATION_BASIC_XML_DESCRIPTION="Used to allow basic authentication to Web services in Joomla."
diff --git a/administrator/language/en-GB/plg_api-authentication_basic.sys.ini b/administrator/language/en-GB/plg_api-authentication_basic.sys.ini
index c64e498e96975..2665ad7613be7 100644
--- a/administrator/language/en-GB/plg_api-authentication_basic.sys.ini
+++ b/administrator/language/en-GB/plg_api-authentication_basic.sys.ini
@@ -4,4 +4,4 @@
; Note : All ini files need to be saved as UTF-8
PLG_API-AUTHENTICATION_BASIC="API Authentication - Basic Auth"
-PLG_API-AUTHENTICATION_BASIC_XML_DESCRIPTION="Used to allow basic authentication to Web Services in Joomla."
+PLG_API-AUTHENTICATION_BASIC_XML_DESCRIPTION="Used to allow basic authentication to Web services in Joomla."
diff --git a/administrator/language/en-GB/plg_api-authentication_token.ini b/administrator/language/en-GB/plg_api-authentication_token.ini
index 1066093ef5e73..4cef68f8d73c6 100644
--- a/administrator/language/en-GB/plg_api-authentication_token.ini
+++ b/administrator/language/en-GB/plg_api-authentication_token.ini
@@ -4,4 +4,4 @@
; Note : All ini files need to be saved as UTF-8
PLG_API-AUTHENTICATION_TOKEN="API Authentication - Joomla Token"
-PLG_API-AUTHENTICATION_TOKEN_XML_DESCRIPTION="Used to allow token-based authentication to Web Services in Joomla."
+PLG_API-AUTHENTICATION_TOKEN_XML_DESCRIPTION="Used to allow token-based authentication to Web services in Joomla."
diff --git a/administrator/language/en-GB/plg_api-authentication_token.sys.ini b/administrator/language/en-GB/plg_api-authentication_token.sys.ini
index 1066093ef5e73..4cef68f8d73c6 100644
--- a/administrator/language/en-GB/plg_api-authentication_token.sys.ini
+++ b/administrator/language/en-GB/plg_api-authentication_token.sys.ini
@@ -4,4 +4,4 @@
; Note : All ini files need to be saved as UTF-8
PLG_API-AUTHENTICATION_TOKEN="API Authentication - Joomla Token"
-PLG_API-AUTHENTICATION_TOKEN_XML_DESCRIPTION="Used to allow token-based authentication to Web Services in Joomla."
+PLG_API-AUTHENTICATION_TOKEN_XML_DESCRIPTION="Used to allow token-based authentication to Web services in Joomla."
diff --git a/administrator/language/en-GB/plg_authentication_cookie.ini b/administrator/language/en-GB/plg_authentication_cookie.ini
index 0620b235e1c14..8cf1f37c8610f 100644
--- a/administrator/language/en-GB/plg_authentication_cookie.ini
+++ b/administrator/language/en-GB/plg_authentication_cookie.ini
@@ -7,5 +7,5 @@ PLG_AUTHENTICATION_COOKIE="Authentication - Cookie"
PLG_AUTHENTICATION_COOKIE_ERROR_LOG_LOGIN_FAILED="Cookie login failed for user %u."
PLG_AUTHENTICATION_COOKIE_FIELD_COOKIE_LIFETIME_LABEL="Cookie Lifetime (days)"
PLG_AUTHENTICATION_COOKIE_FIELD_KEY_LENGTH_LABEL="Key Length"
-PLG_AUTHENTICATION_COOKIE_PRIVACY_CAPABILITY_COOKIE="In conjunction with a plugin which supports a \"Remember Me\" feature, such as the \"System - Remember Me\" plugin, this plugin creates a cookie on the user's client if a \"Remember Me\" checkbox is selected when logging into the website. This cookie can be identified with the prefix `joomla_remember_me` and is used to automatically log users into the website when they visit and are not already logged in."
-PLG_AUTHENTICATION_COOKIE_XML_DESCRIPTION="Handles Joomla's cookie User authentication. Warning! You must have at least one other authentication plugin enabled. You will also need a plugin such as the System - Remember Me plugin to implement cookie login."
+PLG_AUTHENTICATION_COOKIE_PRIVACY_CAPABILITY_COOKIE="In conjunction with a plugin which supports a \"Remember Me\" feature, such as the \"System - Remember Me\" plugin, this plugin creates a cookie in the user's browser if a \"Remember Me\" checkbox is selected when logging into the website. This cookie can be identified with the prefix `joomla_remember_me` and is used to automatically log users into the website when they visit and are not already logged in."
+PLG_AUTHENTICATION_COOKIE_XML_DESCRIPTION="Handles Joomla's cookie User authentication. Warning! You must have at least one other authentication plugin enabled. You will also need a plugin such as the System - Remember Me plugin to implement cookie login. "
diff --git a/administrator/language/en-GB/plg_authentication_cookie.sys.ini b/administrator/language/en-GB/plg_authentication_cookie.sys.ini
index 05bb833bd960b..4ed366fc4a580 100644
--- a/administrator/language/en-GB/plg_authentication_cookie.sys.ini
+++ b/administrator/language/en-GB/plg_authentication_cookie.sys.ini
@@ -4,4 +4,4 @@
; Note : All ini files need to be saved as UTF-8
PLG_AUTHENTICATION_COOKIE="Authentication - Cookie"
-PLG_AUTHENTICATION_COOKIE_XML_DESCRIPTION="Handles Joomla's cookie User authentication. Warning! You must have at least one other authentication plugin enabled. You will also need a plugin such as the System - Remember Me plugin to implement cookie login."
+PLG_AUTHENTICATION_COOKIE_XML_DESCRIPTION="Handles Joomla's cookie User authentication. Warning! You must have at least one other authentication plugin enabled. You will also need a plugin such as the System - Remember Me plugin to implement cookie login. "
diff --git a/administrator/language/en-GB/plg_authentication_joomla.ini b/administrator/language/en-GB/plg_authentication_joomla.ini
index 2a39943effc69..b3206d11b9847 100644
--- a/administrator/language/en-GB/plg_authentication_joomla.ini
+++ b/administrator/language/en-GB/plg_authentication_joomla.ini
@@ -5,4 +5,4 @@
PLG_AUTHENTICATION_JOOMLA="Authentication - Joomla"
PLG_AUTHENTICATION_JOOMLA_ERR_SECRET_CODE_WITHOUT_TFA="You need to enable two factor authentication in your user profile to use the secret code field."
-PLG_AUTHENTICATION_JOOMLA_XML_DESCRIPTION="Handles Joomla's default User authentication. Warning! You must have at least one authentication plugin enabled or you will lose all access to your site."
+PLG_AUTHENTICATION_JOOMLA_XML_DESCRIPTION="Handles Joomla's default User authentication. Warning! You must have at least one authentication plugin enabled or you will lose all access to your site. "
diff --git a/administrator/language/en-GB/plg_authentication_joomla.sys.ini b/administrator/language/en-GB/plg_authentication_joomla.sys.ini
index 521d79d83d5c5..3c0fa2be6c1d0 100644
--- a/administrator/language/en-GB/plg_authentication_joomla.sys.ini
+++ b/administrator/language/en-GB/plg_authentication_joomla.sys.ini
@@ -4,4 +4,4 @@
; Note : All ini files need to be saved as UTF-8
PLG_AUTHENTICATION_JOOMLA="Authentication - Joomla"
-PLG_AUTHENTICATION_JOOMLA_XML_DESCRIPTION="Handles Joomla's default User authentication. Warning! You must have at least one authentication plugin enabled or you will lose all access to your site."
+PLG_AUTHENTICATION_JOOMLA_XML_DESCRIPTION="Handles Joomla's default User authentication. Warning! You must have at least one authentication plugin enabled or you will lose all access to your site. "
diff --git a/administrator/language/en-GB/plg_authentication_ldap.ini b/administrator/language/en-GB/plg_authentication_ldap.ini
index e7b0789361ecd..837a120e3bdcd 100644
--- a/administrator/language/en-GB/plg_authentication_ldap.ini
+++ b/administrator/language/en-GB/plg_authentication_ldap.ini
@@ -33,4 +33,4 @@ PLG_LDAP_FIELD_V3_DESC="Default is LDAP2, but the latest versions of OpenLdap re
PLG_LDAP_FIELD_V3_LABEL="LDAP V3"
PLG_LDAP_FIELD_VALUE_BINDSEARCH="Bind and Search"
PLG_LDAP_FIELD_VALUE_BINDUSER="Bind Directly as User"
-PLG_LDAP_XML_DESCRIPTION="Handles User Authentication against an LDAP server. Warning! You must have at least one authentication plugin enabled or you will lose all access to your site."
+PLG_LDAP_XML_DESCRIPTION="Handles User Authentication against an LDAP server. Warning! You must have at least one authentication plugin enabled or you will lose all access to your site. "
diff --git a/administrator/language/en-GB/plg_authentication_ldap.sys.ini b/administrator/language/en-GB/plg_authentication_ldap.sys.ini
index 7607132e8138e..66e115862adb1 100644
--- a/administrator/language/en-GB/plg_authentication_ldap.sys.ini
+++ b/administrator/language/en-GB/plg_authentication_ldap.sys.ini
@@ -4,4 +4,4 @@
; Note : All ini files need to be saved as UTF-8
PLG_AUTHENTICATION_LDAP="Authentication - LDAP"
-PLG_LDAP_XML_DESCRIPTION="Handles User Authentication against an LDAP server. Warning! You must have at least one authentication plugin enabled or you will lose all access to your site."
+PLG_LDAP_XML_DESCRIPTION="Handles User Authentication against an LDAP server. Warning! You must have at least one authentication plugin enabled or you will lose all access to your site. "
diff --git a/administrator/language/en-GB/plg_content_fields.ini b/administrator/language/en-GB/plg_content_fields.ini
index e1835b94d3957..070e1231c439f 100644
--- a/administrator/language/en-GB/plg_content_fields.ini
+++ b/administrator/language/en-GB/plg_content_fields.ini
@@ -4,4 +4,4 @@
; Note : All ini files need to be saved as UTF-8
PLG_CONTENT_FIELDS="Content - Fields"
-PLG_CONTENT_FIELDS_XML_DESCRIPTION="This plugin allows you to display a custom field which has been inserted with the 'Button - Fields' plugin or using Syntax: {field #} directly into the editor area. Possible Syntax:
{field 1} will display the field with the ID 1{field 1,foo} will display the selected field using the alternative layout 'foo'.{fieldgroup 2} will display all fields within the fieldgroup with the ID 2. "
+PLG_CONTENT_FIELDS_XML_DESCRIPTION="This plugin allows you to display a custom field which has been inserted with the 'Button - Fields' plugin or using Syntax: {field #} directly into the editor area. Possible Syntax: {field 1} will display the field with the ID 1{field 1,foo} will display the selected field using the alternative layout 'foo'.{fieldgroup 2} will display all fields within the fieldgroup with the ID 2. "
diff --git a/administrator/language/en-GB/plg_content_pagebreak.ini b/administrator/language/en-GB/plg_content_pagebreak.ini
index 1db3046a2a2e1..0acb1cd13c6b1 100644
--- a/administrator/language/en-GB/plg_content_pagebreak.ini
+++ b/administrator/language/en-GB/plg_content_pagebreak.ini
@@ -17,4 +17,4 @@ PLG_CONTENT_PAGEBREAK_SLIDERS="Sliders"
PLG_CONTENT_PAGEBREAK_STYLE_LABEL="Presentation Style"
PLG_CONTENT_PAGEBREAK_TABS="Tabs"
PLG_CONTENT_PAGEBREAK_TOC_LABEL="Table of Contents"
-PLG_CONTENT_PAGEBREAK_XML_DESCRIPTION="Allow the creation of a paginated article with an optional table of contents.
Insert page breaks through the use of the page break button normally found in the WYSIWYG editor toolbar. The location of the page break in an article will be displayed in the editor as a simple horizontal line.
The text displayed will depend on the options chosen and may be either the title, alternate text (if provided) or page numbers.
The HTML usage is: <hr class="system-pagebreak" /> <hr class="system-pagebreak" title="The page title" /> or <hr class="system-pagebreak" alt="The first page" /> or <hr class="system-pagebreak" title="The page title" alt="The first page" /> or <hr class="system-pagebreak" alt="The first page" title="The page title" />"
+PLG_CONTENT_PAGEBREAK_XML_DESCRIPTION="Allow the creation of a paginated article with an optional table of contents. Insert page breaks through the use of the page break button normally found in the WYSIWYG editor toolbar. The location of the page break in an article will be displayed in the editor as a simple horizontal line. The text displayed will depend on the options chosen and may be either the title, alternate text (if provided) or page numbers. The HTML usage is: <hr class="system-pagebreak" /> <hr class="system-pagebreak" title="The page title" /> or <hr class="system-pagebreak" alt="The first page" /> or <hr class="system-pagebreak" title="The page title" alt="The first page" /> or <hr class="system-pagebreak" alt="The first page" title="The page title" /> "
diff --git a/administrator/language/en-GB/plg_content_pagebreak.sys.ini b/administrator/language/en-GB/plg_content_pagebreak.sys.ini
index 137e4d5df91a6..07f47d28af244 100644
--- a/administrator/language/en-GB/plg_content_pagebreak.sys.ini
+++ b/administrator/language/en-GB/plg_content_pagebreak.sys.ini
@@ -4,4 +4,4 @@
; Note : All ini files need to be saved as UTF-8
PLG_CONTENT_PAGEBREAK="Content - Page Break"
-PLG_CONTENT_PAGEBREAK_XML_DESCRIPTION="Allow the creation of a paginated article with an optional table of contents.
Insert page breaks through the use of the page break button normally found in the WYSIWYG editor toolbar. The location of the page break in an article will be displayed in the editor as a simple horizontal line.
The text displayed will depend on the options chosen and may be either the title, alternate text (if provided) or page numbers.
The HTML usage is: <hr class="system-pagebreak" /> <hr class="system-pagebreak" title="The page title" /> or <hr class="system-pagebreak" alt="The first page" /> or <hr class="system-pagebreak" title="The page title" alt="The first page" /> or <hr class="system-pagebreak" alt="The first page" title="The page title" />"
+PLG_CONTENT_PAGEBREAK_XML_DESCRIPTION="Allow the creation of a paginated article with an optional table of contents. Insert page breaks through the use of the page break button normally found in the WYSIWYG editor toolbar. The location of the page break in an article will be displayed in the editor as a simple horizontal line. The text displayed will depend on the options chosen and may be either the title, alternate text (if provided) or page numbers. The HTML usage is: <hr class="system-pagebreak" /> <hr class="system-pagebreak" title="The page title" /> or <hr class="system-pagebreak" alt="The first page" /> or <hr class="system-pagebreak" title="The page title" alt="The first page" /> or <hr class="system-pagebreak" alt="The first page" title="The page title" /> "
diff --git a/administrator/language/en-GB/plg_editors-xtd_fields.ini b/administrator/language/en-GB/plg_editors-xtd_fields.ini
index 8d49247a054f6..95b95869dd018 100644
--- a/administrator/language/en-GB/plg_editors-xtd_fields.ini
+++ b/administrator/language/en-GB/plg_editors-xtd_fields.ini
@@ -5,4 +5,4 @@
PLG_EDITORS-XTD_FIELDS="Button - Field"
PLG_EDITORS-XTD_FIELDS_BUTTON_FIELD="Field"
-PLG_EDITORS-XTD_FIELDS_XML_DESCRIPTION="Displays a button to insert a custom field into an editor area. Displays a popup allowing you to choose the field. Warning!: the custom field will not be rendered if the Content - Fields plugin is not enabled."
+PLG_EDITORS-XTD_FIELDS_XML_DESCRIPTION="Displays a button to insert a custom field into an editor area. Displays a popup allowing you to choose the field. Warning!: the custom field will not be rendered if the Content - Fields plugin is not enabled. "
diff --git a/administrator/language/en-GB/plg_editors-xtd_fields.sys.ini b/administrator/language/en-GB/plg_editors-xtd_fields.sys.ini
index 49848bd3b1515..9cbc4989e1b44 100644
--- a/administrator/language/en-GB/plg_editors-xtd_fields.sys.ini
+++ b/administrator/language/en-GB/plg_editors-xtd_fields.sys.ini
@@ -4,4 +4,4 @@
; Note : All ini files need to be saved as UTF-8
PLG_EDITORS-XTD_FIELDS="Button - Field"
-PLG_EDITORS-XTD_FIELDS_XML_DESCRIPTION="Displays a button to insert a custom field into an editor area. Displays a popup allowing you to choose the field. Warning!: the custom field will not be rendered if the Content - Fields plugin is not enabled."
+PLG_EDITORS-XTD_FIELDS_XML_DESCRIPTION="Displays a button to insert a custom field into an editor area. Displays a popup allowing you to choose the field. Warning!: the custom field will not be rendered if the Content - Fields plugin is not enabled. "
diff --git a/administrator/language/en-GB/plg_editors_tinymce.ini b/administrator/language/en-GB/plg_editors_tinymce.ini
index 773f9fed2239f..5afffb0cdf765 100644
--- a/administrator/language/en-GB/plg_editors_tinymce.ini
+++ b/administrator/language/en-GB/plg_editors_tinymce.ini
@@ -74,7 +74,7 @@ PLG_TINY_FIELD_VALUE_SIMPLE="Simple"
PLG_TINY_FIELD_VALUE_SLIDING="Sliding"
PLG_TINY_FIELD_VALUE_WRAP="Wrap"
PLG_TINY_FIELD_WORDCOUNT_LABEL="Word Count"
-PLG_TINY_LEGACY_WARNING="The TinyMCE Editor Plugin has been updated. Currently it uses your existing configuration. By editing the plugin, you can now assign and customise various layouts to specific user groups. Warning: when editing the plugin, you will lose all your previous settings!"
+PLG_TINY_LEGACY_WARNING="The TinyMCE Editor Plugin has been updated. Currently it uses your existing configuration. By editing the plugin, you can now assign and customise various layouts to specific user groups. Warning: when editing the plugin, you will lose all your previous settings! "
PLG_TINY_SET_PRESET_BUTTON_ADVANCED="Use advanced preset"
PLG_TINY_SET_PRESET_BUTTON_MEDIUM="Use medium preset"
PLG_TINY_SET_PRESET_BUTTON_SIMPLE="Use simple preset"
diff --git a/administrator/language/en-GB/plg_extension_namespacemap.ini b/administrator/language/en-GB/plg_extension_namespacemap.ini
index 78a3470ec26ad..d32aa7ebe1df7 100644
--- a/administrator/language/en-GB/plg_extension_namespacemap.ini
+++ b/administrator/language/en-GB/plg_extension_namespacemap.ini
@@ -4,4 +4,4 @@
; Note : All ini files need to be saved as UTF-8
PLG_EXTENSION_NAMESPACEMAP="Extension - Namespace Updater"
-PLG_EXTENSION_NAMESPACEMAP_XML_DESCRIPTION="Automatically builds and updates the administrator/cache/autoload_psr4.php file that is used to autoload extensions. Warning! This plugin must be enabled as it runs on extension install, update and uninstall."
+PLG_EXTENSION_NAMESPACEMAP_XML_DESCRIPTION="Automatically builds and updates the administrator/cache/autoload_psr4.php file that is used to autoload extensions. Warning! This plugin must be enabled as it runs on extension install, update and uninstall. "
\ No newline at end of file
diff --git a/administrator/language/en-GB/plg_extension_namespacemap.sys.ini b/administrator/language/en-GB/plg_extension_namespacemap.sys.ini
index 78a3470ec26ad..8c95b93561d55 100644
--- a/administrator/language/en-GB/plg_extension_namespacemap.sys.ini
+++ b/administrator/language/en-GB/plg_extension_namespacemap.sys.ini
@@ -4,4 +4,4 @@
; Note : All ini files need to be saved as UTF-8
PLG_EXTENSION_NAMESPACEMAP="Extension - Namespace Updater"
-PLG_EXTENSION_NAMESPACEMAP_XML_DESCRIPTION="Automatically builds and updates the administrator/cache/autoload_psr4.php file that is used to autoload extensions. Warning! This plugin must be enabled as it runs on extension install, update and uninstall."
+PLG_EXTENSION_NAMESPACEMAP_XML_DESCRIPTION="Automatically builds and updates the administrator/cache/autoload_psr4.php file that is used to autoload extensions. Warning! This plugin must be enabled as it runs on extension install, update and uninstall. "
diff --git a/administrator/language/en-GB/plg_installer_urlinstaller.ini b/administrator/language/en-GB/plg_installer_urlinstaller.ini
index 4ce5c7fd49d08..cad5aac173e7c 100644
--- a/administrator/language/en-GB/plg_installer_urlinstaller.ini
+++ b/administrator/language/en-GB/plg_installer_urlinstaller.ini
@@ -4,6 +4,5 @@
; Note : All ini files need to be saved as UTF-8
PLG_INSTALLER_URLINSTALLER_BUTTON="Check and Install"
-PLG_INSTALLER_URLINSTALLER_NO_URL="Please enter a URL."
PLG_INSTALLER_URLINSTALLER_PLUGIN_XML_DESCRIPTION="This plugin allows you to install extensions from a URL."
PLG_INSTALLER_URLINSTALLER_TEXT="Install from URL"
diff --git a/administrator/language/en-GB/plg_quickicon_overridecheck.ini b/administrator/language/en-GB/plg_quickicon_overridecheck.ini
index a1159b2b26a50..43a79a9c4fb2e 100644
--- a/administrator/language/en-GB/plg_quickicon_overridecheck.ini
+++ b/administrator/language/en-GB/plg_quickicon_overridecheck.ini
@@ -11,4 +11,4 @@ PLG_QUICKICON_OVERRIDECHECK_GROUP_DESC="The group of this plugin (this value is
PLG_QUICKICON_OVERRIDECHECK_GROUP_LABEL="Group"
PLG_QUICKICON_OVERRIDECHECK_OVERRIDEFOUND="Override(s) to check! %s"
PLG_QUICKICON_OVERRIDECHECK_UPTODATE="Overrides are up to date."
-PLG_QUICKICON_OVERRIDECHECK_XML_DESCRIPTION="Checks overrides on update and enables notifications when you visit the Home Dashboard page. Warning! You must have installer override plugin enabled to see results."
+PLG_QUICKICON_OVERRIDECHECK_XML_DESCRIPTION="Checks overrides on update and enables notifications when you visit the Home Dashboard page. Warning! You must have installer override plugin enabled to see results. "
diff --git a/administrator/language/en-GB/plg_quickicon_overridecheck.sys.ini b/administrator/language/en-GB/plg_quickicon_overridecheck.sys.ini
index 501b2f6474ad2..e498fa5b1d1ee 100644
--- a/administrator/language/en-GB/plg_quickicon_overridecheck.sys.ini
+++ b/administrator/language/en-GB/plg_quickicon_overridecheck.sys.ini
@@ -4,4 +4,4 @@
; Note : All ini files need to be saved as UTF-8
PLG_QUICKICON_OVERRIDECHECK="Quick Icon - Joomla! Overrides Update Notification"
-PLG_QUICKICON_OVERRIDECHECK_XML_DESCRIPTION="Checks overrides on update and enables notifications when you visit the Home Dashboard page. Warning! You must have installer override plugin enabled to see results."
+PLG_QUICKICON_OVERRIDECHECK_XML_DESCRIPTION="Checks overrides on update and enables notifications when you visit the Home Dashboard page. Warning! You must have installer override plugin enabled to see results. "
diff --git a/administrator/language/en-GB/plg_system_httpheaders.ini b/administrator/language/en-GB/plg_system_httpheaders.ini
index 7d32f404ad5e6..3c0c1170ef7f8 100644
--- a/administrator/language/en-GB/plg_system_httpheaders.ini
+++ b/administrator/language/en-GB/plg_system_httpheaders.ini
@@ -31,7 +31,7 @@ PLG_SYSTEM_HTTPHEADERS_POSTINSTALL_INTRODUCTION_ACTION="Enable default security
PLG_SYSTEM_HTTPHEADERS_POSTINSTALL_INTRODUCTION_BODY="Joomla! comes with a built-in set of tools that help you to handle http security headers. These headers help your browser for example to protect your website from XSS and Clickjacking attacks. You can find more details in the HTTP Header Management Tutorial in the Joomla! Documentation. "
PLG_SYSTEM_HTTPHEADERS_POSTINSTALL_INTRODUCTION_TITLE="HTTP Security Headers"
; Please do not translate the following two language strings
-PLG_SYSTEM_HTTPHEADERS_REFERRERPOLICY="Referrer-Policy"
-PLG_SYSTEM_HTTPHEADERS_XFRAMEOPTIONS="X-Frame-Options"
+PLG_SYSTEM_HTTPHEADERS_REFERRERPOLICY="Referrer-Policy"
+PLG_SYSTEM_HTTPHEADERS_XFRAMEOPTIONS="X-Frame-Options"
; Please do not translate 'HTTP Security Headers' in the following language string
PLG_SYSTEM_HTTPHEADERS_XML_DESCRIPTION="This Plugin helps you to set the HTTP Security Headers"
diff --git a/administrator/language/en-GB/plg_system_privacyconsent.sys.ini b/administrator/language/en-GB/plg_system_privacyconsent.sys.ini
index 67ed5de849737..1e2a9a6e69de5 100644
--- a/administrator/language/en-GB/plg_system_privacyconsent.sys.ini
+++ b/administrator/language/en-GB/plg_system_privacyconsent.sys.ini
@@ -4,4 +4,4 @@
; Note : All ini files need to be saved as UTF-8
PLG_SYSTEM_PRIVACYCONSENT="System - Privacy Consent"
-PLG_SYSTEM_PRIVACYCONSENT_XML_DESCRIPTION="Basic plugin to request user's consent to the site's privacy policy. Existing users who have not consented yet will be redirected on login to update their profile."
\ No newline at end of file
+PLG_SYSTEM_PRIVACYCONSENT_XML_DESCRIPTION="Basic plugin to request user's consent to the site's privacy policy. Existing users who have not consented yet will be redirected on login to update their profile."
diff --git a/administrator/language/en-GB/plg_user_joomla.ini b/administrator/language/en-GB/plg_user_joomla.ini
index 9684428c961d1..862eb8cd49a00 100644
--- a/administrator/language/en-GB/plg_user_joomla.ini
+++ b/administrator/language/en-GB/plg_user_joomla.ini
@@ -13,6 +13,6 @@ PLG_USER_JOOMLA_MAIL_MAIL_TITLE="Users: New User"
PLG_USER_JOOMLA_NEW_USER_EMAIL_BODY="Hello {NAME},\n\n\nYou have been added as a User to {SITENAME} by an Administrator.\n\nThis email has your username and password to log in to {URL}\n\nUsername: {USERNAME}\nPassword: {PASSWORD}\n\n\nPlease do not respond to this message as it is automatically generated and is for information purposes only."
PLG_USER_JOOMLA_NEW_USER_EMAIL_SUBJECT="New User Details"
PLG_USER_JOOMLA_POSTINSTALL_STRONGPW_BTN="Enable Strong Password Encryption"
-PLG_USER_JOOMLA_POSTINSTALL_STRONGPW_TEXT="As a security feature, Joomla allows you to switch to strong password encryption. To turn strong passwords on select the button below. Alternatively you can edit the User - Joomla plugin and change the strong password setting to On. Before enabling you should verify that all third party registration/login, user management or bridge extensions installed on your site support this strong password encryption."
+PLG_USER_JOOMLA_POSTINSTALL_STRONGPW_TEXT="As a security feature, Joomla allows you to switch to strong password encryption. To turn strong passwords on select the button below. Alternatively you can edit the User - Joomla plugin and change the strong password setting to On. Before enabling you should verify that all third party registration/login, user management or bridge extensions installed on your site support this strong password encryption. "
PLG_USER_JOOMLA_POSTINSTALL_STRONGPW_TITLE="Strong passwords"
-PLG_USER_JOOMLA_XML_DESCRIPTION="Handles Joomla's default User synchronisation. Warning! You must have enabled at least one plugin that handles the user session management or you will lose all access to your site."
+PLG_USER_JOOMLA_XML_DESCRIPTION="Handles Joomla's default User synchronisation. Warning! You must have enabled at least one plugin that handles the user session management or you will lose all access to your site. "
diff --git a/administrator/language/en-GB/plg_user_joomla.sys.ini b/administrator/language/en-GB/plg_user_joomla.sys.ini
index 3d2ad0e9d1715..9b47aa5299014 100644
--- a/administrator/language/en-GB/plg_user_joomla.sys.ini
+++ b/administrator/language/en-GB/plg_user_joomla.sys.ini
@@ -4,4 +4,4 @@
; Note : All ini files need to be saved as UTF-8
PLG_USER_JOOMLA="User - Joomla!"
-PLG_USER_JOOMLA_XML_DESCRIPTION="Handles Joomla's default User synchronisation. Warning! You must have enabled at least one plugin that handles the user session management or you will lose all access to your site."
+PLG_USER_JOOMLA_XML_DESCRIPTION="Handles Joomla's default User synchronisation. Warning! You must have enabled at least one plugin that handles the user session management or you will lose all access to your site. "
diff --git a/administrator/language/en-GB/tpl_atum.ini b/administrator/language/en-GB/tpl_atum.ini
index c86726b5c0499..6be510fadc425 100644
--- a/administrator/language/en-GB/tpl_atum.ini
+++ b/administrator/language/en-GB/tpl_atum.ini
@@ -7,7 +7,6 @@ ATUM="Atum Administrator template"
TPL_ATUM_BACK_TO_CONTROL_PANEL="Back to Dashboard"
TPL_ATUM_BACKEND_LOGIN="Joomla Administrator Login"
TPL_ATUM_COLORS_HUE="Choose your hue value for the dark template colour"
-TPL_ATUM_COLORS_SETTINGS_BG_DARK_LABEL="Dark Background"
TPL_ATUM_COLORS_SETTINGS_BG_LIGHT_LABEL="Light Background"
TPL_ATUM_COLORS_SETTINGS_CONTRAST_COLOR_LABEL="Contrast Colour"
TPL_ATUM_COLORS_SETTINGS_LABEL="Colour Settings"
diff --git a/administrator/manifests/files/joomla.xml b/administrator/manifests/files/joomla.xml
index 1c34b26990928..3fda02620c211 100644
--- a/administrator/manifests/files/joomla.xml
+++ b/administrator/manifests/files/joomla.xml
@@ -6,8 +6,8 @@
www.joomla.org
(C) 2019 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
- 4.0.0-beta7-dev
- January 2021
+ 4.0.0-beta8-dev
+ February 2021
FILES_JOOMLA_XML_DESCRIPTION
administrator/components/com_admin/script.php
diff --git a/administrator/manifests/packages/pkg_en-GB.xml b/administrator/manifests/packages/pkg_en-GB.xml
index 27247a8e081bc..60b46c4eb79f6 100644
--- a/administrator/manifests/packages/pkg_en-GB.xml
+++ b/administrator/manifests/packages/pkg_en-GB.xml
@@ -3,7 +3,7 @@
English (en-GB) Language Pack
en-GB
4.0.0.1
- January 2021
+ February 2021
Joomla! Project
admin@joomla.org
www.joomla.org
diff --git a/administrator/modules/mod_login/tmpl/default.php b/administrator/modules/mod_login/tmpl/default.php
index e2e929c9b51ff..094f884b998fe 100644
--- a/administrator/modules/mod_login/tmpl/default.php
+++ b/administrator/modules/mod_login/tmpl/default.php
@@ -112,6 +112,8 @@ class="btn btn-secondary w-100 mt-4 "
+
+
diff --git a/administrator/modules/mod_multilangstatus/tmpl/default.php b/administrator/modules/mod_multilangstatus/tmpl/default.php
index 2ed60d741dda4..91544b0bba866 100644
--- a/administrator/modules/mod_multilangstatus/tmpl/default.php
+++ b/administrator/modules/mod_multilangstatus/tmpl/default.php
@@ -18,6 +18,20 @@
return;
}
+$modalHTML = HTMLHelper::_(
+ 'bootstrap.renderModal',
+ 'multiLangModal',
+ array(
+ 'title' => Text::_('MOD_MULTILANGSTATUS'),
+ 'url' => Route::_('index.php?option=com_languages&view=multilangstatus&tmpl=component'),
+ 'height' => '400px',
+ 'width' => '800px',
+ 'bodyHeight' => 70,
+ 'modalWidth' => 80,
+ 'footer' => '',
+ )
+);
+
$app->getDocument()->getWebAssetManager()
->registerAndUseScript('mod_multilangstatus.admin', 'mod_multilangstatus/admin-multilangstatus.min.js', [], ['defer' => true]);
@@ -32,17 +46,5 @@
- Text::_('MOD_MULTILANGSTATUS'),
- 'url' => Route::_('index.php?option=com_languages&view=multilangstatus&tmpl=component'),
- 'height' => '400px',
- 'width' => '800px',
- 'bodyHeight' => 70,
- 'modalWidth' => 80,
- 'footer' => '',
- )
- ); ?>
+
diff --git a/administrator/templates/atum/joomla.asset.json b/administrator/templates/atum/joomla.asset.json
index e0293e5a657fb..d9dbfc2c453f3 100644
--- a/administrator/templates/atum/joomla.asset.json
+++ b/administrator/templates/atum/joomla.asset.json
@@ -2,11 +2,12 @@
"$schema": "https://developer.joomla.org/schemas/json-schema/web_assets.json",
"name": "atum",
"version": "4.0.0",
- "description": "Atum is the default Joomla 4 administrator template",
+ "description": "This file contains details of the assets used by Atum, the default Joomla 4 administrator template.",
"license": "GPL-2.0-or-later",
"assets": [
{
"name": "template.atum.ltr",
+ "description": "The css file to be used when the site is left to right (LTR).",
"type": "style",
"uri": "template.min.css",
"dependencies": [
@@ -15,6 +16,7 @@
},
{
"name": "template.atum.rtl",
+ "description": "The css file to be used when the site is right to left (RTL).",
"type": "style",
"uri": "template-rtl.min.css",
"dependencies": [
@@ -23,6 +25,7 @@
},
{
"name": "template.active.language",
+ "description": "An asset to allow language specific css, eg 'language/[lang-CODE]/[lang-CODE].css', to use it as a dependency to the active template",
"type": "style",
"uri": "",
"class": "LangActiveAssetItem",
@@ -33,6 +36,7 @@
},
{
"name": "template.user",
+ "description": "A file where a user can add their own css.",
"type": "style",
"uri": "user.css",
"dependencies": [
@@ -42,6 +46,7 @@
},
{
"name": "template.atum",
+ "description": "The file containing the javascript for this template.",
"type": "script",
"uri": "templates/atum/template.min.js",
"dependencies": [
@@ -50,9 +55,9 @@
},
{
"name": "template.active",
+ "description": "A dummy asset to allow extensions to use it as a dependency to the active template",
"type": "script",
"uri": "",
- "description": "A dummy asset to allow extensions to use it as a dependency to the active template",
"dependencies": [
"template.atum"
]
diff --git a/administrator/templates/atum/scss/_variables.scss b/administrator/templates/atum/scss/_variables.scss
index 90096d6717b3d..73ec0d2b728d2 100644
--- a/administrator/templates/atum/scss/_variables.scss
+++ b/administrator/templates/atum/scss/_variables.scss
@@ -255,8 +255,8 @@ $quickicon-bg: var(--white);
$quickicon-box-shadow-success: 0 0 3px 0 var(--success);
$quickicon-box-shadow-danger: 0 0 3px 0 var(--danger);
$quickicon-box-shadow-warning: 0 0 3px 0 var(--warning);
-$quickicon-icon-size: 1.3rem;
-$quickicon-icon-size-big: 2rem;
+$quickicon-icon-size: 2rem;
+$quickicon-icon-size-sm: 1.3rem;
// Gutter
$grid-gutter-width: 2rem;
diff --git a/administrator/templates/atum/scss/blocks/_form.scss b/administrator/templates/atum/scss/blocks/_form.scss
index b5a9310b0aca0..d1906457936e9 100644
--- a/administrator/templates/atum/scss/blocks/_form.scss
+++ b/administrator/templates/atum/scss/blocks/_form.scss
@@ -57,12 +57,6 @@
}
-.control-group {
- .switcher__legend {
- font-size: $label-font-size;
- }
-}
-
.spacer {
hr {
width: 380px;
@@ -151,12 +145,6 @@ legend {
bottom: auto;
}
-.switcher__legend {
- margin-bottom: 0;
- font-size: $label-font-size;
- color: var(--atum-special-color);
-}
-
.input-group-append {
overflow: hidden;
transform: translate3d(0, 0, 0);
diff --git a/administrator/templates/atum/scss/blocks/_global.scss b/administrator/templates/atum/scss/blocks/_global.scss
index 084b9cdf261d3..727db4e1a99eb 100644
--- a/administrator/templates/atum/scss/blocks/_global.scss
+++ b/administrator/templates/atum/scss/blocks/_global.scss
@@ -158,6 +158,7 @@ body .container-main {
.item-associations li {
display: inline-block;
+ margin-bottom: 3px;
list-style: none;
}
diff --git a/administrator/templates/atum/scss/blocks/_quickicons.scss b/administrator/templates/atum/scss/blocks/_quickicons.scss
index 966ccb3a62fc1..b130d255dfc04 100644
--- a/administrator/templates/atum/scss/blocks/_quickicons.scss
+++ b/administrator/templates/atum/scss/blocks/_quickicons.scss
@@ -3,281 +3,142 @@
.quick-icons {
background-color: $white;
- li {
- padding: 0;
+ .nav {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
+ grid-gap: 1rem;
}
a {
- width: 100%;
- color: var(--atum-link-color);
text-decoration: none;
transition: all .25s ease;
+ }
- [class^="#{$jicon-css-prefix}-"],
- [class*=" #{$jicon-css-prefix}-"],
- [class^="#{$fa-css-prefix}-"],
- [class*=" #{$fa-css-prefix}-"] {
- margin: 0 auto;
- font-size: $quickicon-icon-size;
- color: transparent;
- background: linear-gradient(var(--atum-link-color), var(--atum-link-hover-color));
- background-clip: text;
+ .quickicon {
+ --text-color: var(--atum-link-color);
+ --bg-color: var(--toolbar-bg);
+ --icon-color: linear-gradient(var(--atum-link-color), var(--atum-link-hover-color));
+ --bg-color-hvr: var(--atum-bg-dark);
+
+ a {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: space-around;
+ height: 100%;
+ color: var(--text-color);
+ text-align: center;
+ background-color: var(--bg-color);
+
+ .quickicon-icon {
+ margin-top: 20px;
+
+ > * {
+ font-size: $quickicon-icon-size;
+ color: transparent;
+ background: var(--icon-color);
+ background-clip: text;
+ }
- &.big {
- font-size: $quickicon-icon-size-big;
+ &.small > * {
+ font-size: $quickicon-icon-size-sm;
+ }
}
- }
- &:hover,
- &:focus,
- &:active {
- color: $white;
- text-decoration: none;
- background: var(--atum-link-color);
+ &:hover,
+ &:focus,
+ &:active {
+ color: $white;
+ text-decoration: none;
+ background: var(--bg-color-hvr);
- [class^="#{$jicon-css-prefix}-"],
- [class*=" #{$jicon-css-prefix}-"],
- [class^="#{$fa-css-prefix}-"],
- [class*=" #{$fa-css-prefix}-"] {
- color: transparent;
- background: linear-gradient(var(--atum-bg-light), $white);
- background-clip: text;
+ .quickicon-icon > * {
+ color: $white;
+ }
}
- }
- }
-
- // Group link to the overview and link to the edit form in a container
- .quickicon-group {
- flex: 1 1 calc(33.333% - 1rem);
- width: calc(33.333% - 1rem);
- max-width: calc(33.333% - 1rem);
- padding: 0;
-
- > ul {
- padding: 0;
- }
-
- @media (max-width: 1350px) {
- flex: 1 1 calc(50% - 1rem);
- width: calc(50% - 1rem);
- max-width: calc(50% - 1rem);
- }
-
- @media (max-width: 1150px) {
- flex: 1 1 calc(100% - 1rem);
- width: calc(100% - 1rem);
- max-width: calc(100% - 1rem);
- }
-
- @include media-breakpoint-down(md) {
- flex: 1 1 calc(50% - 1rem);
- width: calc(50% - 1rem);
- max-width: calc(50% - 1rem);
- }
-
- @media (max-width: 430px) {
- flex: 1 1 calc(100% - 1rem);
- width: calc(100% - 1rem);
- max-width: calc(100% - 1rem);
- }
-
- .quickicon-linkadd {
- width: 2rem;
- background-color: var(--atum-bg-light);
- }
- }
-
- // Single icon
- .quickicon-single {
- flex: 1 1 calc(33.333% - 1rem);
- width: calc(33.333% - 1rem);
- max-width: calc(33.333% - 1rem);
- background: $quickicon-bg;
- }
-
- .quickicon-single,
- .quickicon-group {
- min-height: 5.7rem;
- margin: .5rem;
- border: 1px solid $bluegray;
-
- @media (max-width: 1350px) {
- flex: 1 1 calc(50% - 1rem);
- width: calc(50% - 1rem);
- max-width: calc(50% - 1rem);
- }
-
- @media (max-width: 1150px) {
- flex: 1 1 calc(100% - 1rem);
- width: calc(100% - 1rem);
- max-width: calc(100% - 1rem);
- }
-
- @include media-breakpoint-down(md) {
- flex: 1 1 calc(50% - 1rem);
- width: calc(50% - 1rem);
- max-width: calc(50% - 1rem);
- }
- @media (max-width: 430px) {
- flex: 1 1 calc(100% - 1rem);
- width: calc(100% - 1rem);
- max-width: calc(100% - 1rem);
- }
- }
-
- .quickicon a {
- display: inline-flex;
- flex-direction: column;
- align-self: baseline;
- height: 100%;
- line-height: 1.1;
- text-align: center;
- background-color: var(--toolbar-bg);
+ .quickicon-name {
+ padding: .25rem .2rem .6rem;
+ font-size: $display2-size;
+ }
- > div {
- flex: 1 0 0;
- margin: 0 auto;
+ .quickicon-amount {
+ margin-top: .3rem !important;
+ font-size: $display1-size;
+ font-weight: $bold-weight;
- &.quickicon-icon {
- margin: .8rem auto 0;
+ ~ .quickicon-name {
+ padding-top: 0;
+ }
- &.big [class^="#{$jicon-css-prefix}-"],
- &.big [class*=" #{$jicon-css-prefix}-"],
- &.big [class^="#{$fa-css-prefix}-"],
- &.big [class*=" #{$fa-css-prefix}-"] {
- font-size: $quickicon-icon-size-big;
+ > .#{$jicon-css-prefix}-spinner,
+ > .#{$fa-css-prefix}-spinner {
+ font-size: $display1-size;
}
}
- }
-
- .quickicon-name {
- padding: .2rem .2rem .6rem;
- font-size: $display2-size;
- }
- .quickicon-amount {
- padding: .3rem;
- margin-top: .3rem !important;
- font-size: $display1-size;
- font-weight: $bold-weight;
-
- > .#{$jicon-css-prefix}-spinner,
- > .#{$fa-css-prefix}-spinner {
- font-size: $display1-size;
+ .j-links-link {
+ display: block;
+ padding: 0 .2rem;
+ line-height: 1.1;
}
- }
-
- .j-links-link {
- display: block;
- padding: 0 .2rem;
- line-height: 1.1;
- }
- &.warning,
- &.danger {
- color: $danger-txt;
- background: var(--danger);
- border: 1px solid lighten($danger-txt, 30%);
-
- [class^="#{$jicon-css-prefix}-"],
- [class*=" #{$jicon-css-prefix}-"],
- [class^="#{$fa-css-prefix}-"],
- [class*=" #{$fa-css-prefix}-"] {
- color: $danger-txt;
+ &.warning,
+ &.danger {
+ --text-color: var(--white);
+ --bg-color: var(--danger);
+ --icon-color: var(--white);
+ --bg-color-hvr: var(--danger);
}
- &:hover,
- &:focus,
- &:active {
- color: var(--white);
- background: var(--danger);
-
- [class^="#{$jicon-css-prefix}-"]::before,
- [class*=" #{$jicon-css-prefix}-"]::before,
- [class^="#{$fa-css-prefix}-"]::before,
- [class*=" #{$fa-css-prefix}-"]::before {
- color: var(--white);
- }
+ &.success {
+ --text-color: var(--success);
+ --bg-color: var(--white);
+ --icon-color: linear-gradient(var(--success), #159c1e);
+ --bg-color-hvr: var(--success);
}
}
+ }
- &.success {
- color: var(--success);
- border: 1px solid lighten($success-txt, 20%);
+ .quickicon-linkadd {
+ width: 2rem;
+ font-size: 1.3rem;
+ background-color: var(--atum-bg-light);
- [class^="#{$jicon-css-prefix}-"],
- [class*=" #{$jicon-css-prefix}-"],
- [class^="#{$fa-css-prefix}-"],
- [class*=" #{$fa-css-prefix}-"] {
+ a {
+ justify-content: center;
+ width: 100%;
+
+ > * {
color: transparent;
- background: linear-gradient(var(--success), #159c1e);
+ background: linear-gradient(var(--atum-link-color),var(--atum-link-hover-color));
background-clip: text;
}
&:hover,
&:focus,
&:active {
- color: var(--white);
- background: var(--success);
+ background: var(--atum-bg-dark);
- [class^="#{$jicon-css-prefix}-"]::before,
- [class*=" #{$jicon-css-prefix}-"]::before,
- [class^="#{$fa-css-prefix}-"]::before,
- [class*=" #{$fa-css-prefix}-"]::before {
- color: transparent;
- background: linear-gradient($white, lighten($green, 40%));
- background-clip: text;
+ * {
+ color: $white;
}
}
}
-
- &:hover,
- &:focus,
- &:active {
- color: $white;
- text-decoration: none;
- background: var(--atum-bg-dark);
- }
}
-}
-
-#content {
- .menu-quicktask {
- position: absolute;
- [dir=ltr] & {
- right: 1.25rem;
- }
-
- [dir=rtl] & {
- left: 1.25rem;
- }
+ .quickicon-single,
+ .quickicon-group {
+ min-height: 5.7rem;
+ border: 1px solid $bluegray;
}
}
-#wrapper.closed {
- .quick-icons {
-
- .quickicon-single,
- .quickicon-group {
- @media (max-width: 1180px) {
- flex: 1 1 calc(50% - 1rem);
- width: calc(50% - 1rem);
- max-width: calc(50% - 1rem);
- }
-
- @media (max-width: 950px) {
- flex: 1 1 calc(100% - 1rem);
- width: calc(100% - 1rem);
- max-width: calc(100% - 1rem);
- }
+#content .menu-quicktask {
+ position: absolute;
+ right: 1.25rem;
- @media (max-width: 767px) {
- flex: 1 1 calc(33% - 1rem);
- width: calc(33% - 1rem);
- max-width: calc(33% - 1rem);
- }
- }
+ [dir=rtl] & {
+ left: 1.25rem;
}
}
diff --git a/administrator/templates/atum/scss/blocks/_toolbar.scss b/administrator/templates/atum/scss/blocks/_toolbar.scss
index 317b00ccaea15..abbcee7149f79 100644
--- a/administrator/templates/atum/scss/blocks/_toolbar.scss
+++ b/administrator/templates/atum/scss/blocks/_toolbar.scss
@@ -34,6 +34,8 @@
.btn > span,
.dropdown-item > span {
margin-inline-end: .5rem;
+ width: 1.25em;
+ text-align: center;
}
}
@@ -120,16 +122,15 @@
}
.btn-group:not(:last-child) > .dropdown-toggle-split {
+ order: 1;
margin-inline-start: -$border-radius;
[dir="ltr"] & {
- border-top-right-radius: $border-radius;
- border-bottom-right-radius: $border-radius;
+ border-radius: 0 $border-radius $border-radius 0;
}
[dir="rtl"] & {
- border-top-left-radius: $border-radius;
- border-bottom-left-radius: $border-radius;
+ border-radius: $border-radius 0 0 $border-radius;
}
}
diff --git a/administrator/templates/atum/scss/blocks/_utilities.scss b/administrator/templates/atum/scss/blocks/_utilities.scss
index 7ab8311c41c76..d66c9f054bc94 100644
--- a/administrator/templates/atum/scss/blocks/_utilities.scss
+++ b/administrator/templates/atum/scss/blocks/_utilities.scss
@@ -24,64 +24,115 @@
display: table-row;
}
-// Column Count
+// Form Grid
+
+.form-grid {
+ --span-1: span 1;
+ --span-2: span 1;
+ --span-3: span 1;
+ --span-4: span 1;
+ --span-5: span 1;
+
+ display: grid;
+ grid-template-columns: repeat(1, 1fr);
+ grid-gap: 1rem;
+
+ @include media-breakpoint-up(sm) {
+ --span-2: span 2;
+ --span-3: span 2;
+ --span-4: span 2;
+ --span-5: span 2;
+
+ grid-template-columns: repeat(2, 1fr);
+ }
-[class^="column-"],
-[class*=" column-"] {
- padding-bottom: 1rem;
- column-gap: 2rem;
+ @include media-breakpoint-up(md) {
+ --span-3: span 3;
+ --span-4: span 4;
+ --span-5: span 4;
- > div {
- display: inline-flex;
- flex-direction: column;
- width: 100%;
- break-inside: avoid;
- page-break-inside: avoid;
+ grid-template-columns: repeat(4, 1fr);
+ grid-gap: 1rem 2rem;
+ }
- &.hidden {
- display: none;
- }
+ @include media-breakpoint-up(lg) {
+ --span-5: span 5;
- .control-label {
- width: 100%;
- }
+ grid-template-columns: repeat(6, 1fr);
}
- .form-no-columns & {
- column-count: auto;
+ > * {
+ grid-column: 1 / -1;
}
-}
-@include media-breakpoint-up(sm) {
- .column-count-sm-2 {
- column-count: 2;
+ .stack {
+ flex-direction: column;
}
- .column-count-sm-3 {
- column-count: 3;
+ .span-1 {
+ grid-column: 1 / var(--span-1);
+
+ &-inline {
+ grid-column: var(--span-1);
+ }
}
-}
-@include media-breakpoint-up(md) {
- .column-count-md-2 {
- column-count: 2;
+ .span-2 {
+ grid-column: 1 / var(--span-2);
+
+ &-inline {
+ grid-column: var(--span-2);
+ }
}
- .column-count-md-3 {
- column-count: 3;
+ .span-3 {
+ grid-column: 1 / var(--span-3);
+
+ &-inline {
+ grid-column: var(--span-3);
+ }
}
-}
-@include media-breakpoint-up(lg) {
- .column-count-lg-2 {
- column-count: 2;
+ .span-4 {
+ grid-column: 1 / var(--span-4);
+
+ &-inline {
+ grid-column: var(--span-4);
+ }
}
- .column-count-lg-3 {
- column-count: 3;
+ .span-5 {
+ grid-column: 1 / var(--span-5);
+
+ &-inline {
+ grid-column: var(--span-5);
+ }
+ }
+
+ @include media-breakpoint-up(lg) {
+ .offset-1 {
+ grid-column-start: 2;
+ }
+
+ .offset-2 {
+ grid-column-start: 3;
+ }
+
+ .offset-3 {
+ grid-column-start: 4;
+ }
+
+ .offset-4 {
+ grid-column-start: 5;
+ }
+
+ .offset-5 {
+ grid-column-start: 6;
+ }
}
}
+
// Sizing
.w-1 {
@@ -139,3 +190,7 @@
.w-80 {
width: 80%;
}
+
+.editor-xtd-buttons .btn {
+ margin-bottom: 5px;
+}
diff --git a/administrator/templates/atum/scss/pages/_com_modules.scss b/administrator/templates/atum/scss/pages/_com_modules.scss
index 5abb97f018771..148558822b555 100644
--- a/administrator/templates/atum/scss/pages/_com_modules.scss
+++ b/administrator/templates/atum/scss/pages/_com_modules.scss
@@ -6,13 +6,10 @@
.card {
display: flex;
- &:hover {
- box-shadow: 0 0 40px 10px rgba(0, 28, 73, .15);
- }
-
.btn {
width: 100%;
- border-radius: 0;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
}
}
}
diff --git a/administrator/templates/atum/scss/pages/_com_templates.scss b/administrator/templates/atum/scss/pages/_com_templates.scss
index 3a90cc8307f42..e5cc7eae3e9df 100644
--- a/administrator/templates/atum/scss/pages/_com_templates.scss
+++ b/administrator/templates/atum/scss/pages/_com_templates.scss
@@ -30,8 +30,8 @@
.menu-links-block {
padding: 15px;
background-color: var(--card-bg);
+ border: 1px solid $border-color;
border-radius: 3px;
- box-shadow: $atum-box-shadow;
}
label {
diff --git a/administrator/templates/atum/scss/template-rtl.scss b/administrator/templates/atum/scss/template-rtl.scss
index 845d8f8e9c2c5..e2f155f9d759c 100644
--- a/administrator/templates/atum/scss/template-rtl.scss
+++ b/administrator/templates/atum/scss/template-rtl.scss
@@ -27,16 +27,6 @@ ul {
// Header
.header {
- .page-title {
- [class^="#{$jicon-css-prefix}-"],
- [class*=" #{$jicon-css-prefix}-"],
- [class^="#{$fa-css-prefix}-"],
- [class*=" #{$fa-css-prefix}-"] {
- margin-right: 0;
- margin-left: 15px;
- }
- }
-
.logo svg,
.logo img {
margin-right: .8rem;
@@ -134,6 +124,21 @@ ul {
direction: ltr;
}
+// skipto
+.skip-to {
+ &.popup {
+ right: -3000em;
+ left: 0 !important;
+ &.focus {
+ right: 46%;
+ left: 0 !important;
+ }
+ }
+ [role="separator"] {
+ text-align: right !important;
+ }
+}
+
// SearchTools rounded corners
.input-group > .input-group-prepend > .btn,
.input-group > .input-group-prepend > .input-group-text,
diff --git a/administrator/templates/atum/scss/vendor/bootstrap/_bootstrap-rtl.scss b/administrator/templates/atum/scss/vendor/bootstrap/_bootstrap-rtl.scss
index 574d3b71d019a..e7bdcc5c95845 100644
--- a/administrator/templates/atum/scss/vendor/bootstrap/_bootstrap-rtl.scss
+++ b/administrator/templates/atum/scss/vendor/bootstrap/_bootstrap-rtl.scss
@@ -88,8 +88,8 @@
}
.ms-auto {
- margin-right: 0 !important;
- margin-left: auto !important;
+ margin-right: auto !important;
+ margin-left: 0 !important;
}
.pe-0 {
@@ -142,3 +142,35 @@
padding-left: 0 !important;
}
+
+.input-group {
+ &:not(.has-validation) {
+ > :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu),
+ > .dropdown-toggle:nth-last-child(n + 3) {
+ @include border-end-radius($border-radius);
+ }
+ }
+
+ &.has-validation {
+ > :nth-last-child(n + 3):not(.dropdown-toggle):not(.dropdown-menu),
+ > .dropdown-toggle:nth-last-child(n + 4) {
+ @include border-end-radius(0);
+ }
+ }
+ $validation-messages: "";
+ @each $state in map-keys($form-validation-states) {
+ $validation-messages: $validation-messages + ":not(." + unquote($state) + "-tooltip)" + ":not(." + unquote($state) + "-feedback)";
+ }
+
+ > :not(:first-child):not(.dropdown-menu)#{$validation-messages} {
+ margin-left: -$input-border-width;
+ @include border-start-radius(0);
+ @include border-end-radius(0);
+ }
+
+ > :last-child:not(.dropdown-menu)#{$validation-messages} {
+ margin-left: -$input-border-width;
+ @include border-start-radius($border-radius);
+ @include border-end-radius(0);
+ }
+}
diff --git a/administrator/templates/atum/scss/vendor/joomla-custom-elements/joomla-tab.scss b/administrator/templates/atum/scss/vendor/joomla-custom-elements/joomla-tab.scss
index b001a558e6fa7..8a5b8e7b8a0e1 100644
--- a/administrator/templates/atum/scss/vendor/joomla-custom-elements/joomla-tab.scss
+++ b/administrator/templates/atum/scss/vendor/joomla-custom-elements/joomla-tab.scss
@@ -57,7 +57,7 @@ joomla-tab {
margin: -1px;
background-color: $white;
background-image: none;
- border: 2px solid var(--bluegray);
+ border: 1px solid var(--bluegray);
border-bottom: solid 1px #fff;
border-radius: 0;
box-shadow: none;
@@ -136,9 +136,10 @@ joomla-tab {
position: relative;
display: block;
padding: .75em 1em;
+ margin: -1px 0;
color: var(--atum-special-color);
text-decoration: none;
- border: 0;
+ border-top: 1px solid transparent;
border-bottom: 1px solid $gray-300;
box-shadow: none;
@@ -158,6 +159,10 @@ joomla-tab {
height: auto;
background-color: var(--atum-bg-dark);
}
+
+ .text-muted {
+ color: var(--atum-text-light) !important;
+ }
}
}
diff --git a/api/language/en-GB/joomla.ini b/api/language/en-GB/joomla.ini
index ea619e29cccf1..d125aaee78049 100644
--- a/api/language/en-GB/joomla.ini
+++ b/api/language/en-GB/joomla.ini
@@ -259,7 +259,7 @@ JFIELD_ORDERING_LABEL="Ordering"
JFIELD_PARAMS_LABEL="Options"
JFIELD_PASSWORD_INDICATE_COMPLETE="Password accepted"
JFIELD_PASSWORD_INDICATE_INCOMPLETE="Password doesn't meet site's requirements"
-JFIELD_PASSWORD_NOTE_DESC="%1s symbol(s), %2s uppercase letter(s), %3s lowercase letter(s), %4s number(s) and be %5s characters long"
+JFIELD_PASSWORD_NOTE_DESC="%1$s symbol(s), %2$s uppercase letter(s), %3$s lowercase letter(s), %4$s number(s) and be %5$s characters long"
JFIELD_PASSWORD_NOTE_LBL="Password must contain:"
JFIELD_PLG_SEARCH_ALL_DESC="Include published items in the search."
JFIELD_PLG_SEARCH_ALL_LABEL="Search Published"
@@ -428,7 +428,7 @@ JGLOBAL_FILTER_GROUPS_DESC="This sets the user groups that you want filters appl
JGLOBAL_FILTER_GROUPS_LABEL="Filter Groups"
JGLOBAL_FILTER_TAGS_DESC="2. List additional tags, separating each tag name with a space or comma. For example: p,div,span."
JGLOBAL_FILTER_TAGS_LABEL="Filter Tags2"
-JGLOBAL_FILTER_TYPE_DESC="1. Blacklist allows all tags and attributes except for those in the blacklist. -- Tags for the Default Blacklist include: 'applet', 'body', 'bgsound', 'base', 'basefont', 'canvas', 'embed', 'frame', 'frameset', 'head', 'html', 'id', 'iframe', 'ilayer', 'layer', 'link', 'meta', 'name', 'object', 'script', 'style', 'title', 'xml' -- Attributes for the Default Blacklist include: 'action', 'background', 'codebase', 'dynsrc', 'lowsrc', 'formaction' -- You can blacklist additional tags and attributes by adding to the Filter Tags and Filter Attributes fields, separating each tag or attribute name with a comma. -- Custom Blacklist allows you to override the Default Blacklist. Add the tags and attributes to be blacklisted in the Filter Tags and Filter Attributes fields. Whitelist allows only the tags listed in the Filter Tags and Filter Attributes fields. No HTML removes all HTML tags from the content when it is saved. Please note that these settings work regardless of the editor that you are using. Even if you are using a WYSIWYG editor, the filtering settings may strip additional tags and attributes prior to saving information in the database."
+JGLOBAL_FILTER_TYPE_DESC="1. Forbidden List allows all tags and attributes except for those listed. -- Tags for the Default Forbidden List include: 'applet', 'body', 'bgsound', 'base', 'basefont', 'canvas', 'embed', 'frame', 'frameset', 'head', 'html', 'id', 'iframe', 'ilayer', 'layer', 'link', 'meta', 'name', 'object', 'script', 'style', 'title', 'xml' -- Attributes for the Default Forbidden List include: 'action', 'background', 'codebase', 'dynsrc', 'lowsrc', 'formaction' -- You can forbid additional tags and attributes by adding to the Filter Tags and Filter Attributes fields, separating each tag or attribute name with a comma. -- Custom Forbidden List allows you to override the Default Forbidden List. Add the tags and attributes to be forbidden in the Filter Tags and Filter Attributes fields. Allowed List allows only the tags listed in the Filter Tags and Filter Attributes fields. No HTML removes all HTML tags from the content when it is saved. Please note that these settings work regardless of the editor that you are using. Even if you are using a WYSIWYG editor, the filtering settings may strip additional tags and attributes prior to saving information in the database."
JGLOBAL_FILTER_TYPE_LABEL="Filter Type1"
JGLOBAL_FILTERED_BY="Filtered by:"
JGLOBAL_FULL_TEXT="Full Text"
@@ -994,10 +994,10 @@ JWARNING_UNPUBLISH_MUST_SELECT="You must select at least one item to unpublish."
JWORKFLOW="Workflow: %s"
JWORKFLOW_ENABLED_LABEL="Enable Workflow"
JWORKFLOW_EXECUTE_TRANSITION="Select the transition to execute on this item."
-JWORKFLOW_EXTENSION_BLACKLIST_DESCRIPTION="Disable this plugin for listed extensions."
-JWORKFLOW_EXTENSION_BLACKLIST_LABEL="Extension Blacklist"
-JWORKFLOW_EXTENSION_WHITELIST_DESCRIPTION="Activate this plugin only for listed extensions. If used all other extensions are disabled."
-JWORKFLOW_EXTENSION_WHITELIST_LABEL="Extension Whitelist"
+JWORKFLOW_EXTENSION_FORBIDDEN_DESCRIPTION="Disable this plugin for listed extensions."
+JWORKFLOW_EXTENSION_FORBIDDEN_LABEL="Forbidden Extensions"
+JWORKFLOW_EXTENSION_ALLOWED_DESCRIPTION="Activate this plugin only for listed extensions. If used all other extensions are disabled."
+JWORKFLOW_EXTENSION_ALLOWED_LABEL="Allowed Extensions"
JWORKFLOW_FIELD_COMPONENT_SECTIONS_TEXT="%1$s: %2$s"
JWORKFLOW_SHOW_TRANSITIONS_FOR_THIS_ITEM="Show the transition selection to execute a transition on this item."
JWORKFLOW_TITLE="Workflow"
diff --git a/api/language/en-GB/langmetadata.xml b/api/language/en-GB/langmetadata.xml
index bb8f135989cf6..eee7292e47aea 100644
--- a/api/language/en-GB/langmetadata.xml
+++ b/api/language/en-GB/langmetadata.xml
@@ -2,7 +2,7 @@
English (en-GB)
4.0.0
- January 2021
+ February 2021
Joomla! Project
admin@joomla.org
www.joomla.org
diff --git a/build/.eslintrc b/build/.eslintrc
index d6d38dc2c5f1f..175a32adb3034 100644
--- a/build/.eslintrc
+++ b/build/.eslintrc
@@ -7,7 +7,6 @@
],
"parser": "vue-eslint-parser",
"parserOptions": {
-
"sourceType": "module"
},
// ESLint will not look in parent folders for eslint configs
@@ -21,7 +20,8 @@
// Additional global variables your script accesses during execution
"globals": {
"Joomla": true,
- "MediaManager" : true
+ "MediaManager" : true,
+ "bootstrap": true
},
// Rule overrides
"rules": {
@@ -32,6 +32,8 @@
// Allow strict mode (we are not dealing with modules)
"strict": [0],
// Disable alert rule till we have a CE in place
- "no-alert": 0
+ "no-alert": 0,
+ // Allow extensions on imports
+ "import/extensions": 0
}
}
diff --git a/build/build-modules-js/compilecss.es6.js b/build/build-modules-js/compilecss.es6.js
index 1a606f9747d89..f11db7b3c6c81 100644
--- a/build/build-modules-js/compilecss.es6.js
+++ b/build/build-modules-js/compilecss.es6.js
@@ -1,9 +1,8 @@
-const Fs = require('fs');
-const FsExtra = require('fs-extra');
-const Path = require('path');
-const Recurs = require('recursive-readdir');
-const UglyCss = require('uglifycss');
-const CompileScss = require('./stylesheets/scss-transform.es6.js');
+const { stat } = require('fs-extra');
+const { sep } = require('path');
+const recursive = require('recursive-readdir');
+const { handleScssFile } = require('./stylesheets/handle-scss.es6.js');
+const { handleCssFile } = require('./stylesheets/handle-css.es6.js');
const RootPath = process.cwd();
@@ -20,96 +19,70 @@ const RootPath = process.cwd();
* @param {object} options The options
* @param {string} path The folder that needs to be compiled, optional
*/
-module.exports.compile = (options, path) => {
- Promise.resolve()
- // Compile the scss files
- .then(() => {
- const files = [];
- let folders = [];
+module.exports.stylesheets = async (options, path) => {
+ const files = [];
+ let folders = [];
- if (path) {
- const stats = Fs.lstatSync(`${RootPath}/${path}`);
+ if (path) {
+ const stats = await stat(`${RootPath}/${path}`);
- if (stats.isDirectory()) {
- folders.push(`${RootPath}/${path}`);
- } else if (stats.isFile()) {
- files.push(`${RootPath}/${path}`);
- } else {
- // eslint-disable-next-line no-console
- console.error(`Unknown path ${path}`);
- process.exit(1);
- }
- } else {
- folders = [
- `${RootPath}/build/media_source`,
- `${RootPath}/templates`,
- `${RootPath}/installation/template`,
- `${RootPath}/administrator/templates`,
- ];
- }
+ if (stats.isDirectory()) {
+ folders.push(`${RootPath}/${path}`);
+ } else if (stats.isFile()) {
+ files.push(`${RootPath}/${path}`);
+ } else {
+ // eslint-disable-next-line no-console
+ console.error(`Unknown path ${path}`);
+ process.exit(1);
+ }
+ } else {
+ folders = [
+ `${RootPath}/build/media_source`,
+ `${RootPath}/templates`,
+ `${RootPath}/administrator/templates`,
+ `${RootPath}/installation/template`,
+ `${RootPath}/media/vendor/debugbar`,
+ ];
+ }
- // Loop to get the files that should be compiled via parameter
- folders.forEach((folder) => {
- Recurs(folder, ['*.js', '*.map', '*.svg', '*.png', '*.gif', '*.swf', '*.html', '*.json']).then(
- (filesRc) => {
- filesRc.forEach(
- (file) => {
- // Don't take files with "_" but "file" has the full path, so check via match
- if (file.match(/\.scss$/)) {
- // Bail out for non Joomla convention folders, eg: scss
- if (!(file.match(/\/scss\//) || file.match(/\\scss\\/))) {
- return;
- }
- // Ignore files starting with _
- if (!file.match(/(\/|\\)_[^/\\]+$/)) {
- files.push(file);
- }
+ const folderPromises = [];
- // Update the scss in the media folder
- if (file.match(/build\/media_source\//)) {
- FsExtra.mkdirsSync(Path.dirname(file).replace('/build/media_source/', '/media/').replace('\\build\\media_source\\', '\\media\\'), {});
- Fs.copyFileSync(file, file.replace('/build/media_source/', '/media/').replace('\\build\\media_source\\', '\\media\\'));
- }
- }
- if (file.match(/\.css/) && !(file.match(/\/template(s)?\//) || file.match(/\\template(s)?\\/))) {
- // CSS file, we will copy the file and then minify it in place
- // Ensure that the directories exist or create them
- FsExtra.mkdirsSync(Path.dirname(file).replace('/build/media_source/', '/media/').replace('\\build\\media_source\\', '\\media\\'), {});
- Fs.copyFileSync(file, file.replace('/build/media_source/', '/media/').replace('\\build\\media_source\\', '\\media\\'));
- Fs.writeFileSync(
- file.replace('/build/media_source/', '/media/').replace('\\build\\media_source\\', '\\media\\').replace('.css', '.min.css'),
- UglyCss.processFiles([file], { expandVars: false }),
- { encoding: 'utf8' },
- );
+ // Loop to get the files that should be compiled via parameter
+ // eslint-disable-next-line no-restricted-syntax
+ for (const folder of folders) {
+ folderPromises.push(recursive(folder, ['!*.+(scss|css)']));
+ }
- // eslint-disable-next-line no-console
- console.log(`CSS file copied/minified: ${file}`);
- }
- },
- (error) => {
- // eslint-disable-next-line no-console
- console.error(error.formatted);
- },
- );
+ const computedFiles = await Promise.all(folderPromises);
- return files;
- },
- ).then(
- (scssFiles) => {
- scssFiles.forEach(
- (inputFile) => {
- CompileScss.compile(inputFile);
- },
- );
- },
- );
- });
- })
+ const cssFilesPromises = [];
+ const scssFilesPromises = [];
- // Handle errors
- .catch((error) => {
- // eslint-disable-next-line no-console
- console.error(`${error}`);
- process.exit(1);
- });
+ // Loop to get the files that should be compiled via parameter
+ [].concat(...computedFiles).forEach((file) => {
+ if (file.endsWith('.css') && !file.endsWith('.min.css')) {
+ cssFilesPromises.push(handleCssFile(file));
+ }
+
+ // Don't take files with "_" but "file" has the full path, so check via match
+ if (file.endsWith('.scss') && !file.match(/(\/|\\)_[^/\\]+$/)) {
+ // Bail out for non Joomla convention folders, eg: scss
+ if (!(file.match(/\/scss\//) || file.match(/\\scss\\/))) {
+ return;
+ }
+
+ files.push(file);
+ }
+ });
+
+ // eslint-disable-next-line no-restricted-syntax
+ for (const file of files) {
+ const outputFile = file.replace(`${sep}scss${sep}`, `${sep}css${sep}`)
+ .replace(`${sep}build${sep}media_source${sep}`, `${sep}media${sep}`)
+ .replace('.scss', '.css');
+
+ scssFilesPromises.push(handleScssFile(file, outputFile));
+ }
+
+ await Promise.all([...cssFilesPromises, ...scssFilesPromises]);
};
diff --git a/build/build-modules-js/compilejs.es6.js b/build/build-modules-js/compilejs.es6.js
index d79c201236c01..0f3122d3ddac0 100644
--- a/build/build-modules-js/compilejs.es6.js
+++ b/build/build-modules-js/compilejs.es6.js
@@ -1,7 +1,9 @@
-const Fs = require('fs');
+const { stat } = require('fs-extra');
const { sep } = require('path');
-const Recurs = require('recursive-readdir');
-const HandleFile = require('./javascript/handle-file.es6.js');
+const recursive = require('recursive-readdir');
+const { handleES5File } = require('./javascript/handle-es5.es6.js');
+const { handleESMFile } = require('./javascript/compile-es6.es6.js');
+const { handleWCFile } = require('./javascript/compile-w-c.es6.js');
const RootPath = process.cwd();
@@ -19,50 +21,58 @@ const RootPath = process.cwd();
* @param { object } options The options from settings.json
* @param { string } path The folder that needs to be compiled, optional
*/
-module.exports.compileJS = (options, path) => {
- Promise.resolve(options, path)
- // Compile the scss files
- .then(() => {
- let folders = [];
- if (path) {
- const stats = Fs.lstatSync(`${RootPath}/${path}`);
+module.exports.scripts = async (options, path) => {
+ const files = [];
+ let folders = [];
- if (!stats.isDirectory()) {
- // @todo: allow to compile single file
- throw new Error(`Path should be a directory: ${path}`);
- }
+ if (path) {
+ const stats = await stat(`${RootPath}/${path}`);
- folders.push(`${RootPath}/${path}`);
- } else {
- folders = [
- `${RootPath}/build/media_source`,
- `${RootPath}/templates/cassiopeia/js`,
- ];
- }
+ if (stats.isDirectory()) {
+ folders.push(`${RootPath}/${path}`);
+ } else if (stats.isFile()) {
+ files.push(`${RootPath}/${path}`);
+ } else {
+ // eslint-disable-next-line no-console
+ console.error(`Unknown path ${path}`);
+ process.exit(1);
+ }
+ } else {
+ folders = [
+ `${RootPath}/build/media_source`,
+ `${RootPath}/templates/cassiopeia`,
+ ];
+ }
- // Loop to get some text for the packgage.json
- folders.forEach((folder) => {
- Recurs(folder, ['*.min.js', '*.map', '*.scss', '*.css', '*.svg', '*.png', '*.swf', '*.gif', '*.json']).then(
- (files) => {
- files.forEach(
- (file) => {
- if (file.includes(`build${sep}media_source${sep}vendor${sep}bootstrap${sep}js`)) {
- return;
- }
- HandleFile.run(file);
- },
- (error) => {
- // eslint-disable-next-line no-console
- console.error(error.formatted);
- },
- );
- },
- );
- });
- })
+ const folderPromises = [];
- // Handle errors
- .catch((error) => {
- throw new Error(`${error}`);
- });
+ // Loop to get the files that should be compiled via parameter
+ // eslint-disable-next-line no-restricted-syntax
+ for (const folder of folders) {
+ folderPromises.push(recursive(folder, ['!*.+(js)']));
+ }
+
+ const computedFiles = await Promise.all(folderPromises);
+ const computedFilesFlat = [].concat(...computedFiles);
+
+ const jsFilesPromises = [];
+ const wcFilesPromises = [];
+ const esmFilesPromises = [];
+
+ // Loop to get the files that should be compiled via parameter
+ computedFilesFlat.forEach((file) => {
+ if (file.includes(`build${sep}media_source${sep}vendor${sep}bootstrap${sep}js`)) {
+ return;
+ }
+
+ if (file.match(/\.es5\.js$/)) {
+ jsFilesPromises.push(handleES5File(file));
+ } else if (file.match(/\.w-c\.es6\.js$/)) {
+ wcFilesPromises.push(handleWCFile(file));
+ } else if (file.match(/\.es6\.js$/)) {
+ esmFilesPromises.push(handleESMFile(file));
+ }
+ });
+
+ await Promise.all([...jsFilesPromises, ...wcFilesPromises, ...esmFilesPromises]);
};
diff --git a/build/build-modules-js/compress.es6.js b/build/build-modules-js/compress.es6.js
new file mode 100644
index 0000000000000..bc29aff3bb5d1
--- /dev/null
+++ b/build/build-modules-js/compress.es6.js
@@ -0,0 +1,26 @@
+const { getFiles } = require('@dgrammatiko/compress/src/getFiles.js');
+const { compressFile } = require('@dgrammatiko/compress/src/compressFile.js');
+
+/**
+ * Method that will pre compress (gzip) all .css/.js files
+ * in the templates and in the media folder
+ */
+module.exports.compressFiles = async (enableBrotli = false) => {
+ const paths = [
+ `${process.cwd()}/media`,
+ `${process.cwd()}/installation/template`,
+ `${process.cwd()}/templates`,
+ `${process.cwd()}/administrator/templates`,
+ ];
+
+ const tasks = [];
+ const compressTasks = [];
+ paths.map((path) => tasks.push(getFiles(`${path}/`)));
+
+ const files = await Promise.all(tasks);
+ [].concat(...files).map((file) => compressTasks.push(compressFile(file, enableBrotli)));
+
+ await Promise.all(compressTasks);
+ // eslint-disable-next-line no-console
+ console.log('Done 👍');
+};
diff --git a/build/build-modules-js/error-pages.es6.js b/build/build-modules-js/error-pages.es6.js
index 41ccd150f3de2..70177aa0ee3ac 100644
--- a/build/build-modules-js/error-pages.es6.js
+++ b/build/build-modules-js/error-pages.es6.js
@@ -1,20 +1,20 @@
-const Fs = require('fs');
+const {
+ access, mkdir, readFile, writeFile,
+} = require('fs').promises;
const Ini = require('ini');
-const Path = require('path');
+const { dirname } = require('path');
const Recurs = require('recursive-readdir');
-const UglifyCss = require('uglifycss');
-const UglifyJs = require('uglify-es');
+const Postcss = require('postcss');
+const Autoprefixer = require('autoprefixer');
+const CssNano = require('cssnano');
+const { minify } = require('terser');
const RootPath = process.cwd();
const dir = `${RootPath}/installation/language`;
const srcPath = `${RootPath}/build/warning_page`;
-// Set the initial template
-let incomplete = 'window.errorLocale = {';
-let unsupported = 'window.errorLocale = {';
-
/**
- * Will produce 2 .html files
+ * Will produce as many .html files as defined in settings.json
* Expects three files:
* build/warning_page/template.css
* build/warning_page/template.html
@@ -23,80 +23,141 @@ let unsupported = 'window.errorLocale = {';
* And also specific strings in the languages in the installation folder!
* Also the base strings are held in build/build-modules-js/settings.json
*/
-module.exports.run = (options) => {
- const initTemplate = Fs.readFileSync(`${srcPath}/template.html`, 'utf-8');
- let cssContent = Fs.readFileSync(`${srcPath}/template.css`, 'utf-8');
- let jsContent = Fs.readFileSync(`${srcPath}/template.js`, 'utf-8');
-
- cssContent = UglifyCss.processString(cssContent, { expandVars: false });
- jsContent = UglifyJs.minify(jsContent);
-
- Recurs(dir).then(
- (files) => {
- files.sort().forEach((file) => {
- const languageStrings = Ini.parse(Fs.readFileSync(file, 'UTF-8'));
-
- // Build the variables into json for the unsupported page
- if (languageStrings.MIN_PHP_ERROR_LANGUAGE) {
- const name = Path.dirname(file).replace(/.+\//, '').replace(/.+\\/, '');
- unsupported += `"${name}":{"language":"${languageStrings.MIN_PHP_ERROR_LANGUAGE}",`
- + `"header":"${languageStrings.MIN_PHP_ERROR_HEADER}",`
- + `"text1":"${languageStrings.MIN_PHP_ERROR_TEXT}",`
- + `"help-url-text":"${languageStrings.MIN_PHP_ERROR_URL_TEXT}"},`;
- }
-
- // Build the variables into json for the unsupported page
- if (languageStrings.BUILD_INCOMPLETE_LANGUAGE) {
- const name = Path.dirname(file).replace(/.+\//, '').replace(/.+\\/, '');
- incomplete += `"${name}":{"language":"${languageStrings.BUILD_INCOMPLETE_LANGUAGE}",`
- + `"header":"${languageStrings.BUILD_INCOMPLETE_HEADER}",`
- + `"text1":"${languageStrings.BUILD_INCOMPLETE_TEXT}",`
- + `"help-url-text":"${languageStrings.BUILD_INCOMPLETE_URL_TEXT}"},`;
- }
- });
-
- unsupported = `${unsupported}}`;
- incomplete = `${incomplete}}`;
-
- Object.keys(options.settings.errorPages).sort().forEach((name) => {
- let checkContent = initTemplate;
- checkContent = checkContent.replace('{{jsonContents}}', name === 'incomplete' ? incomplete : unsupported);
- checkContent = checkContent.replace('{{PHP_VERSION}}', '');
- checkContent = checkContent.replace('{{Title}}', options.settings.errorPages[name].title);
- checkContent = checkContent.replace('{{Header}}', options.settings.errorPages[name].header);
- checkContent = checkContent.replace('{{Description}}', options.settings.errorPages[name].text);
- checkContent = checkContent.replace('{{Link}}', options.settings.errorPages[name].link);
- checkContent = checkContent.replace('{{LinkText}}', options.settings.errorPages[name].linkText);
-
- if (cssContent) {
- checkContent = checkContent.replace('{{cssContents}}', cssContent);
- }
-
- if (jsContent) {
- checkContent = checkContent.replace('{{jsContents}}', jsContent.code);
- }
-
- Fs.writeFile(
- `${RootPath}${options.settings.errorPages[name].destFile}`,
- checkContent,
- { encoding: 'utf8' },
- (err) => {
- if (err) {
- // eslint-disable-next-line no-console
- console.log(err);
- return;
- }
-
- // eslint-disable-next-line no-console
- console.log(`The ${options.settings.errorPages[name].destFile} page was created successfully!`);
- },
- );
- });
- },
- (error) => {
- // eslint-disable-next-line no-console
- console.error(`${error}`);
- process.exit(1);
- },
- );
+module.exports.createErrorPages = async (options) => {
+ const iniFilesProcess = [];
+ const processPages = [];
+ global.incompleteObj = {};
+ global.unsupportedObj = {};
+ global.fatalObj = {};
+ global.noxmlObj = {};
+
+ const initTemplate = await readFile(`${srcPath}/template.html`, { encoding: 'utf8' });
+ let cssContent = await readFile(`${srcPath}/template.css`, { encoding: 'utf8' });
+ let jsContent = await readFile(`${srcPath}/template.js`, { encoding: 'utf8' });
+
+ const cssMin = await Postcss([Autoprefixer, CssNano]).process(cssContent, { from: undefined });
+
+ cssContent = cssMin.css;
+ jsContent = await minify(jsContent);
+
+ const processIni = async (file) => {
+ const languageStrings = Ini.parse(await readFile(file, { encoding: 'utf8' }));
+
+ // Build the variables into json for the unsupported page
+ if (languageStrings.MIN_PHP_ERROR_LANGUAGE) {
+ const name = dirname(file).replace(/.+\//, '').replace(/.+\\/, '');
+ global.unsupportedObj = {
+ ...global.unsupportedObj,
+ [name]: {
+ language: languageStrings.BUILD_MIN_PHP_ERROR_LANGUAGE,
+ header: languageStrings.BUILD_MIN_PHP_ERROR_HEADER,
+ text1: languageStrings.BUILD_MIN_PHP_ERROR_TEXT,
+ 'help-url-text': languageStrings.BUILD_MIN_PHP_ERROR_URL_TEXT,
+ },
+ };
+ }
+
+ // Build the variables into json for the build incomplete page
+ if (languageStrings.BUILD_INCOMPLETE_LANGUAGE) {
+ const name = dirname(file).replace(/.+\//, '').replace(/.+\\/, '');
+ global.incompleteObj = {
+ ...global.incompleteObj,
+ [name]: {
+ language: languageStrings.BUILD_INCOMPLETE_LANGUAGE,
+ header: languageStrings.BUILD_INCOMPLETE_HEADER,
+ text1: languageStrings.BUILD_INCOMPLETE_TEXT,
+ 'help-url-text': languageStrings.BUILD_INCOMPLETE_URL_TEXT,
+ },
+ };
+ }
+
+ // Build the variables into json for the fatal error page
+ if (languageStrings.BUILD_FATAL_LANGUAGE) {
+ const name = dirname(file).replace(/.+\//, '').replace(/.+\\/, '');
+ global.fatalObj = {
+ ...global.fatalObj,
+ [name]: {
+ language: languageStrings.BUILD_FATAL_LANGUAGE,
+ header: languageStrings.BUILD_FATAL_HEADER,
+ text1: languageStrings.BUILD_FATAL_TEXT,
+ 'help-url-text': languageStrings.BUILD_FATAL_URL_TEXT,
+ },
+ };
+ }
+
+ // Build the variables into json for the missing XML error page
+ if (languageStrings.BUILD_NOXML_LANGUAGE) {
+ const name = dirname(file).replace(/.+\//, '').replace(/.+\\/, '');
+ global.noxmlObj = {
+ ...global.noxmlObj,
+ [name]: {
+ language: languageStrings.BUILD_NOXML_LANGUAGE,
+ header: languageStrings.BUILD_NOXML_HEADER,
+ text1: languageStrings.BUILD_NOXML_TEXT,
+ 'help-url-text': languageStrings.BUILD_NOXML_URL_TEXT,
+ },
+ };
+ }
+ };
+
+ const files = await Recurs(dir);
+ files.sort().forEach((file) => {
+ iniFilesProcess.push(processIni(file));
+ });
+
+ await Promise.all(iniFilesProcess).catch((err) => {
+ // eslint-disable-next-line no-console
+ console.error(err);
+ process.exit(-1);
+ });
+
+ const processPage = async (name) => {
+ const jsonContent = `window.errorLocale=${JSON.stringify(global[`${name}Obj`])};`;
+
+ let template = initTemplate;
+
+ template = template.replace('{{jsonContents}}', jsonContent);
+ template = template.replace('{{Title}}', options.settings.errorPages[name].title);
+ template = template.replace('{{Header}}', options.settings.errorPages[name].header);
+ template = template.replace('{{Description}}', options.settings.errorPages[name].text);
+ template = template.replace('{{Link}}', options.settings.errorPages[name].link);
+ template = template.replace('{{LinkText}}', options.settings.errorPages[name].linkText);
+
+ if (cssContent) {
+ template = template.replace('{{cssContents}}', cssContent);
+ }
+
+ if (jsContent) {
+ template = template.replace('{{jsContents}}', jsContent.code);
+ }
+
+ let mediaExists = false;
+ try {
+ await access(dirname(`${RootPath}${options.settings.errorPages[name].destFile}`));
+ mediaExists = true;
+ } catch (err) {
+ // Do nothing
+ }
+
+ if (!mediaExists) {
+ await mkdir(dirname(`${RootPath}${options.settings.errorPages[name].destFile}`), { recursive: true });
+ }
+
+ await writeFile(
+ `${RootPath}${options.settings.errorPages[name].destFile}`,
+ template,
+ { encoding: 'utf8' },
+ );
+
+ // eslint-disable-next-line no-console
+ console.error(`Created the file: ${options.settings.errorPages[name].destFile}`);
+ };
+
+ Object.keys(options.settings.errorPages).forEach((name) => processPages.push(processPage(name)));
+
+ await Promise.all(processPages).catch((err) => {
+ // eslint-disable-next-line no-console
+ console.error(err);
+ process.exit(-1);
+ });
};
diff --git a/build/build-modules-js/gzip-assets.es6.js b/build/build-modules-js/gzip-assets.es6.js
deleted file mode 100644
index f47d43fa5f51d..0000000000000
--- a/build/build-modules-js/gzip-assets.es6.js
+++ /dev/null
@@ -1,131 +0,0 @@
-/**
- * For creating Brotli files you need to install iltorb
- * and import it like:
- * const { compressStream } = require('iltorb');
- */
-const Fs = require('fs');
-const { gzip } = require('@gfx/zopfli');
-const walkSync = require('walk-sync');
-
-const RootPath = process.cwd();
-const compressStream = '';
-const options = {
- verbose: false,
- verbose_more: false,
- numiterations: 15,
- blocksplitting: true,
- blocksplittingmax: 15,
-};
-
-/**
- * Method that will create a gzipped vestion of the given file
- *
- * @param { string } file The path of the file
- *
- * @returns { void }
- */
-const handleFile = (file, enableBrotli) => {
- if (file.match('/images') || file.match('\\images')) {
- return;
- }
-
- if (file.match(/\.min\.js/) && !file.match(/\.min\.js\.gz/) && !file.match(/\.min\.js\.br/) && !file.toLowerCase().match(/json/) && !file.toLowerCase().match(/license/)) {
- // eslint-disable-next-line no-console
- console.log(`Processing: ${file}`);
-
- if (enableBrotli && compressStream) {
- // Brotli file
- Fs.createReadStream(file)
- .pipe(compressStream())
- .pipe(Fs.createWriteStream(file.replace(/\.js$/, '.js.br')));
- } else {
- // Gzip the file
- Fs.readFile(file, (err, data) => {
- if (err) throw err;
- gzip(data, options, (error, output) => {
- if (error) throw err;
- // Save the gzipped file
- Fs.writeFileSync(
- file.replace(/\.js$/, '.js.gz'),
- output,
- { encoding: 'utf8' },
- );
- });
- });
- }
- }
-
- if (file.match(/\.min\.css/) && !file.match(/\.min\.css\.gz/) && !file.match(/\.min\.css\.br/) && !file.match(/\.css\.map/) && !file.toLowerCase().match(/license/)) {
- // eslint-disable-next-line no-console
- console.log(`Processing: ${file}`);
-
- if (enableBrotli && compressStream) {
- // Brotli file
- Fs.createReadStream(file)
- .pipe(compressStream())
- .pipe(Fs.createWriteStream(file.replace(/\.css$/, '.css.br')));
- } else {
- // Gzip the file
- Fs.readFile(file, (err, data) => {
- if (err) throw err;
- gzip(data, options, (error, output) => {
- if (error) throw err;
- // Save the gzipped file
- Fs.writeFileSync(
- file.replace(/\.css$/, '.css.gz'),
- output,
- { encoding: 'utf8' },
- );
- });
- });
- }
- }
-};
-
-/**
- * Method to gzip the script and stylesheet files
- *
- * @param brotliParam {string} The CLI argument
- *
- * @returns { void }
- */
-const gzipFiles = (brotliParam) => {
- let enableBrotli = false;
- if (brotliParam === 'brotli') {
- enableBrotli = true;
- }
- // Minify the legacy files
- // eslint-disable-next-line no-console
- console.log('Gziping stylesheets and scripts...');
-
- const templatesFiles = walkSync(`${RootPath}/templates`, {
- globs: ['**/*.{js,css}'],
- includeBasePath: true,
- ignore: [],
- directories: false,
- });
- const adminTemplatesFiles = walkSync(`${RootPath}/administrator/templates`, {
- globs: ['**/*.{js,css}'],
- includeBasePath: true,
- ignore: [],
- directories: false,
- });
- const mediaFiles = walkSync(`${RootPath}/media`, {
- globs: ['**/*.{js,css}'],
- includeBasePath: true,
- ignore: [],
- directories: false,
- });
-
- if (templatesFiles.length) {
- templatesFiles.forEach((file) => handleFile(file, enableBrotli));
- }
- if (adminTemplatesFiles.length) {
- adminTemplatesFiles.forEach((file) => handleFile(file, enableBrotli));
- }
- if (mediaFiles.length) {
- mediaFiles.forEach((file) => handleFile(file, enableBrotli));
- }
-};
-
-module.exports.gzipFiles = gzipFiles;
diff --git a/build/build-modules-js/init.es6.js b/build/build-modules-js/init.es6.js
deleted file mode 100644
index acba1d26452b3..0000000000000
--- a/build/build-modules-js/init.es6.js
+++ /dev/null
@@ -1,363 +0,0 @@
-const Copydir = require('copy-dir');
-const Fs = require('fs');
-const FsExtra = require('fs-extra');
-const Path = require('path');
-
-const RootPath = process.cwd();
-const xmlVersionStr = /()(.+)(<\/version>)/;
-
-/**
- * Method that will erase the media/vendor folder
- * and populate the debugbar assets
- *
- * @returns { void }
- */
-const cleanVendors = () => {
- if (Fs.existsSync(Path.join(RootPath, 'libraries/vendor/maximebf/debugbar/src/DebugBar/Resources'))) {
- // Remove the vendor folder
- FsExtra.removeSync(Path.join(RootPath, 'media/vendor'));
- // eslint-disable-next-line no-console
- console.error('/media/vendor has been removed.');
-
- // Copy some assets from a PHP package
- FsExtra.copySync(Path.join(RootPath, 'libraries/vendor/maximebf/debugbar/src/DebugBar/Resources'), Path.join(RootPath, 'media/vendor/debugbar'));
- // Do some cleanup
- FsExtra.removeSync(Path.join(RootPath, 'media/vendor/debugbar/vendor/font-awesome'));
- FsExtra.removeSync(Path.join(RootPath, 'media/vendor/debugbar/vendor/jquery'));
- } else {
- // eslint-disable-next-line no-console
- console.error('You need to run `npm install` AFTER the command `composer install`!!!. The debug plugin HASN\'T installed all its front end assets');
- process.exit(1);
- }
-};
-
-/**
- * Copies all the files from a directory
- *
- * @param {string} dirName the name of the source folder
- * @param {string} name the name of the destination folder
- * @param {string} type the type of the folder, eg: js, css, fonts, images
- *
- * @returns { void }
- */
-const copyAll = (dirName, name, type) => {
- const folderName = dirName === '/' ? '/' : `/${dirName}`;
- FsExtra.copySync(Path.join(RootPath, `node_modules/${name}/${folderName}`),
- Path.join(RootPath, `media/vendor/${name.replace(/.+\//, '')}/${type}`));
-};
-
-/**
- * Copies an array of files from a directory
- *
- * @param {string} dirName the name of the source folder
- * @param {array} files the array of files to be be copied
- * @param {string} name the name of the destination folder
- * @param {string} type the type of the folder, eg: js, css, fonts, images
- *
- * @returns { void }
- */
-const copyArrayFiles = (dirName, files, name, type) => {
- files.forEach((file) => {
- const folderName = dirName === '/' ? '/' : `/${dirName}/`;
- if (FsExtra.existsSync(`node_modules/${name}${folderName}${file}`)) {
- FsExtra.copySync(`node_modules/${name}${folderName}${file}`, `media/vendor/${name.replace(/.+\//, '')}${type ? `/${type}` : ''}/${file}`);
- }
- });
-};
-
-/**
- *
- * @param {object} files the object of files map, eg {"src.js": "js/src.js"}
- * @param {string} srcDir the name of the package root dir
- * @param {string} destDir the name of the Vendor destination dir
- *
- * @returns {Array}
- */
-const copyFilesTo = (files, srcDir, destDir) => {
- const filesResult = [];
-
- // Copy each file
- // eslint-disable-next-line guard-for-in, no-restricted-syntax
- for (const srcFile in files) {
- const destFile = files[srcFile];
- const srcPath = Path.join(srcDir, srcFile);
- const destPath = Path.join(destDir, destFile);
-
- FsExtra.copySync(srcPath, destPath);
- filesResult.push(destPath);
- }
-
- return filesResult;
-};
-
-/**
- * Method to concatenate some files
- *
- * @param {array} files the array of files to be be concatenated
- * @param {string} output the name of the output file
- *
- * @returns {void}
- */
-const concatFiles = (files, output) => {
- let tempMem = '';
- files.forEach((file) => {
- if (FsExtra.existsSync(`${RootPath}/${file}`)) {
- tempMem += Fs.readFileSync(`${RootPath}/${file}`);
- }
- });
-
- Fs.writeFileSync(`${RootPath}/${output}`, tempMem);
-};
-
-/**
- * Main method that will copy all vendor files according to Joomla's specs
- *
- * @param options The options from setting.json
- *
- * @returns {void}
- */
-const copyFiles = (options) => {
- const mediaVendorPath = Path.join(RootPath, 'media/vendor');
- const registry = {
- $schema: 'https://developer.joomla.org/schemas/json-schema/web_assets.json',
- name: options.name,
- version: options.version,
- description: options.description,
- license: options.license,
- assets: [],
- };
-
- if (!FsExtra.existsSync(mediaVendorPath)) {
- FsExtra.mkdirSync(mediaVendorPath);
- }
-
- // Loop to get some text for the packgage.json
- // eslint-disable-next-line guard-for-in, no-restricted-syntax
- for (const packageName in options.settings.vendors) {
- const vendor = options.settings.vendors[packageName];
- const vendorName = vendor.name || packageName;
- const modulePathJson = require.resolve(`${packageName}/package.json`);
- const modulePathRoot = Path.dirname(modulePathJson);
- // eslint-disable-next-line global-require, import/no-dynamic-require
- const moduleOptions = require(modulePathJson);
-
- if (packageName === 'codemirror') {
- const itemvendorPath = Path.join(RootPath, `media/vendor/${packageName}`);
- if (!FsExtra.existsSync(itemvendorPath)) {
- FsExtra.mkdirSync(itemvendorPath);
- FsExtra.mkdirSync(Path.join(itemvendorPath, 'addon'));
- FsExtra.mkdirSync(Path.join(itemvendorPath, 'lib'));
- FsExtra.mkdirSync(Path.join(itemvendorPath, 'mode'));
- FsExtra.mkdirSync(Path.join(itemvendorPath, 'keymap'));
- FsExtra.mkdirSync(Path.join(itemvendorPath, 'theme'));
- }
-
- copyAll('addon', 'codemirror', 'addon');
- copyAll('lib', 'codemirror', 'lib');
- copyAll('mode', 'codemirror', 'mode');
- copyAll('keymap', 'codemirror', 'keymap');
- copyAll('theme', 'codemirror', 'theme');
-
- concatFiles(
- [
- 'media/vendor/codemirror/addon/display/autorefresh.js',
- 'media/vendor/codemirror/addon/display/fullscreen.js',
- 'media/vendor/codemirror/addon/display/panel.js',
- 'media/vendor/codemirror/addon/edit/closebrackets.js',
- 'media/vendor/codemirror/addon/edit/closetag.js',
- 'media/vendor/codemirror/addon/edit/matchbrackets.js',
- 'media/vendor/codemirror/addon/edit/matchtags.js',
- 'media/vendor/codemirror/addon/fold/brace-fold.js',
- 'media/vendor/codemirror/addon/fold/foldcode.js',
- 'media/vendor/codemirror/addon/fold/foldgutter.js',
- 'media/vendor/codemirror/addon/fold/xml-fold.js',
- 'media/vendor/codemirror/addon/mode/loadmode.js',
- 'media/vendor/codemirror/addon/mode/multiplex.js',
- 'media/vendor/codemirror/addon/scroll/annotatescrollbar.js',
- 'media/vendor/codemirror/addon/scroll/simplescrollbars.js',
- 'media/vendor/codemirror/addon/scroll/matchesonscrollbar.js',
- 'media/vendor/codemirror/addon/scroll/match-highlighter.js',
- 'media/vendor/codemirror/addon/scroll/searchcursor.js',
- 'media/vendor/codemirror/addon/selection/active-line.js',
- 'media/vendor/codemirror/mode/meta.js',
- ],
- 'media/vendor/codemirror/lib/addons.js',
- );
-
- concatFiles(
- [
- 'media/vendor/codemirror/lib/codemirror.js',
- 'media/vendor/codemirror/lib/addons.js',
-
- ],
- 'media/vendor/codemirror/lib/codemirror-ce.js',
- );
-
- concatFiles([
- 'media/vendor/codemirror/addon/display/fullscreen.css',
- 'media/vendor/codemirror/addon/fold/foldgutter.css',
- 'media/vendor/codemirror/addon/search/matchesonscrollbar.css',
- 'media/vendor/codemirror/addon/scroll/simplescrollbars.css',
- ], 'media/vendor/codemirror/lib/addons.css');
-
- // Update the XML file for Codemirror
- let codemirrorXml = Fs.readFileSync(`${RootPath}/plugins/editors/codemirror/codemirror.xml`, { encoding: 'UTF-8' });
- codemirrorXml = codemirrorXml.replace(xmlVersionStr, `$1${moduleOptions.version}$3`);
- Fs.writeFileSync(`${RootPath}/plugins/editors/codemirror/codemirror.xml`, codemirrorXml, { encoding: 'UTF-8' });
- } else if (packageName === 'tinymce') {
- const itemvendorPath = Path.join(RootPath, `media/vendor/${packageName}`);
-
- if (!FsExtra.existsSync(itemvendorPath)) {
- FsExtra.mkdirSync(itemvendorPath);
- FsExtra.mkdirSync(Path.join(itemvendorPath, 'icons'));
- FsExtra.mkdirSync(Path.join(itemvendorPath, 'plugins'));
- FsExtra.mkdirSync(Path.join(itemvendorPath, 'langs'));
- FsExtra.mkdirSync(Path.join(itemvendorPath, 'skins'));
- FsExtra.mkdirSync(Path.join(itemvendorPath, 'themes'));
- FsExtra.mkdirSync(Path.join(itemvendorPath, 'templates'));
- }
-
- copyAll('icons', 'tinymce', 'icons');
- copyAll('plugins', 'tinymce', 'plugins');
- copyAll('skins', 'tinymce', 'skins');
- copyAll('themes', 'tinymce', 'themes');
-
- copyArrayFiles('', ['tinymce.js', 'tinymce.min.js', 'changelog.txt', 'license.txt'], 'tinymce', '');
-
- // Update the XML file for tinyMCE
- let tinyXml = Fs.readFileSync(`${RootPath}/plugins/editors/tinymce/tinymce.xml`, { encoding: 'UTF-8' });
- tinyXml = tinyXml.replace(xmlVersionStr, `$1${moduleOptions.version}$3`);
- Fs.writeFileSync(`${RootPath}/plugins/editors/tinymce/tinymce.xml`, tinyXml, { encoding: 'UTF-8' });
-
- // Remove that sourcemap...
- let tinyWrongMap = Fs.readFileSync(`${RootPath}/media/vendor/tinymce/skins/ui/oxide/skin.min.css`, { encoding: 'UTF-8' });
- tinyWrongMap = tinyWrongMap.replace('/*# sourceMappingURL=skin.min.css.map */', '');
- Fs.writeFileSync(`${RootPath}/media/vendor/tinymce/skins/ui/oxide/skin.min.css`, tinyWrongMap, { encoding: 'UTF-8' });
- } else {
- ['js', 'css', 'filesExtra'].forEach((type) => {
- if (!vendor[type]) return;
-
- const dest = Path.join(mediaVendorPath, vendorName);
- copyFilesTo(vendor[type], modulePathRoot, dest, type);
- });
-
- // Copy the license if exists
- if (options.settings.vendors[packageName].licenseFilename
- && Fs.existsSync(`${Path.join(RootPath, `node_modules/${packageName}`)}/${options.settings.vendors[packageName].licenseFilename}`)
- ) {
- const dest = Path.join(mediaVendorPath, vendorName);
- FsExtra.copySync(`${Path.join(RootPath, `node_modules/${packageName}`)}/${options.settings.vendors[packageName].licenseFilename}`, `${dest}/${options.settings.vendors[packageName].licenseFilename}`);
- }
- }
-
- // Joomla's hack to expose the chosen base classes so we can extend it ourselves
- // (it was better than the many hacks we had before. But I'm still ashamed of myself).
- if (packageName === 'chosen-js') {
- const dest = Path.join(mediaVendorPath, vendorName);
- const chosenPath = `${dest}/${options.settings.vendors[packageName].js['chosen.jquery.js']}`;
- let ChosenJs = Fs.readFileSync(chosenPath, { encoding: 'UTF-8' });
- ChosenJs = ChosenJs.replace('}).call(this);', ' document.AbstractChosen = AbstractChosen;\n'
- + ' document.Chosen = Chosen;\n'
- + '}).call(this);');
- Fs.writeFileSync(chosenPath, ChosenJs, { encoding: 'UTF-8' });
- }
-
- // Append initialising code to the end of the Short-and-Sweet javascript
- if (packageName === 'short-and-sweet') {
- const dest = Path.join(mediaVendorPath, vendorName);
- const shortandsweetPath = `${dest}/${options.settings.vendors[packageName].js['dist/short-and-sweet.min.js']}`;
- let ShortandsweetJs = Fs.readFileSync(shortandsweetPath, { encoding: 'UTF-8' });
- ShortandsweetJs = ShortandsweetJs.concat('document.addEventListener(\'DOMContentLoaded\', function()'
- + '{shortAndSweet(\'textarea.charcount\', {counterClassName: \'small text-muted\'}); });');
- Fs.writeFileSync(shortandsweetPath, ShortandsweetJs, { encoding: 'UTF-8' });
- }
-
- // Add provided Assets to a registry, if any
- if (vendor.provideAssets && vendor.provideAssets.length) {
- vendor.provideAssets.forEach((assetInfo) => {
- const registryItemBase = {
- package: packageName,
- name: assetInfo.name || vendorName,
- version: moduleOptions.version,
- type: assetInfo.type,
- };
-
- const registryItem = Object.assign(assetInfo, registryItemBase);
-
- // Update path to file
- if (assetInfo.uri && (assetInfo.type === 'script' || assetInfo.type === 'style' || assetInfo.type === 'webcomponent')) {
- let itemPath = assetInfo.uri;
-
- // Check for external path
- if (itemPath.indexOf('http://') !== 0 && itemPath.indexOf('https://') !== 0 && itemPath.indexOf('//') !== 0) {
- itemPath = `vendor/${vendorName}/${itemPath}`;
- }
-
- registryItem.uri = itemPath;
- }
-
- registry.assets.push(registryItem);
- });
- }
-
- // eslint-disable-next-line no-console
- console.log(`${packageName} was updated.`);
- }
-
- // Write assets registry
- Fs.writeFileSync(
- Path.join(mediaVendorPath, 'joomla.asset.json'),
- JSON.stringify(registry, null, 2),
- { encoding: 'UTF-8' },
- );
-
- // Restore our code on the vendor folders
- FsExtra.copySync(Path.join(RootPath, 'build/media_source/vendor/tinymce/templates'), Path.join(RootPath, 'media/vendor/tinymce/templates'));
-};
-
-/**
- * Method to recreate the basic media folder structure
- * After execution the media folder is populated with empty js and css subdirectories
- * images subfolders with the relative files
- * any other files except .js, .css, .scss
- *
- * @returns { void }
- */
-const recreateMediaFolder = () => {
- // eslint-disable-next-line no-console
- console.log('Recreating the media folder...');
-
- Copydir.sync(Path.join(RootPath, 'build/media_source'), Path.join(RootPath, 'media'), (stat, filepath, filename) => {
- if (stat === 'file' && filename.match(/\.(es6\.js|es5\.js|scss)$/)) {
- return false;
- }
- if (stat === 'directory' && filename.match(/^(core\.es6|scss)$/)) {
- return false;
- }
- return true;
- }, (err) => {
- if (!err) {
- // eslint-disable-next-line no-console
- console.log('Legacy media files restored');
- }
- });
-};
-
-module.exports.copyAssets = (options) => {
- Promise.resolve()
- // Copy a fresh version of the files
- .then(cleanVendors())
-
- // Copy a fresh version of the files
- .then(recreateMediaFolder())
-
- // Copy a fresh version of the files
- .then(copyFiles(options))
-
- // Handle errors
- .catch((error) => {
- // eslint-disable-next-line no-console
- console.error(`${error}`);
- process.exit(1);
- });
-};
diff --git a/build/build-modules-js/init/cleanup-media.es6.js b/build/build-modules-js/init/cleanup-media.es6.js
new file mode 100644
index 0000000000000..c3ccc0b1191ec
--- /dev/null
+++ b/build/build-modules-js/init/cleanup-media.es6.js
@@ -0,0 +1,38 @@
+const {
+ stat, mkdir, copy, remove,
+} = require('fs-extra');
+const { join } = require('path');
+
+const RootPath = process.cwd();
+
+/**
+ * Method that will erase the media/vendor folder
+ * and populate the debugbar assets
+ *
+ * @returns {Promise}
+ */
+module.exports.cleanVendors = async () => {
+ // eslint-disable-next-line no-console
+ console.log('Cleanup the Vendor ');
+
+ const mediaFolder = await stat(join(RootPath, 'libraries/vendor/maximebf/debugbar/src/DebugBar/Resources'));
+
+ if (await mediaFolder.isDirectory()) {
+ // Remove the vendor folder
+ // await remove(join(RootPath, 'media'));
+ // eslint-disable-next-line no-console
+ // console.error('/media has been removed.');
+
+ // Recreate the media folder
+ await mkdir(join(RootPath, 'media/vendor/debugbar'), { recursive: true });
+
+ // Copy some assets from a PHP package
+ await copy(join(RootPath, 'libraries/vendor/maximebf/debugbar/src/DebugBar/Resources'), join(RootPath, 'media/vendor/debugbar'));
+ await remove(join(RootPath, 'media/vendor/debugbar/vendor/font-awesome'));
+ await remove(join(RootPath, 'media/vendor/debugbar/vendor/jquery'));
+ } else {
+ // eslint-disable-next-line no-console
+ console.error('You need to run `npm install` AFTER the command `composer install`!!!. The debug plugin HASN\'T installed all its front end assets');
+ process.exit(1);
+ }
+};
diff --git a/build/build-modules-js/init/common/concat-files.es6.js b/build/build-modules-js/init/common/concat-files.es6.js
new file mode 100644
index 0000000000000..9d170c148789a
--- /dev/null
+++ b/build/build-modules-js/init/common/concat-files.es6.js
@@ -0,0 +1,26 @@
+const { readFile, writeFile, existsSync } = require('fs-extra');
+
+const RootPath = process.cwd();
+
+/**
+ * Method to concatenate some files
+ *
+ * @param {array} files the array of files to be be concatenated
+ * @param {string} output the name of the output file
+ *
+ * @returns {void}
+ */
+module.exports.concatFiles = async (files, output) => {
+ const promises = [];
+
+ // eslint-disable-next-line no-restricted-syntax
+ for (const file of files) {
+ if (existsSync(`${RootPath}/${file}`)) {
+ promises.push(readFile(`${RootPath}/${file}`, { encoding: 'utf8' }));
+ }
+ }
+
+ const res = await Promise.all(promises);
+
+ await writeFile(`${RootPath}/${output}`, res.join(' '));
+};
diff --git a/build/build-modules-js/init/common/copy-all-files.es6.js b/build/build-modules-js/init/common/copy-all-files.es6.js
new file mode 100644
index 0000000000000..7a78ddf658892
--- /dev/null
+++ b/build/build-modules-js/init/common/copy-all-files.es6.js
@@ -0,0 +1,19 @@
+const { copy } = require('fs-extra');
+const { join } = require('path');
+
+const RootPath = process.cwd();
+
+/**
+ * Copies all the files from a directory
+ *
+ * @param {string} dirName the name of the source folder
+ * @param {string} name the name of the destination folder
+ * @param {string} type the type of the folder, eg: js, css, fonts, images
+ *
+ * @returns { void }
+ */
+module.exports.copyAllFiles = async (dirName, name, type) => {
+ const folderName = dirName === '/' ? '/' : `/${dirName}`;
+ await copy(join(RootPath, `node_modules/${name}/${folderName}`),
+ join(RootPath, `media/vendor/${name.replace(/.+\//, '')}/${type}`));
+};
diff --git a/build/build-modules-js/init/exemptions/codemirror.es6.js b/build/build-modules-js/init/exemptions/codemirror.es6.js
new file mode 100644
index 0000000000000..9969522fc4632
--- /dev/null
+++ b/build/build-modules-js/init/exemptions/codemirror.es6.js
@@ -0,0 +1,78 @@
+const {
+ existsSync, readFile, writeFile, mkdir,
+} = require('fs-extra');
+const { join } = require('path');
+
+const { concatFiles } = require('../common/concat-files.es6.js');
+const { copyAllFiles } = require('../common/copy-all-files.es6.js');
+
+const RootPath = process.cwd();
+const xmlVersionStr = /()(.+)(<\/version>)/;
+
+/**
+ * Codemirror needs special treatment
+ */
+module.exports.codeMirror = async (packageName, version) => {
+ const itemvendorPath = join(RootPath, `media/vendor/${packageName}`);
+ if (!await existsSync(itemvendorPath)) {
+ await mkdir(itemvendorPath, { recursive: true });
+ await mkdir(join(itemvendorPath, 'addon'));
+ await mkdir(join(itemvendorPath, 'lib'));
+ await mkdir(join(itemvendorPath, 'mode'));
+ await mkdir(join(itemvendorPath, 'keymap'));
+ await mkdir(join(itemvendorPath, 'theme'));
+ }
+
+ await copyAllFiles('addon', 'codemirror', 'addon');
+ await copyAllFiles('lib', 'codemirror', 'lib');
+ await copyAllFiles('mode', 'codemirror', 'mode');
+ await copyAllFiles('keymap', 'codemirror', 'keymap');
+ await copyAllFiles('theme', 'codemirror', 'theme');
+
+ await concatFiles(
+ [
+ 'media/vendor/codemirror/addon/display/fullscreen.js',
+ 'media/vendor/codemirror/addon/display/panel.js',
+ 'media/vendor/codemirror/addon/edit/closebrackets.js',
+ 'media/vendor/codemirror/addon/edit/closetag.js',
+ 'media/vendor/codemirror/addon/edit/matchbrackets.js',
+ 'media/vendor/codemirror/addon/edit/matchtags.js',
+ 'media/vendor/codemirror/addon/fold/brace-fold.js',
+ 'media/vendor/codemirror/addon/fold/foldcode.js',
+ 'media/vendor/codemirror/addon/fold/foldgutter.js',
+ 'media/vendor/codemirror/addon/fold/xml-fold.js',
+ 'media/vendor/codemirror/addon/mode/loadmode.js',
+ 'media/vendor/codemirror/addon/mode/multiplex.js',
+ 'media/vendor/codemirror/addon/scroll/annotatescrollbar.js',
+ 'media/vendor/codemirror/addon/scroll/simplescrollbars.js',
+ 'media/vendor/codemirror/addon/scroll/matchesonscrollbar.js',
+ 'media/vendor/codemirror/addon/scroll/match-highlighter.js',
+ 'media/vendor/codemirror/addon/scroll/searchcursor.js',
+ 'media/vendor/codemirror/addon/selection/active-line.js',
+ 'media/vendor/codemirror/mode/meta.js',
+ ],
+ 'media/vendor/codemirror/lib/addons.js',
+ );
+
+ await concatFiles(
+ [
+ 'media/vendor/codemirror/lib/codemirror.js',
+ 'media/vendor/codemirror/lib/addons.js',
+ ],
+
+ 'media/vendor/codemirror/lib/codemirror-ce.js',
+ );
+
+ await concatFiles([
+ 'media/vendor/codemirror/addon/display/fullscreen.css',
+ 'media/vendor/codemirror/addon/fold/foldgutter.css',
+ 'media/vendor/codemirror/addon/search/matchesonscrollbar.css',
+ 'media/vendor/codemirror/addon/scroll/simplescrollbars.css',
+ ],
+ 'media/vendor/codemirror/lib/addons.css');
+
+ // Update the XML file for Codemirror
+ let codemirrorXml = await readFile(`${RootPath}/plugins/editors/codemirror/codemirror.xml`, { encoding: 'utf8' });
+ codemirrorXml = codemirrorXml.replace(xmlVersionStr, `$1${version}$3`);
+ await writeFile(`${RootPath}/plugins/editors/codemirror/codemirror.xml`, codemirrorXml, { encoding: 'utf8' });
+};
diff --git a/build/build-modules-js/init/exemptions/tinymce.es6.js b/build/build-modules-js/init/exemptions/tinymce.es6.js
new file mode 100644
index 0000000000000..4cf86913cc7d4
--- /dev/null
+++ b/build/build-modules-js/init/exemptions/tinymce.es6.js
@@ -0,0 +1,70 @@
+const {
+ existsSync, copy, readFile, writeFile, mkdir,
+} = require('fs-extra');
+const { join } = require('path');
+
+const { copyAllFiles } = require('../common/copy-all-files.es6.js');
+
+const RootPath = process.cwd();
+const xmlVersionStr = /()(.+)(<\/version>)/;
+
+/**
+ * Copies an array of files from a directory
+ *
+ * @param {string} dirName the name of the source folder
+ * @param {array} files the array of files to be be copied
+ * @param {string} name the name of the destination folder
+ * @param {string} type the type of the folder, eg: js, css, fonts, images
+ *
+ * @returns { void }
+ */
+const copyArrayFiles = async (dirName, files, name, type) => {
+ const promises = [];
+ // eslint-disable-next-line guard-for-in,no-restricted-syntax
+ for (const file of files) {
+ const folderName = dirName === '/' ? '/' : `/${dirName}/`;
+
+ if (existsSync(`node_modules/${name}${folderName}${file}`)) {
+ promises.push(copy(`node_modules/${name}${folderName}${file}`, `media/vendor/${name.replace(/.+\//, '')}${type ? `/${type}` : ''}/${file}`));
+ }
+ }
+
+ await Promise.all(promises);
+};
+
+/**
+ * tinyMCE needs special treatment
+ */
+module.exports.tinyMCE = async (packageName, version) => {
+ const itemvendorPath = join(RootPath, `media/vendor/${packageName}`);
+
+ if (!await existsSync(itemvendorPath)) {
+ await mkdir(itemvendorPath);
+ await mkdir(join(itemvendorPath, 'icons'));
+ await mkdir(join(itemvendorPath, 'plugins'));
+ await mkdir(join(itemvendorPath, 'langs'));
+ await mkdir(join(itemvendorPath, 'skins'));
+ await mkdir(join(itemvendorPath, 'themes'));
+ await mkdir(join(itemvendorPath, 'templates'));
+ }
+
+ await copyAllFiles('icons', 'tinymce', 'icons');
+ await copyAllFiles('plugins', 'tinymce', 'plugins');
+ await copyAllFiles('skins', 'tinymce', 'skins');
+ await copyAllFiles('themes', 'tinymce', 'themes');
+
+ await copyArrayFiles('', ['tinymce.js', 'tinymce.min.js', 'changelog.txt', 'license.txt'], 'tinymce', '');
+
+ // Update the XML file for tinyMCE
+ let tinyXml = await readFile(`${RootPath}/plugins/editors/tinymce/tinymce.xml`, { encoding: 'utf8' });
+ tinyXml = tinyXml.replace(xmlVersionStr, `$1${version}$3`);
+ await writeFile(`${RootPath}/plugins/editors/tinymce/tinymce.xml`, tinyXml, { encoding: 'utf8' });
+
+ // Remove that sourcemap...
+ let tinyWrongMap = await readFile(`${RootPath}/media/vendor/tinymce/skins/ui/oxide/skin.min.css`, { encoding: 'utf8' });
+ tinyWrongMap = tinyWrongMap.replace('/*# sourceMappingURL=skin.min.css.map */', '');
+ await writeFile(`${RootPath}/media/vendor/tinymce/skins/ui/oxide/skin.min.css`, tinyWrongMap, { encoding: 'utf8' });
+
+ // Restore our code on the vendor folders
+ await copy(join(RootPath, 'build/media_source/vendor/tinymce/templates'), join(RootPath, 'media/vendor/tinymce/templates'));
+};
diff --git a/build/build-modules-js/init/localise-packages.es6.js b/build/build-modules-js/init/localise-packages.es6.js
new file mode 100644
index 0000000000000..8437fca6e5030
--- /dev/null
+++ b/build/build-modules-js/init/localise-packages.es6.js
@@ -0,0 +1,149 @@
+const {
+ existsSync, copy, writeFile, mkdir, mkdirs, ensureDir,
+} = require('fs-extra');
+const { dirname, join } = require('path');
+const { codeMirror } = require('./exemptions/codemirror.es6.js');
+const { tinyMCE } = require('./exemptions/tinymce.es6.js');
+
+const RootPath = process.cwd();
+
+/**
+ *
+ * @param {object} files the object of files map, eg {"src.js": "js/src.js"}
+ * @param {string} srcDir the name of the package root dir
+ * @param {string} destDir the name of the Vendor destination dir
+ *
+ * @returns {Promise}
+ */
+const copyFilesTo = async (files, srcDir, destDir) => {
+ const copyPromises = [];
+
+ async function doTheCopy(source, dest) {
+ await ensureDir(dirname(dest));
+ await copy(source, dest);
+ }
+
+ // Copy each file
+ // eslint-disable-next-line no-restricted-syntax,guard-for-in
+ for (const srcFile in files) {
+ copyPromises.push(doTheCopy(join(srcDir, srcFile), join(destDir, files[srcFile])));
+ }
+
+ return Promise.all(copyPromises);
+};
+
+/**
+ * Main method that will resolve each vendor package
+ *
+ * @returns {Promise}
+ */
+const resolvePackage = async (vendor, packageName, mediaVendorPath, options, registry) => {
+ const vendorName = vendor.name || packageName;
+ const modulePathJson = require.resolve(`${packageName}/package.json`);
+ const modulePathRoot = dirname(modulePathJson);
+ // eslint-disable-next-line global-require, import/no-dynamic-require
+ const moduleOptions = require(modulePathJson);
+
+ const promises = [];
+
+ if (packageName === 'codemirror') {
+ promises.push(codeMirror(packageName, moduleOptions.version));
+ } else if (packageName === 'tinymce') {
+ promises.push(tinyMCE(packageName, moduleOptions.version));
+ } else {
+ await mkdirs(join(mediaVendorPath, vendorName));
+
+ ['js', 'css', 'filesExtra'].forEach((type) => {
+ if (!vendor[type]) return;
+
+ promises.push(
+ copyFilesTo(vendor[type], modulePathRoot, join(mediaVendorPath, vendorName), type),
+ );
+ });
+ }
+
+ // Copy the license if existsSync
+ if (options.settings.vendors[packageName].licenseFilename
+ && await existsSync(`${join(RootPath, `node_modules/${packageName}`)}/${options.settings.vendors[packageName].licenseFilename}`)
+ ) {
+ const dest = join(mediaVendorPath, vendorName);
+ await copy(
+ `${join(RootPath, `node_modules/${packageName}`)}/${options.settings.vendors[packageName].licenseFilename}`,
+ `${dest}/${options.settings.vendors[packageName].licenseFilename}`,
+ );
+ }
+
+ await Promise.all(promises);
+
+ // Add provided Assets to a registry, if any
+ if (vendor.provideAssets && vendor.provideAssets.length) {
+ vendor.provideAssets.forEach((assetInfo) => {
+ const registryItemBase = {
+ package: packageName,
+ name: assetInfo.name || vendorName,
+ version: moduleOptions.version,
+ type: assetInfo.type,
+ };
+
+ const registryItem = Object.assign(assetInfo, registryItemBase);
+
+ // Update path to file
+ if (assetInfo.uri && (assetInfo.type === 'script' || assetInfo.type === 'style' || assetInfo.type === 'webcomponent')) {
+ let itemPath = assetInfo.uri;
+
+ // Check for external path
+ if (itemPath.indexOf('http://') !== 0 && itemPath.indexOf('https://') !== 0 && itemPath.indexOf('//') !== 0) {
+ itemPath = `vendor/${vendorName}/${itemPath}`;
+ }
+
+ registryItem.uri = itemPath;
+ }
+
+ registry.assets.push(registryItem);
+ });
+ }
+
+ // eslint-disable-next-line no-console
+ console.log(`${packageName} was updated.`);
+};
+
+/**
+ * Main method that will copy all vendor files according to Joomla's specs
+ *
+ * @param options The options from setting.json
+ *
+ * @returns {Promise}
+ */
+module.exports.localisePackages = async (options) => {
+ const mediaVendorPath = join(RootPath, 'media/vendor');
+ const registry = {
+ $schema: 'https://developer.joomla.org/schemas/json-schema/web_assets.json',
+ name: options.name,
+ version: options.version,
+ description: options.description,
+ license: options.license,
+ assets: [],
+ };
+ const promises = [];
+
+ if (!await existsSync(mediaVendorPath)) {
+ await mkdir(mediaVendorPath, { recursive: true });
+ }
+
+ // Loop to get some text for the packgage.json
+ // eslint-disable-next-line guard-for-in, no-restricted-syntax
+ for (const packageName in options.settings.vendors) {
+ const vendor = options.settings.vendors[packageName];
+
+ promises.push(resolvePackage(vendor, packageName, mediaVendorPath, options, registry));
+ }
+
+ await Promise.all(promises);
+
+ // Write assets registry
+ await writeFile(
+ join(mediaVendorPath, 'joomla.asset.json'),
+ JSON.stringify(registry, null, 2),
+ { encoding: 'utf8' },
+ );
+};
diff --git a/build/build-modules-js/init/minify-vendor.es6.js b/build/build-modules-js/init/minify-vendor.es6.js
new file mode 100644
index 0000000000000..50ea5df481f36
--- /dev/null
+++ b/build/build-modules-js/init/minify-vendor.es6.js
@@ -0,0 +1,103 @@
+const { lstat, readFile, writeFile } = require('fs-extra');
+const { sep } = require('path');
+const recursive = require('recursive-readdir');
+const { minify } = require('terser');
+
+const RootPath = process.cwd();
+
+const folders = [
+ 'media/vendor/accessibility/js',
+ 'media/vendor/chosen/js',
+ 'media/vendor/codemirror',
+ 'media/vendor/debugbar',
+ 'media/vendor/punycode/js',
+ 'media/vendor/qrcode/js',
+ 'media/vendor/short-and-sweet/js',
+ 'media/vendor/webcomponentsjs/js',
+];
+
+let allFiles = [];
+
+const noMinified = [
+ 'media/vendor/accessibility/js/accessibility.min.js',
+ 'media/vendor/short-and-sweet/js/short-and-sweet.min.js',
+];
+
+const alreadyMinified = [
+ 'media/vendor/webcomponentsjs/js/webcomponents-ce.js',
+ 'media/vendor/webcomponentsjs/js/webcomponents-sd.js',
+ 'media/vendor/webcomponentsjs/js/webcomponents-sd-ce.js',
+ 'media/vendor/webcomponentsjs/js/webcomponents-sd-ce-pf.js',
+];
+
+/**
+ * Check if a file exists
+ *
+ * @param file
+ * @returns {Promise}
+ */
+const minifiedExists = async (file) => {
+ try {
+ return (await lstat(file)).isFile();
+ } catch (e) {
+ return false;
+ }
+};
+
+/**
+ *
+ * @param {string} file
+ *
+ * @returns {Promise}
+ */
+const minifyJS = async (file) => {
+ const needsDotJS = noMinified.includes(file.replace(`${RootPath}${sep}`, ''));
+ if (file.endsWith('.min.js') && !needsDotJS) {
+ return;
+ }
+
+ // eslint-disable-next-line no-console
+ console.log(`Processing Vendor file: ${file}`);
+
+ let minified;
+ const fileExists = await minifiedExists(file);
+ if (!fileExists) {
+ return;
+ }
+
+ const content = await readFile(file, { encoding: 'utf8' });
+
+ const isMinified = alreadyMinified.includes(file.replace(`${RootPath}${sep}`, ''));
+ if (isMinified || needsDotJS) {
+ minified = content;
+ } else {
+ minified = (await minify(content, { sourceMap: false, format: { comments: false } })).code;
+ }
+
+ const newFile = needsDotJS ? file.replace('.min.js', '.js') : file.replace('.js', '.min.js');
+ // Write the file
+ await writeFile(
+ newFile,
+ minified,
+ { encoding: 'utf8' },
+ );
+};
+
+/**
+ * Method that will minify a set of vendor javascript files
+ *
+ * @returns {Promise}
+ */
+module.exports.minifyVendor = async () => {
+ // return;
+ const folderPromises = [];
+ const filesPromises = [];
+
+ folders.map((folder) => folderPromises.push(recursive(folder, ['!*.+(js)'])));
+
+ const computedFiles = await Promise.all(folderPromises);
+ allFiles = [...allFiles, ...[].concat(...computedFiles)];
+ allFiles.map((file) => filesPromises.push(minifyJS(file)));
+
+ return Promise.all(filesPromises);
+};
diff --git a/build/build-modules-js/init/patches.es6.js b/build/build-modules-js/init/patches.es6.js
new file mode 100644
index 0000000000000..4845f42185fb6
--- /dev/null
+++ b/build/build-modules-js/init/patches.es6.js
@@ -0,0 +1,33 @@
+const { readFile, writeFile } = require('fs-extra');
+const { join } = require('path');
+
+const RootPath = process.cwd();
+
+/**
+ * Main method that will patch files...
+ *
+ * @param options The options from setting.json
+ *
+ * @returns {Promise}
+ */
+module.exports.patchPackages = async (options) => {
+ const mediaVendorPath = join(RootPath, 'media/vendor');
+
+ // Joomla's hack to expose the chosen base classes so we can extend it ourselves
+ // (it was better than the many hacks we had before. But I'm still ashamed of myself).
+ let dest = join(mediaVendorPath, 'chosen');
+ const chosenPath = `${dest}/${options.settings.vendors['chosen-js'].js['chosen.jquery.js']}`;
+ let ChosenJs = await readFile(chosenPath, { encoding: 'utf8' });
+ ChosenJs = ChosenJs.replace('}).call(this);', ` document.AbstractChosen = AbstractChosen;
+ document.Chosen = Chosen;
+}).call(this);`);
+ await writeFile(chosenPath, ChosenJs, { encoding: 'utf8' });
+
+ // Append initialising code to the end of the Short-and-Sweet javascript
+ dest = join(mediaVendorPath, 'short-and-sweet');
+ const shortandsweetPath = `${dest}/${options.settings.vendors['short-and-sweet'].js['dist/short-and-sweet.min.js']}`;
+ let ShortandsweetJs = await readFile(shortandsweetPath, { encoding: 'utf8' });
+ ShortandsweetJs = ShortandsweetJs.concat('document.addEventListener(\'DOMContentLoaded\', function()'
+ + '{shortAndSweet(\'textarea.charcount\', {counterClassName: \'small text-muted\'}); });');
+ await writeFile(shortandsweetPath, ShortandsweetJs, { encoding: 'utf8' });
+};
diff --git a/build/build-modules-js/init/recreate-media.es6.js b/build/build-modules-js/init/recreate-media.es6.js
new file mode 100644
index 0000000000000..2460b0dd94ddc
--- /dev/null
+++ b/build/build-modules-js/init/recreate-media.es6.js
@@ -0,0 +1,31 @@
+const { stat, copy } = require('fs-extra');
+const { join, extname } = require('path');
+
+const RootPath = process.cwd();
+
+/**
+ * Method to recreate the basic media folder structure
+ * After execution the media folder is populated with empty js and css subdirectories
+ * images subfolders with their relative files and any other files except .js, .css
+ *
+ * @returns {Promise}
+ */
+module.exports.recreateMediaFolder = async () => {
+ // eslint-disable-next-line no-console
+ console.log('Recreating the media folder...');
+
+ const filterFunc = async (src) => {
+ const fileStat = await stat(src);
+ if (fileStat.isDirectory() && src.endsWith('core.es6')) {
+ return false;
+ }
+
+ if (fileStat.isFile() && (extname(src) === '.js' || extname(src) === '.css')) {
+ return false;
+ }
+
+ return true;
+ };
+
+ await copy(join(RootPath, 'build/media_source'), join(RootPath, 'media'), { filter: filterFunc });
+};
diff --git a/build/build-modules-js/javascript/babel-transform.es6.js b/build/build-modules-js/javascript/babel-transform.es6.js
index eb3ab839eeec1..458f05162f071 100644
--- a/build/build-modules-js/javascript/babel-transform.es6.js
+++ b/build/build-modules-js/javascript/babel-transform.es6.js
@@ -1,36 +1,53 @@
+const { writeFile } = require('fs').promises;
const Babel = require('@babel/core');
-const Fs = require('fs');
const FsExtra = require('fs-extra');
-const Path = require('path');
+const { dirname } = require('path');
+const { minify } = require('terser');
+
+/**
+ * Create the minified file as well
+ *
+ * @returns {Promise}
+ * @param fileName {string}
+ * @param data {string}
+ */
+const createMinified = async (fileName, data) => {
+ const mini = await minify(data, { sourceMap: false, format: { comments: false } });
+ await writeFile(fileName, mini.code, { encoding: 'utf8' });
+};
/**
*
* @param fileContents the content of the file to be transpiled
* @param settings the settings for the transpiler
- * @param output the full pat + filename + extension of the trnspiled file
+ * @param output the full pat + filename + extension of the transpiled file
*/
-module.exports.run = (fileContents, settings, output) => {
- Babel.transform(fileContents, settings, (error, result) => {
- if (error) {
- // eslint-disable-next-line no-console
- console.error(`${error}`);
- process.exit(1);
- }
+module.exports.BabelTransform = async (fileContents, settings, output) => {
+ let transformedData;
+
+ try {
+ transformedData = await Babel.transform(fileContents, settings);
+ } catch (error) {
+ // eslint-disable-next-line no-console
+ console.error(`${error}`);
+ process.exit(1);
+ }
+
+ // Ensure the folder exists or create it
+ await FsExtra.ensureDir(dirname(output), {});
- // Ensure the folder exists or create it
- FsExtra.mkdirsSync(Path.dirname(output), {});
+ await writeFile(
+ output,
+ transformedData.code, // + os.EOL
+ { encoding: 'utf8' },
+ (fsError) => {
+ if (fsError) {
+ // eslint-disable-next-line no-console
+ console.error(`${fsError}`);
+ process.exit(1);
+ }
+ },
+ );
- Fs.writeFile(
- output,
- result.code, // + os.EOL
- { encoding: 'utf8' },
- (fsError) => {
- if (fsError) {
- // eslint-disable-next-line no-console
- console.error(`${fsError}`);
- process.exit(1);
- }
- },
- );
- });
+ await createMinified(output.replace('.js', '.min.js'), transformedData.code);
};
diff --git a/build/build-modules-js/build-bootstrap-js.es6.js b/build/build-modules-js/javascript/build-bootstrap-js.es6.js
similarity index 76%
rename from build/build-modules-js/build-bootstrap-js.es6.js
rename to build/build-modules-js/javascript/build-bootstrap-js.es6.js
index 4d074f80a79cf..b3825fdaccc0a 100644
--- a/build/build-modules-js/build-bootstrap-js.es6.js
+++ b/build/build-modules-js/javascript/build-bootstrap-js.es6.js
@@ -1,5 +1,5 @@
const {
- readdir, readFile, rename, writeFile, unlink,
+ readdir, readFile, writeFile, unlink,
} = require('fs').promises;
const { resolve } = require('path');
const { minify } = require('terser');
@@ -13,11 +13,13 @@ const tasks = [];
const inputFolder = 'build/media_source/vendor/bootstrap/js';
const outputFolder = 'media/vendor/bootstrap/js';
+const getCurrentUnixTime = Math.round((new Date()).getTime() / 1000);
+
const createMinified = async (file) => {
const initial = await readFile(resolve(outputFolder, file), { encoding: 'utf8' });
- const mini = await minify(initial);
- await rename(resolve(outputFolder, file), resolve(outputFolder, `${file.split('-')[0]}.es6.js`));
- await writeFile(resolve(outputFolder, `${file.split('-')[0]}.es6.min.js`), mini.code, { encoding: 'utf8' });
+ const mini = await minify(initial.replace('./popper.js', `./popper.min.js?${getCurrentUnixTime}`).replace('./dom.js', `./dom.min.js?${getCurrentUnixTime}`), { sourceMap: false, format: { comments: false } });
+ await writeFile(resolve(outputFolder, file), initial.replace('./popper.js', `./popper.js?${getCurrentUnixTime}`).replace('./dom.js', `./dom.js?${getCurrentUnixTime}`), { encoding: 'utf8' });
+ await writeFile(resolve(outputFolder, file.replace('.js', '.min.js')), mini.code, { encoding: 'utf8' });
};
const build = async () => {
@@ -31,6 +33,21 @@ const build = async () => {
replace({
'process.env.NODE_ENV': '\'production\'',
}),
+ babel({
+ exclude: 'node_modules/core-js/**',
+ babelHelpers: 'bundled',
+ babelrc: false,
+ presets: [
+ [
+ '@babel/preset-env',
+ {
+ targets: {
+ esmodules: true,
+ },
+ },
+ ],
+ ],
+ }),
],
external: [
'./base-component.js',
@@ -67,7 +84,11 @@ const build = async () => {
format: 'es',
sourcemap: false,
dir: outputFolder,
+ chunkFileNames: '[name].js',
});
+
+ // closes the bundle
+ await bundle.close();
};
const buildLegacy = async () => {
@@ -110,11 +131,14 @@ const buildLegacy = async () => {
format: 'iife',
sourcemap: false,
name: 'Bootstrap',
- file: resolve(outputFolder, 'bootstrap.es5.js'),
+ file: resolve(outputFolder, 'bootstrap-es5.js'),
});
+
+ // closes the bundle
+ await bundle.close();
};
-(async () => {
+module.exports.bootstrapJs = async () => {
rimraf.sync(resolve(outputFolder));
try {
@@ -142,9 +166,9 @@ const buildLegacy = async () => {
try {
await buildLegacy(inputFolder, 'index.es6.js');
- const es5File = await readFile(resolve(outputFolder, 'bootstrap.es5.js'), { encoding: 'utf8' });
- const mini = await minify(es5File);
- await writeFile(resolve(outputFolder, 'bootstrap.es5.min.js'), mini.code, { encoding: 'utf8' });
+ const es5File = await readFile(resolve(outputFolder, 'bootstrap-es5.js'), { encoding: 'utf8' });
+ const mini = await minify(es5File, { sourceMap: false, format: { comments: false } });
+ await writeFile(resolve(outputFolder, 'bootstrap-es5.min.js'), mini.code, { encoding: 'utf8' });
// eslint-disable-next-line no-console
console.log('Legacy done! ✅');
} catch (error) {
@@ -152,4 +176,4 @@ const buildLegacy = async () => {
console.error(error);
process.exit(1);
}
-})();
+};
diff --git a/build/build-modules-js/javascript/build-com_media-js.es6.js b/build/build-modules-js/javascript/build-com_media-js.es6.js
new file mode 100644
index 0000000000000..6dca61fa6d29c
--- /dev/null
+++ b/build/build-modules-js/javascript/build-com_media-js.es6.js
@@ -0,0 +1,120 @@
+const { readFile, writeFile } = require('fs').promises;
+const { resolve } = require('path');
+const { minify } = require('terser');
+const rollup = require('rollup');
+const { nodeResolve } = require('@rollup/plugin-node-resolve');
+const replace = require('@rollup/plugin-replace');
+const { babel } = require('@rollup/plugin-babel');
+const VuePlugin = require('rollup-plugin-vue');
+const commonjs = require('@rollup/plugin-commonjs');
+
+const inputJS = 'administrator/components/com_media/resources/scripts/mediamanager.es6.js';
+
+const createMinified = async (file, contents) => {
+ const mini = await minify(contents, { sourceMap: false, format: { comments: false } });
+ await writeFile(file, mini.code, { encoding: 'utf8' });
+};
+const buildLegacy = async (file) => {
+ // eslint-disable-next-line no-console
+ console.log('Building Legacy Media Manager...');
+
+ const bundle = await rollup.rollup({
+ input: file,
+ plugins: [
+ nodeResolve(),
+ commonjs(),
+ babel({
+ exclude: 'node_modules/core-js/**',
+ babelHelpers: 'bundled',
+ babelrc: false,
+ presets: [
+ [
+ '@babel/preset-env',
+ {
+ corejs: '3.8',
+ useBuiltIns: 'usage',
+ targets: {
+ ie: '11',
+ },
+ loose: true,
+ bugfixes: true,
+ modules: false,
+ ignoreBrowserslistConfig: true,
+ },
+ ],
+ ],
+ }),
+ ],
+ external: [],
+ });
+
+ await bundle.write({
+ format: 'iife',
+ sourcemap: false,
+ name: 'JoomlaMediaManager',
+ file: 'media/com_media/js/media-manager-es5.js',
+ });
+
+ // closes the bundle
+ await bundle.close();
+
+ const contents = await readFile('media/com_media/js/media-manager-es5.js', { encoding: 'utf8' });
+ await createMinified(resolve('media/com_media/js/media-manager-es5.min.js'), contents);
+ // eslint-disable-next-line no-console
+ console.log('Legacy Media Manager ready ✅');
+};
+
+module.exports.mediaManager = async () => {
+ // eslint-disable-next-line no-console
+ console.log('Building Media Manager ES Module...');
+
+ const bundle = await rollup.rollup({
+ input: resolve(inputJS),
+ plugins: [
+ VuePlugin({
+ target: 'browser',
+ css: false,
+ compileTemplate: true,
+ template: {
+ isProduction: true,
+ },
+ }),
+ nodeResolve(),
+ replace({
+ 'process.env.NODE_ENV': JSON.stringify('production'),
+ }),
+ babel({
+ exclude: 'node_modules/core-js/**',
+ babelHelpers: 'bundled',
+ babelrc: false,
+ presets: [
+ [
+ '@babel/preset-env',
+ {
+ targets: {
+ esmodules: true,
+ },
+ loose: true,
+ bugfixes: false,
+ ignoreBrowserslistConfig: true,
+ },
+ ],
+ ],
+ }),
+ ],
+ });
+
+ await bundle.write({
+ format: 'es',
+ sourcemap: false,
+ file: 'media/com_media/js/media-manager.js',
+ });
+
+ // closes the bundle
+ await bundle.close();
+ const contents = await readFile('media/com_media/js/media-manager.js', { encoding: 'utf8' });
+ await createMinified(resolve('media/com_media/js/media-manager.min.js'), contents);
+ // eslint-disable-next-line no-console
+ console.log('ES2017 Media Manager ready ✅');
+ await buildLegacy(resolve('media/com_media/js/media-manager.js'));
+};
diff --git a/build/build-modules-js/javascript/compile-es6.es6.js b/build/build-modules-js/javascript/compile-es6.es6.js
index 05d03ae0c3565..24c8d44126431 100644
--- a/build/build-modules-js/javascript/compile-es6.es6.js
+++ b/build/build-modules-js/javascript/compile-es6.es6.js
@@ -1,11 +1,25 @@
-const Fs = require('fs');
-const Path = require('path');
-const FsExtra = require('fs-extra');
-const Babel = require('./babel-transform.es6.js');
+const { lstat, readdir, readFile } = require('fs').promises;
+const { dirname, sep } = require('path');
+const { ensureDir } = require('fs-extra');
+const { BabelTransform } = require('./babel-transform.es6.js');
const headerText = `PLEASE DO NOT MODIFY THIS FILE. WORK ON THE ES6 VERSION.
OTHERWISE YOUR CHANGES WILL BE REPLACED ON THE NEXT BUILD.`;
+/**
+ * Check if a file exists
+ *
+ * @param file
+ * @returns {Promise}
+ */
+const folderExists = async (folder) => {
+ try {
+ return (await lstat(folder)).isDirectory();
+ } catch (e) {
+ return false;
+ }
+};
+
// Predefine some settings
const settings = [
{
@@ -23,21 +37,6 @@ const settings = [
],
comments: true,
},
- {
- presets: [
- ['@babel/preset-env', {
- targets: {
- browsers: ['ie 11'],
- },
- modules: false,
- }],
- ['minify', { builtIns: false }],
- ],
- plugins: [
- ['@babel/plugin-transform-classes'],
- ],
- comments: false,
- },
{
presets: [
['@babel/preset-env', {
@@ -52,19 +51,6 @@ const settings = [
],
comments: true,
},
- {
- presets: [
- ['@babel/preset-env', {
- targets: {
- browsers: ['> 5%', 'not ie 11'],
- },
- modules: false,
- }],
- ['minify', { builtIns: false }],
- ],
- plugins: [],
- comments: false,
- },
];
/**
@@ -72,48 +58,44 @@ const settings = [
*
* @param file the full path to the file + filename + extension
*/
-module.exports.compileFile = (file) => {
- Promise.resolve()
- .then(() => {
- const filePath = file.slice(0, -7);
+module.exports.handleESMFile = async (file) => {
+ const filePath = file.slice(0, -7);
+ const newPath = filePath.replace(`${sep}build${sep}media_source${sep}`, `${sep}media${sep}`);
+ const outputFiles = [
+ `${newPath}.js`,
+ `${newPath}.es6.js`,
+ ];
- const outputFiles = [
- `${filePath.replace('/build/media_source/', '/media/').replace('\\build\\media_source\\', '\\media\\')}.js`,
- `${filePath.replace('/build/media_source/', '/media/').replace('\\build\\media_source\\', '\\media\\')}.min.js`,
- `${filePath.replace('/build/media_source/', '/media/').replace('\\build\\media_source\\', '\\media\\')}.es6.js`,
- `${filePath.replace('/build/media_source/', '/media/').replace('\\build\\media_source\\', '\\media\\')}.es6.min.js`,
- ];
+ // Ensure that the directories exist or create them
+ ensureDir(dirname(file.replace(`${sep}build${sep}media_source${sep}`, `${sep}media${sep}`)));
- // Ensure that the directories exist or create them
- FsExtra.mkdirsSync(Path.dirname(file).replace('/build/media_source/', '/media/').replace('\\build\\media_source\\', '\\media\\'), {});
+ // Get the contents of the ES-XXXX file
+ let es6File = await readFile(file, { encoding: 'utf8' });
+ const es6FileAsync = [];
+ const es6Subdir = file.replace('es6.js', 'es6');
+ const coreWeirdFolderExists = await folderExists(es6Subdir);
- // Get the contents of the ES-XXXX file
- let es6File = Fs.readFileSync(file, 'utf8');
- const es6Subdir = file.replace('es6.js', 'es6');
+ if (coreWeirdFolderExists) {
+ const allCorefilesPromises = [];
+ const concatenateFileContents = async (es6SubFile) => {
+ es6FileAsync.push(await readFile(`${es6Subdir}/${es6SubFile}`, { encoding: 'utf8' }));
+ };
+ const es6SubFiles = await readdir(es6Subdir);
+ es6SubFiles.sort();
+ es6SubFiles.map((es6SubFile) => allCorefilesPromises.push(concatenateFileContents(es6SubFile)));
+ await Promise.all(allCorefilesPromises);
+ }
- if (Fs.existsSync(es6Subdir)) {
- const stats = Fs.lstatSync(es6Subdir);
+ if (es6FileAsync.length) {
+ es6File += es6FileAsync.join('');
+ }
- if (stats.isDirectory()) {
- const es6SubFiles = Fs.readdirSync(es6Subdir);
- es6SubFiles.sort();
- es6SubFiles.forEach((es6SubFile) => {
- es6File += Fs.readFileSync(`${es6Subdir}/${es6SubFile}`, 'utf8');
- });
- }
- }
-
- settings.forEach((setting, index) => {
- // eslint-disable-next-line no-console
- console.error(`Transpiling ES6 file: ${file}`);
- Babel.run(es6File, setting, outputFiles[index]);
- });
- })
-
- // Handle errors
- .catch((error) => {
+ const jobs = [];
+ settings.forEach((setting, index) => {
// eslint-disable-next-line no-console
- console.error(`${error}`);
- process.exit(1);
- });
+ console.error(`Transpiling ES6 file: ${file}`);
+ jobs.push(BabelTransform(es6File, setting, outputFiles[index]));
+ });
+
+ return Promise.all(jobs);
};
diff --git a/build/build-modules-js/javascript/compile-w-c.es6.js b/build/build-modules-js/javascript/compile-w-c.es6.js
index fe0c7b8d38dfd..1f1fc68726b6d 100644
--- a/build/build-modules-js/javascript/compile-w-c.es6.js
+++ b/build/build-modules-js/javascript/compile-w-c.es6.js
@@ -1,11 +1,12 @@
const Autoprefixer = require('autoprefixer');
const CssNano = require('cssnano');
const Fs = require('fs');
+const { sep } = require('path');
const Postcss = require('postcss');
const Sass = require('sass');
-const Babel = require('./babel-transform.es6.js');
+const { BabelTransform } = require('./babel-transform.es6.js');
-const createJsFiles = (inputFile, es6FileContents) => {
+const createJsFiles = async (inputFile, es6FileContents) => {
// Define some settings
const settings = [
{
@@ -18,17 +19,6 @@ const createJsFiles = (inputFile, es6FileContents) => {
],
comments: true,
},
- {
- presets: [
- ['@babel/preset-env', {
- targets: {
- browsers: ['last 1 Chrome version'],
- },
- }],
- ['minify', { builtIns: false }],
- ],
- comments: false,
- },
{
presets: [
['@babel/preset-env', {
@@ -41,36 +31,21 @@ const createJsFiles = (inputFile, es6FileContents) => {
'@babel/plugin-transform-classes',
],
comments: true,
-
- },
- {
- presets: [
-
- ['@babel/preset-env', {
- targets: {
- browsers: ['ie 11'],
- },
- }],
- ['minify', { builtIns: false }],
- ],
- plugins: [
- ['@babel/plugin-transform-classes'],
- ],
- comments: false,
-
},
];
+ const file = inputFile.replace(`${sep}build${sep}media_source${sep}`, `${sep}media${sep}`);
const outputFiles = [
- inputFile.replace('/build/media_source/', '/media/').replace('\\build\\media_source\\', '\\media\\').replace('.w-c.es6.js', '.js'),
- inputFile.replace('/build/media_source/', '/media/').replace('\\build\\media_source\\', '\\media\\').replace('.w-c.es6.js', '.min.js'),
- inputFile.replace('/build/media_source/', '/media/').replace('\\build\\media_source\\', '\\media\\').replace('.w-c.es6.js', '-es5.js'),
- inputFile.replace('/build/media_source/', '/media/').replace('\\build\\media_source\\', '\\media\\').replace('.w-c.es6.js', '-es5.min.js'),
+ file.replace('.w-c.es6.js', '.js'),
+ file.replace('.w-c.es6.js', '-es5.js'),
];
+ const tasks = [];
settings.forEach((setting, index) => {
- Babel.run(es6FileContents, setting, outputFiles[index]);
+ tasks.push(BabelTransform(es6FileContents, setting, outputFiles[index]));
});
+
+ await Promise.all(tasks);
};
/**
@@ -78,7 +53,7 @@ const createJsFiles = (inputFile, es6FileContents) => {
*
* @param file The full path to the file + filename + extension
*/
-module.exports.compile = (inputFile) => {
+module.exports.handleWCFile = async (inputFile) => {
Promise.resolve()
.then(() => {
// Get the contents of the ES-XXXX file
diff --git a/build/build-modules-js/javascript/handle-es5.es6.js b/build/build-modules-js/javascript/handle-es5.es6.js
new file mode 100644
index 0000000000000..89050e64c2dfc
--- /dev/null
+++ b/build/build-modules-js/javascript/handle-es5.es6.js
@@ -0,0 +1,18 @@
+const { readFile, writeFile } = require('fs').promises;
+const FsExtra = require('fs-extra');
+const { dirname, sep } = require('path');
+const { minify } = require('terser');
+
+module.exports.handleES5File = async (file) => {
+ if (file.match(/\.es5\.js$/)) {
+ // ES5 file, we will copy the file and then minify it in place
+ // Ensure that the directories exist or create them
+ await FsExtra.ensureDir(dirname(file).replace(`${sep}build${sep}media_source${sep}`, `${sep}media${sep}`));
+ await FsExtra.copy(file, file.replace(`${sep}build${sep}media_source${sep}`, `${sep}media${sep}`).replace('.es5.js', '.js'));
+ const fileContent = await readFile(file, { encoding: 'utf8' });
+ const content = await minify(fileContent, { sourceMap: false, format: { comments: false } });
+ await writeFile(file.replace(`${sep}build${sep}media_source${sep}`, `${sep}media${sep}`).replace('.es5.js', '.min.js'), content.code, { encoding: 'utf8' });
+ // eslint-disable-next-line no-console
+ console.log(`Es5 file copied/minified: ${file}`);
+ }
+};
diff --git a/build/build-modules-js/javascript/handle-file.es6.js b/build/build-modules-js/javascript/handle-file.es6.js
deleted file mode 100644
index 01e59b7d86579..0000000000000
--- a/build/build-modules-js/javascript/handle-file.es6.js
+++ /dev/null
@@ -1,24 +0,0 @@
-const Fs = require('fs');
-const FsExtra = require('fs-extra');
-const Path = require('path');
-const UglifyJS = require('uglify-es');
-const TranspileJs = require('./compile-es6.es6.js');
-const TranspileWc = require('./compile-w-c.es6.js');
-
-module.exports.run = (file) => {
- if (file.match(/\.js/) && file.match(/\.es6\.js/) && !file.match(/\.w-c\.es6\.js/)) {
- // ES6 file so we need to transpile it
- TranspileJs.compileFile(file);
- } else if (file.match(/\.js/) && file.match(/\.es5\.js/)) {
- // ES5 file, we will copy the file and then minify it in place
- // Ensure that the directories exist or create them
- FsExtra.mkdirsSync(Path.dirname(file).replace('/build/media_source/', '/media/').replace('\\build\\media_source\\', '\\media\\'), {});
- Fs.copyFileSync(file, file.replace('/build/media_source/', '/media/').replace('\\build\\media_source\\', '\\media\\').replace('.es5.js', '.js'));
- Fs.writeFileSync(file.replace('/build/media_source/', '/media/').replace('\\build\\media_source\\', '\\media\\').replace('.es5.js', '.min.js'), UglifyJS.minify(Fs.readFileSync(file, 'utf8')).code, { encoding: 'utf8' });
- // eslint-disable-next-line no-console
- console.log(`Es5 file copied/minified: ${file}`);
- } else if (file.match(/\.js/) && file.match(/\.w-c\.es6\.js/)) {
- // Web Component, so we need to transpile it
- TranspileWc.compile(file);
- }
-};
diff --git a/build/build-modules-js/javascript/minify-vendor.es6.js b/build/build-modules-js/javascript/minify-vendor.es6.js
deleted file mode 100644
index 0d54a05642dcf..0000000000000
--- a/build/build-modules-js/javascript/minify-vendor.es6.js
+++ /dev/null
@@ -1,54 +0,0 @@
-const Fs = require('fs');
-const Path = require('path');
-const UglifyJS = require('uglify-es');
-const walkSync = require('walk-sync');
-
-const RootPath = process.cwd();
-
-/**
- * Method that will minify a set of vendor javascript files
- */
-module.exports.compile = () => {
- Promise.resolve()
- .then(() => {
- const folders = [
- Path.join(RootPath, 'media/vendor/codemirror'),
- Path.join(RootPath, 'media/vendor/punycode/js'),
- Path.join(RootPath, 'media/vendor/webcomponentsjs'),
- ];
-
- // Loop to get some text for the package.json
- folders.forEach((folder) => {
- const files = walkSync(folder, {
- globs: ['**/*.js'],
- includeBasePath: true,
- ignore: [],
- directories: false,
- });
-
- if (files.length) {
- files.forEach(
- (file) => {
- if (file.match(/\.js/) && !file.match(/LICENSE\.md/)) {
- // eslint-disable-next-line no-console
- console.log(`Processing ES5 file: ${file}`);
- // Write the file
- Fs.writeFileSync(
- file.replace('.js', '.min.js'),
- UglifyJS.minify(Fs.readFileSync(file, 'utf8')).code,
- { encoding: 'utf8' },
- );
- }
- },
- );
- }
- });
- })
-
- // Handle errors
- .catch((error) => {
- // eslint-disable-next-line no-console
- console.error(`${error}`);
- process.exit(1);
- });
-};
diff --git a/build/build-modules-js/settings.json b/build/build-modules-js/settings.json
index 51e58b3cdcd6e..6d9a6a971dd51 100644
--- a/build/build-modules-js/settings.json
+++ b/build/build-modules-js/settings.json
@@ -23,7 +23,10 @@
{
"name": "awesomplete",
"type": "script",
- "uri": "awesomplete.min.js"
+ "uri": "awesomplete.min.js",
+ "attributes": {
+ "defer": true
+ }
},
{
"name": "awesomplete",
@@ -69,6 +72,128 @@
"dependencies": [
"bootstrap.css"
]
+ },
+ {
+ "name": "bootstrap.es5",
+ "type": "script",
+ "uri": "bootstrap-es5.min.js",
+ "dependencies": [
+ "core"
+ ],
+ "attributes": {
+ "nomodule": true,
+ "defer": true
+ }
+ },
+ {
+ "name": "bootstrap.alert",
+ "type": "script",
+ "uri": "alert.min.js",
+ "dependencies": [
+ "bootstrap.es5"
+ ],
+ "attributes": {
+ "type": "module"
+ }
+ },
+ {
+ "name": "bootstrap.button",
+ "type": "script",
+ "uri": "button.min.js",
+ "dependencies": [
+ "bootstrap.es5"
+ ],
+ "attributes": {
+ "type": "module"
+ }
+ },
+ {
+ "name": "bootstrap.carousel",
+ "type": "script",
+ "uri": "carousel.min.js",
+ "dependencies": [
+ "bootstrap.es5"
+ ],
+ "attributes": {
+ "type": "module"
+ }
+ },
+ {
+ "name": "bootstrap.collapse",
+ "type": "script",
+ "uri": "collapse.min.js",
+ "dependencies": [
+ "bootstrap.es5"
+ ],
+ "attributes": {
+ "type": "module"
+ }
+ },
+ {
+ "name": "bootstrap.dropdown",
+ "type": "script",
+ "uri": "dropdown.min.js",
+ "dependencies": [
+ "bootstrap.es5"
+ ],
+ "attributes": {
+ "type": "module"
+ }
+ },
+ {
+ "name": "bootstrap.modal",
+ "type": "script",
+ "uri": "modal.min.js",
+ "dependencies": [
+ "bootstrap.es5"
+ ],
+ "attributes": {
+ "type": "module"
+ }
+ },
+ {
+ "name": "bootstrap.popover",
+ "type": "script",
+ "uri": "popover.min.js",
+ "dependencies": [
+ "bootstrap.es5"
+ ],
+ "attributes": {
+ "type": "module"
+ }
+ },
+ {
+ "name": "bootstrap.scrollspy",
+ "type": "script",
+ "uri": "scrollspy.min.js",
+ "dependencies": [
+ "bootstrap.es5"
+ ],
+ "attributes": {
+ "type": "module"
+ }
+ },
+ {
+ "name": "bootstrap.tab",
+ "type": "script",
+ "uri": "tab.min.js",
+ "dependencies": [
+ "bootstrap.es5"
+ ],
+ "attributes": {
+ "type": "module"
+ }
+ },
+ {
+ "name": "bootstrap.toast",
+ "type": "script",
+ "uri": "toast.min.js",
+ "dependencies": [
+ "bootstrap.es5"
+ ],
+ "attributes": {
+ "type": "module"
+ }
}
],
"dependencies": [],
@@ -120,6 +245,10 @@
"public/assets/styles/choices.css": "css/choices.css",
"public/assets/styles/choices.min.css": "css/choices.min.css"
},
+ "filesExtra": {
+ "src/styles/base.scss": "scss/base.scss",
+ "src/styles/choices.scss": "scss/choices.scss"
+ },
"provideAssets": [
{
"name": "choicesjs",
@@ -129,7 +258,10 @@
{
"name": "choicesjs",
"type": "script",
- "uri": "choices.min.js"
+ "uri": "choices.min.js",
+ "attributes": {
+ "defer": true
+ }
},
{
"name": "choicesjs",
@@ -306,26 +438,58 @@
{
"name": "webcomponent.joomla-alert",
"type": "style",
- "uri": "joomla-alert.min.css",
- "webcomponent": true
+ "uri": "joomla-alert.min.css"
},
{
- "name": "webcomponent.joomla-tab",
- "type": "style",
- "uri": "joomla-tab.min.css",
- "webcomponent": true
+ "name": "webcomponent.joomla-alert-legacy",
+ "type": "script",
+ "uri": "joomla-alert-es5.min.js",
+ "attributes": {
+ "nomodule": true,
+ "defer": true
+ },
+ "dependencies": [
+ "wcpolyfill"
+ ]
},
{
"name": "webcomponent.joomla-alert",
"type": "script",
"uri": "joomla-alert.min.js",
- "webcomponent": true
+ "attributes": {
+ "type": "module"
+ },
+ "dependencies": [
+ "webcomponent.joomla-alert-legacy"
+ ]
+ },
+ {
+ "name": "webcomponent.joomla-tab",
+ "type": "style",
+ "uri": "joomla-tab.min.css"
+ },
+ {
+ "name": "webcomponent.joomla-tab-legacy",
+ "type": "script",
+ "uri": "joomla-tab-es5.min.js",
+ "attributes": {
+ "nomodule": true,
+ "defer": true
+ },
+ "dependencies": [
+ "wcpolyfill"
+ ]
},
{
"name": "webcomponent.joomla-tab",
"type": "script",
"uri": "joomla-tab.min.js",
- "webcomponent": true
+ "attributes": {
+ "type": "module"
+ },
+ "dependencies": [
+ "webcomponent.joomla-tab-legacy"
+ ]
}
],
"dependencies": [],
@@ -366,7 +530,10 @@
{
"name": "punycode",
"type": "script",
- "uri": "punycode.js"
+ "uri": "punycode.js",
+ "attributes": {
+ "defer": true
+ }
}
],
"dependencies": [],
@@ -432,7 +599,19 @@
"bundles/webcomponents-sd-ce-pf.js": "js/webcomponents-sd-ce-pf.js"
},
"dependencies": [],
- "licenseFilename": "LICENSE.md"
+ "licenseFilename": "LICENSE.md",
+ "provideAssets": [
+ {
+ "name": "wcpolyfill",
+ "type": "script",
+ "uri": "webcomponents-sd-ce-pf.js",
+ "attributes": {
+ "nomodule": true,
+ "defer": true
+ },
+ "dependencies": ["core"]
+ }
+ ]
},
"chosen-js": {
"name": "chosen",
@@ -490,6 +669,7 @@
"licenseFilename": "LICENSE",
"js": {
"dist/metismenujs.js": "js/metismenujs.js",
+ "dist/metismenujs.js.map": "js/metismenujs.js.map",
"dist/metismenujs.min.js": "js/metismenujs.min.js",
"dist/metismenujs.min.js.map": "js/metismenujs.min.js.map"
},
@@ -583,7 +763,6 @@
},
"errorPages": {
"incomplete": {
- "phpVersionReplaceble": "",
"title": "Joomla: Environment Setup Incomplete",
"header": "Environment Setup Incomplete",
"text": "It looks like you are trying to run Joomla! from our git repository. To do so requires you complete a couple of extra steps first.",
@@ -592,13 +771,28 @@
"destFile": "/templates/system/build_incomplete.html"
},
"unsupported": {
- "phpVersionReplaceble": "data-php-version=\"{{PHP_VERSION}}\"",
"title": "Joomla: unsupported PHP version",
"header": "Sorry, your PHP version is not supported",
- "text": "Your host needs to use PHP version {{PHP_VERSION}} or newer to run this version of Joomla!",
+ "text": "Your host needs to use PHP version {{phpversion}} or newer to run this version of Joomla!",
"link": "J4.x:Unsupported_PHP_Version",
"linkText": "Help me resolve this",
"destFile": "/templates/system/incompatible.html"
+ },
+ "noxml": {
+ "title": "Joomla: Missing PHP-XML library",
+ "header": "Sorry, your PHP is missing a vital library",
+ "text": "Your host needs to use PHP with support for the XML library to run this version of Joomla!",
+ "link": "J4.x:Missing_XML_Library",
+ "linkText": "Help me resolve this",
+ "destFile": "/media/system/html/noxml.html"
+ },
+ "fatal": {
+ "title": "An Error Occurred: {{statusText}}",
+ "header": "Sorry, there was a problem we could not recover from.",
+ "text": "The server returned a \"{{statusCode_statusText}}\"",
+ "link": "J4.x:FatalError",
+ "linkText": "Help me resolve this",
+ "destFile": "/templates/system/fatal-error.html"
}
}
}
diff --git a/build/build-modules-js/stylesheets/handle-css.es6.js b/build/build-modules-js/stylesheets/handle-css.es6.js
new file mode 100644
index 0000000000000..d15d49bf63329
--- /dev/null
+++ b/build/build-modules-js/stylesheets/handle-css.es6.js
@@ -0,0 +1,32 @@
+const {
+ copy, readFile, writeFile, ensureDir,
+} = require('fs-extra');
+const { dirname, sep } = require('path');
+const Postcss = require('postcss');
+const Autoprefixer = require('autoprefixer');
+const CssNano = require('cssnano');
+
+module.exports.handleCssFile = async (file) => {
+ const outputFile = file.replace(`${sep}build${sep}media_source${sep}`, `${sep}media${sep}`);
+ try {
+ // CSS file, we will copy the file and then minify it in place
+ // Ensure that the directories exist or create them
+ await ensureDir(dirname(outputFile), { recursive: true, mode: 0o2644 });
+
+ if (file !== outputFile) {
+ await copy(file, outputFile, { overwrite: true });
+ }
+
+ const content = await readFile(file, { encoding: 'utf8' });
+ const cssMin = await Postcss([Autoprefixer, CssNano]).process(content, { from: undefined });
+
+ // Ensure the folder exists or create it
+ await writeFile(outputFile.replace('.css', '.min.css'), cssMin.css.toString(), { encoding: 'utf8', mode: 0o2644 });
+
+ // eslint-disable-next-line no-console
+ console.log(`CSS file copied/minified: ${file}`);
+ } catch (err) {
+ // eslint-disable-next-line no-console
+ console.log(err);
+ }
+};
diff --git a/build/build-modules-js/stylesheets/handle-scss.es6.js b/build/build-modules-js/stylesheets/handle-scss.es6.js
new file mode 100644
index 0000000000000..13274340191d7
--- /dev/null
+++ b/build/build-modules-js/stylesheets/handle-scss.es6.js
@@ -0,0 +1,47 @@
+const Autoprefixer = require('autoprefixer');
+const CssNano = require('cssnano');
+const { writeFile } = require('fs').promises;
+const { ensureDir } = require('fs-extra');
+const { dirname, sep } = require('path');
+const Postcss = require('postcss');
+const Sass = require('sass');
+
+module.exports.handleScssFile = async (file) => {
+ const cssFile = file.replace(`${sep}scss${sep}`, `${sep}css${sep}`)
+ .replace(`${sep}build${sep}media_source${sep}`, `${sep}media${sep}`)
+ .replace('.scss', '.css');
+
+ let compiled;
+ try {
+ compiled = Sass.renderSync({ file });
+ } catch (error) {
+ // eslint-disable-next-line no-console
+ console.error(error.formatted);
+ process.exit(1);
+ }
+
+ // Auto prefixing
+ const cleaner = Postcss([Autoprefixer()]);
+ const res = await cleaner.process(compiled.css.toString(), { from: undefined });
+
+ // Ensure the folder exists or create it
+ await ensureDir(dirname(cssFile), {});
+ await writeFile(
+ cssFile,
+ res.css,
+ { encoding: 'utf8', mode: 0o2644 },
+ );
+
+ const cssMin = await Postcss([CssNano]).process(res.css, { from: undefined });
+
+ // Ensure the folder exists or create it
+ await ensureDir(dirname(cssFile.replace('.css', '.min.css')), {});
+ await writeFile(
+ cssFile.replace('.css', '.min.css'),
+ cssMin.css,
+ { encoding: 'utf8', mode: 0o2644 },
+ );
+
+ // eslint-disable-next-line no-console
+ console.log(`SCSS File compiled: ${cssFile}`);
+};
diff --git a/build/build-modules-js/stylesheets/scss-transform.es6.js b/build/build-modules-js/stylesheets/scss-transform.es6.js
index 0d868ddc283f1..04e1317e4bd14 100644
--- a/build/build-modules-js/stylesheets/scss-transform.es6.js
+++ b/build/build-modules-js/stylesheets/scss-transform.es6.js
@@ -1,15 +1,14 @@
const Autoprefixer = require('autoprefixer');
const CssNano = require('cssnano');
-const Fs = require('fs');
+const Fs = require('fs').promises;
const FsExtra = require('fs-extra');
-const Path = require('path');
+const { dirname, sep } = require('path');
const Postcss = require('postcss');
const Sass = require('sass');
-module.exports.compile = (file) => {
- const cssFile = file.replace('/scss/', '/css/').replace('\\scss\\', '\\css\\')
- .replace('.scss', '.css').replace('/build/media_source/', '/media/')
- .replace('\\build\\media_source\\', '\\media\\');
+module.exports.compile = async (file) => {
+ const cssFile = file.replace(`${sep}scss${sep}`, `${sep}css${sep}`)
+ .replace('.scss', '.css').replace(`${sep}build${sep}media_source${sep}`, `${sep}media${sep}`);
let compiled;
try {
@@ -20,34 +19,34 @@ module.exports.compile = (file) => {
process.exit(1);
}
+ // forked.on('message', async (msg) => {
+ // console.log('Message from child', msg);
+
// Auto prefixing
- const cleaner = Postcss(
- [
- Autoprefixer(),
- ],
+ const cleaner = Postcss([Autoprefixer()]);
+ const res = await cleaner.process(compiled.css.toString(), { from: undefined });
+
+ // Ensure the folder exists or create it
+ await FsExtra.mkdirs(dirname(cssFile), {});
+ await Fs.writeFile(
+ cssFile,
+ res.css.toString(),
+ { encoding: 'utf8', mode: 0o2644 },
);
- cleaner.process(compiled.css.toString(), { from: undefined })
- .then((res) => {
- // Ensure the folder exists or create it
- FsExtra.mkdirsSync(Path.dirname(cssFile), {});
-
- Fs.writeFileSync(
- cssFile,
- res.css.toString(),
- { encoding: 'utf8', mode: 0o2644 },
- );
-
- Postcss([CssNano]).process(res.css.toString(), { from: undefined }).then((cssMin) => {
- // Ensure the folder exists or create it
- FsExtra.mkdirsSync(Path.dirname(cssFile.replace('.css', '.min.css')), {});
- Fs.writeFileSync(
- cssFile.replace('.css', '.min.css'),
- cssMin.css.toString(),
- { encoding: 'utf8', mode: 0o2644 },
- );
-
- // eslint-disable-next-line no-console
- console.log(`SCSS File compiled: ${cssFile}`);
- });
- });
+
+ const cssMin = await Postcss([CssNano]).process(res.css.toString(), { from: undefined });
+
+ // Ensure the folder exists or create it
+ FsExtra.mkdirs(dirname(cssFile.replace('.css', '.min.css')), {});
+ await Fs.writeFile(
+ cssFile.replace('.css', '.min.css'),
+ cssMin.css.toString(),
+ { encoding: 'utf8', mode: 0o2644 },
+ );
+
+ // eslint-disable-next-line no-console
+ console.log(`SCSS File compiled: ${cssFile}`);
+ // });
+
+ // forked.send({ file });
};
diff --git a/build/build-modules-js/watch.es6.js b/build/build-modules-js/watch.es6.js
index 2c5b4cf2c3c30..4dcc3d634a6ca 100644
--- a/build/build-modules-js/watch.es6.js
+++ b/build/build-modules-js/watch.es6.js
@@ -1,6 +1,8 @@
const watch = require('watch');
-const Path = require('path');
-const HandleJsFile = require('./javascript/handle-file.es6.js');
+const { join, extname } = require('path');
+const { handleWCFile } = require('./javascript/compile-w-c.es6.js');
+const { handleESMFile } = require('./javascript/compile-es6.es6.js');
+const { handleES5File } = require('./javascript/handle-es5.es6.js');
const RootPath = process.cwd();
@@ -15,17 +17,34 @@ const RootPath = process.cwd();
// eslint-disable-next-line max-len, no-param-reassign, no-return-assign
const debounce = (callback, time = 250, interval) => (...args) => clearTimeout(interval, interval = setTimeout(callback, time, ...args));
-module.exports.run = () => {
- watch.createMonitor(Path.join(RootPath, 'build/media_source'), (monitor) => {
+module.exports.watching = () => {
+ watch.createMonitor(join(RootPath, 'build/media_source'), (monitor) => {
monitor.on('created', (file) => {
- if (file.match(/\.js/) && (file.match(/\.es5\.js/) || file.match(/\.es6\.js/) || file.match(/\.w-c\.es6\.js/))) {
- debounce(HandleJsFile.run(file), 300);
+ if (extname(file) === '.js') {
+ if (file.match(/\.w-c\.es6\.js/)) {
+ debounce(handleWCFile(file), 300);
+ }
+ if (file.match(/\.es6\.js/)) {
+ debounce(handleESMFile(file), 300);
+ }
+ if (file.match(/\.es5\.js/)) {
+ debounce(handleES5File(file), 300);
+ }
}
+
// @todo css and scss
});
monitor.on('changed', (file) => {
- if (file.match(/\.js/) && (file.match(/\.es5\.js/) || file.match(/\.es6\.js/) || file.match(/\.w-c\.es6\.js/))) {
- debounce(HandleJsFile.run(file), 300);
+ if (extname(file) === '.js') {
+ if (file.match(/\.w-c\.es6\.js/)) {
+ debounce(handleWCFile(file), 300);
+ }
+ if (file.match(/\.es6\.js/)) {
+ debounce(handleESMFile(file), 300);
+ }
+ if (file.match(/\.es5\.js/)) {
+ debounce(handleES5File(file), 300);
+ }
}
// @todo css and scss
});
diff --git a/build/build.js b/build/build.js
index 4cf9300ba9992..3b9841eec37ac 100644
--- a/build/build.js
+++ b/build/build.js
@@ -6,35 +6,68 @@
* npm ci
*
* For dedicated tasks, please run:
- * node build.js --build-pages === will create the error pages (for incomplete repo build PHP+NPM)
- * node build.js --copy-assets === will clean the media/vendor folder and then will populate the folder from node_modules
- * node build.js --compile-js === will transpile ES6 files and also uglify the ES6,ES5 files
- * node build.js --compile-css === will compile all the scss defined files and also create a minified version of the css
- * node build.js --gzip === will create gzip files for all the minified stylesheets and scripts.'
+ * node build.js --build-pages will create the error pages (for incomplete repo build PHP+NPM)
+ * node build.js --copy-assets will clean the media/vendor folder and then will populate the folder from node_modules
+ * node build.js --compile-js will transpile ES6 files and also uglify the ES6,ES5 files
+ * node build.js --compile-css will compile all the scss defined files and also create a minified version of the css
+ * node build.js --compile-bs will compile all the Bootstrap javascript components
+ * node build.js --com-media will compile the media manager Vue application
+ * node build.js --watch-com-media will compile the media manager Vue application
+ * node build.js --gzip will create gzip files for all the minified stylesheets and scripts.
*/
// eslint-disable-next-line import/no-extraneous-dependencies
const Program = require('commander');
+const semver = require('semver');
// eslint-disable-next-line import/no-extraneous-dependencies
// Joomla Build modules
-const errorPages = require('./build-modules-js/error-pages.es6.js');
-const init = require('./build-modules-js/init.es6.js');
-const compileCSS = require('./build-modules-js/compilecss.es6.js');
-const compileJS = require('./build-modules-js/compilejs.es6.js');
-const minifyVendor = require('./build-modules-js/javascript/minify-vendor.es6.js');
-const watch = require('./build-modules-js/watch.es6.js');
-const { gzipFiles } = require('./build-modules-js/gzip-assets.es6');
+const { createErrorPages } = require('./build-modules-js/error-pages.es6.js');
+const { stylesheets } = require('./build-modules-js/compilecss.es6.js');
+const { scripts } = require('./build-modules-js/compilejs.es6.js');
+const { bootstrapJs } = require('./build-modules-js/javascript/build-bootstrap-js.es6.js');
+const { localisePackages } = require('./build-modules-js/init/localise-packages.es6.js');
+const { minifyVendor } = require('./build-modules-js/init/minify-vendor.es6.js');
+const { patchPackages } = require('./build-modules-js/init/patches.es6.js');
+const { cleanVendors } = require('./build-modules-js/init/cleanup-media.es6.js');
+const { recreateMediaFolder } = require('./build-modules-js/init/recreate-media.es6');
+const { watching } = require('./build-modules-js/watch.es6.js');
+const { mediaManager } = require('./build-modules-js/javascript/build-com_media-js.es6');
+const { compressFiles } = require('./build-modules-js/compress.es6.js');
// The settings
const options = require('../package.json');
const settings = require('./build-modules-js/settings.json');
+// Simple timer
+const timer = (name) => {
+ const start = new Date();
+ return {
+ stop: () => {
+ const end = new Date();
+ const time = end.getTime() - start.getTime();
+ console.log('Timer:', name, 'finished in', time, 'ms');
+ },
+ };
+};
+
// Merge Joomla's specific settings to the main package.json object
if ('settings' in settings) {
options.settings = settings.settings;
}
+const handleError = (err, terminateCode) => {
+ // eslint-disable-next-line no-console
+ console.error(err);
+ process.exit(terminateCode);
+};
+
+const allowedVersion = () => {
+ if (!semver.satisfies(process.version.substring(1), options.engines.node)) {
+ handleError(`Command line tools require Node Version ${options.engines.node} but found ${process.version}`, -1);
+ }
+};
+
// Initialize the CLI
Program
.version(options.version)
@@ -42,8 +75,12 @@ Program
.option('--build-pages', 'Creates the error pages for unsupported PHP version & incomplete environment')
.option('--compile-js, --compile-js path', 'Handles ES6, ES5 and web component scripts')
.option('--compile-css, --compile-css path', 'Compiles all the scss files to css')
+ .option('--compile-bs', 'Compiles all the Bootstrap component scripts.')
.option('--watch', 'Watch file changes and re-compile (ATM only works for the js in the media_source).')
+ .option('--com-media', 'Compile the Media Manager client side App.')
+ .option('--watch-com-media', 'Watch and Compile the Media Manager client side App.')
.option('--gzip', 'Compress all the minified stylesheets and scripts.')
+ .option('--prepare', 'Run all the needed tasks to initialise the repo')
.on('--help', () => {
// eslint-disable-next-line no-console
console.log(`Version: ${options.version}`);
@@ -51,61 +88,94 @@ Program
})
.parse(process.argv);
-
// Show help by default
if (!process.argv.slice(2).length) {
Program.outputHelp();
- process.exit(1);
+ handleError('', 1);
}
// Update the vendor folder
if (Program.copyAssets) {
- Promise.resolve()
- .then(init.copyAssets(options))
- .then(minifyVendor.compile(options))
-
- // Exit with success
- .then(() => process.exit(0))
-
- // Handle errors
- .catch((err) => {
- // eslint-disable-next-line no-console
- console.error(err);
- process.exit(-1);
- });
+ allowedVersion();
+ Promise.all([cleanVendors()])
+ .then(() => recreateMediaFolder())
+ .then(() => localisePackages(options))
+ .then(() => patchPackages(options))
+ .then(() => minifyVendor())
+ .then(() => {
+ process.exit(0);
+ })
+ .catch((error) => handleError(error, 1));
}
-
// Creates the error pages for unsupported PHP version & incomplete environment
if (Program.buildPages) {
- Promise.resolve()
- .then(() => {
- errorPages.run(options);
- })
- // Handle errors
- .catch((err) => {
- // eslint-disable-next-line no-console
- console.error(err);
- process.exit(-1);
- });
+ Promise.all([createErrorPages(options)])
+ .catch((err) => handleError(err, 1));
}
// Convert scss to css
if (Program.compileCss) {
- compileCSS.compile(options, Program.args[0]);
+ Promise.all([stylesheets(options, Program.args[0])])
+ .catch((err) => handleError(err, 1));
}
// Compress/transpile the javascript files
if (Program.compileJs) {
- compileJS.compileJS(options, Program.args[0]);
+ Promise.all([scripts(options, Program.args[0])])
+ .catch((err) => handleError(err, 1));
}
// Compress/transpile the javascript files
if (Program.watch) {
- watch.run();
+ watching();
+}
+
+// Gzip js/css files
+if (Program.compileBs) {
+ bootstrapJs();
}
// Gzip js/css files
if (Program.gzip) {
- gzipFiles();
+ compressFiles();
+}
+
+// Compile the media manager
+if (Program.comMedia) {
+ // false indicates "no watch"
+ mediaManager(false);
+}
+
+// Watch & Compile the media manager
+if (Program.watchComMedia) {
+ mediaManager(true);
+}
+
+// Prepare the repo for dev work
+if (Program.prepare) {
+ (async () => {
+ const bench = timer('Build');
+ try {
+ allowedVersion();
+ await cleanVendors();
+ await recreateMediaFolder();
+ await localisePackages(options);
+ await patchPackages(options);
+ await Promise.all([
+ minifyVendor(),
+ createErrorPages(options),
+ stylesheets(options, Program.args[0]),
+ scripts(options, Program.args[0]),
+ bootstrapJs(),
+ ]);
+ bench.stop();
+ } catch (err) {
+ // eslint-disable-next-line no-console
+ console.error(err);
+ process.exit(-1);
+ }
+
+ process.exit(0);
+ })();
}
diff --git a/build/media_source/com_joomlaupdate/js/default.es5.js b/build/media_source/com_joomlaupdate/js/default.es5.js
index 92324ea348e58..9b3a6b6453505 100644
--- a/build/media_source/com_joomlaupdate/js/default.es5.js
+++ b/build/media_source/com_joomlaupdate/js/default.es5.js
@@ -116,7 +116,7 @@ Joomla = window.Joomla || {};
*/
PreUpdateChecker.config = {
serverUrl: 'index.php?option=com_joomlaupdate&task=update.fetchextensioncompatibility',
- selector: '.extension-check'
+ selector: '.extension-check',
};
/**
@@ -128,7 +128,7 @@ Joomla = window.Joomla || {};
INCOMPATIBLE: 0,
COMPATIBLE: 1,
MISSING_COMPATIBILITY_TAG: 2,
- SERVER_ERROR: 3
+ SERVER_ERROR: 3,
};
/**
@@ -142,11 +142,16 @@ Joomla = window.Joomla || {};
// No point creating and loading a component stylesheet for 4 settings
$('.compatibilitytypes img').css('height', '20px');
- $('.compatibilitytypes').css('display', 'none').css('margin-left', 0);
+ [].slice.call(document.querySelectorAll('.compatibilitytypes')).forEach((el) => {
+ el.style.display = 'none';
+ el.style.marginLeft = 0;
+ });
// The currently processing line should show until it’s finished
- $('#compatibilitytype0').css('display', 'block');
- $('.compatibilitytoggle').css('float', 'right').css('cursor', 'pointer');
-
+ document.getElementById('compatibilitytype0').style.display = 'block';
+ [].slice.call(document.querySelectorAll('.compatibilitytoggle')).forEach((el) => {
+ el.style.float = 'right';
+ el.style.cursor = 'pointer';
+ });
$('.compatibilitytoggle').on('click', function(toggle, index)
{
@@ -155,11 +160,11 @@ Joomla = window.Joomla || {};
{
$(this).data('state', 'open');
$(this).html( COM_JOOMLAUPDATE_VIEW_DEFAULT_SHOW_LESS_EXTENSION_COMPATIBILITY_INFORMATION);
- compatibilitytypes.find('.exname').removeClass('span8').addClass('span4');
- compatibilitytypes.find('.extype').removeClass('span4').addClass('span2');
- compatibilitytypes.find('.upcomp').removeClass('hidden').addClass('span2');
- compatibilitytypes.find('.currcomp').removeClass('hidden').addClass('span2');
- compatibilitytypes.find('.instver').removeClass('hidden').addClass('span2');
+ compatibilitytypes.find('.exname').removeClass('col-md-8').addClass('col-md-4');
+ compatibilitytypes.find('.extype').removeClass('col-md-4').addClass('col-md-2');
+ compatibilitytypes.find('.upcomp').removeClass('hidden').addClass('col-md-2');
+ compatibilitytypes.find('.currcomp').removeClass('hidden').addClass('col-md-2');
+ compatibilitytypes.find('.instver').removeClass('hidden').addClass('col-md-2');
if (PreUpdateChecker.showyellowwarning)
{
@@ -174,11 +179,11 @@ Joomla = window.Joomla || {};
{
$(this).data('state', 'closed');
$(this).html( COM_JOOMLAUPDATE_VIEW_DEFAULT_SHOW_MORE_EXTENSION_COMPATIBILITY_INFORMATION);
- compatibilitytypes.find('.exname').addClass('span8').removeClass('span4');
- compatibilitytypes.find('.extype').addClass('span4').removeClass('span2');
- compatibilitytypes.find('.upcomp').addClass('hidden').removeClass('span2');
- compatibilitytypes.find('.currcomp').addClass('hidden').removeClass('span2');
- compatibilitytypes.find('.instver').addClass('hidden').removeClass('span2');
+ compatibilitytypes.find('.exname').addClass('col-md-8').removeClass('col-md-4');
+ compatibilitytypes.find('.extype').addClass('col-md-4').removeClass('col-md-2');
+ compatibilitytypes.find('.upcomp').addClass('hidden').removeClass('col-md-2');
+ compatibilitytypes.find('.currcomp').addClass('hidden').removeClass('col-md-2');
+ compatibilitytypes.find('.instver').addClass('hidden').removeClass('col-md-2');
compatibilitytypes.find("#updateyellowwarning").addClass('hidden');
compatibilitytypes.find("#updateorangewarning").addClass('hidden');
@@ -214,7 +219,7 @@ Joomla = window.Joomla || {};
url: PreUpdateChecker.config.serverUrl
+ '&joomla-target-version=' + encodeURIComponent(PreUpdateChecker.joomlaTargetVersion)
+ 'joomla-current-version=' + PreUpdateChecker.joomlaCurrentVersion
- + 'extension-version=' + node.data('extension-current-version')
+ + 'extension-version=' + node.getAttribute('data-extension-current-version')
+ '&extension-id=' + encodeURIComponent(node.getAttribute('data-extension-id')),
onSuccess(data) {
var response = JSON.parse(data);
@@ -303,17 +308,22 @@ Joomla = window.Joomla || {};
}
}
// Insert the generated html
- var extensionId = extensionData.$element.data('extensionId');
+ var extensionId = extensionData.element.getAttribute('data-extension-id');
document.getElementById('available-version-' + extensionId ).innerHTML = html;
- extensionData.$element.closest('tr').appendTo($('#compatibilitytype' + extensionData.compatibilityData.resultGroup + ' tbody'));
- $('#compatibilitytype' + extensionData.compatibilityData.resultGroup).css('display', 'block');
+ var compatType = document.querySelector('#compatibilitytype' + extensionData.compatibilityData.resultGroup + ' tbody')
+
+ if (compatType)
+ {
+ compatType.appendChild(extensionData.element.closest('tr'));
+ }
+ document.getElementById('compatibilitytype' + extensionData.compatibilityData.resultGroup).style.display = 'block';
document.getElementById('compatibilitytype0').style.display = 'block';
// Have we finished?
if ($('#compatibilitytype0 tbody td').length == 0) {
- $('#compatibilitytype0').css('display', 'none');
+ document.getElementById('compatibilitytype0').style.display = 'none';
}
}
// Run PreUpdateChecker on document ready
diff --git a/build/media_source/com_media/joomla.asset.json b/build/media_source/com_media/joomla.asset.json
index 8028719ba314e..f89147d9c6a57 100644
--- a/build/media_source/com_media/joomla.asset.json
+++ b/build/media_source/com_media/joomla.asset.json
@@ -19,18 +19,30 @@
{
"name": "com_media.mediamanager",
"type": "style",
- "uri": "com_media/mediamanager.min.css"
+ "uri": "com_media/media-manager.min.css"
},
{
- "name": "com_media.mediamanager",
+ "name": "com_media.mediamanager.es5",
"type": "script",
- "uri": "com_media/mediamanager.min.js",
+ "uri": "com_media/media-manager-es5.min.js",
"dependencies": [
"core"
],
"attributes": {
+ "nomodule": true,
"defer": true
}
+ },
+ {
+ "name": "com_media.mediamanager",
+ "type": "script",
+ "uri": "com_media/media-manager.min.js",
+ "dependencies": [
+ "com_media.mediamanager.es5"
+ ],
+ "attributes": {
+ "type": "module"
+ }
}
]
}
diff --git a/administrator/components/com_media/resources/styles/variables.scss b/build/media_source/com_media/scss/_variables.scss
similarity index 100%
rename from administrator/components/com_media/resources/styles/variables.scss
rename to build/media_source/com_media/scss/_variables.scss
diff --git a/administrator/components/com_media/resources/styles/components/_animations.scss b/build/media_source/com_media/scss/components/_animations.scss
similarity index 100%
rename from administrator/components/com_media/resources/styles/components/_animations.scss
rename to build/media_source/com_media/scss/components/_animations.scss
diff --git a/administrator/components/com_media/resources/styles/components/_layout.scss b/build/media_source/com_media/scss/components/_layout.scss
similarity index 100%
rename from administrator/components/com_media/resources/styles/components/_layout.scss
rename to build/media_source/com_media/scss/components/_layout.scss
diff --git a/administrator/components/com_media/resources/styles/components/_media-breadcrumb.scss b/build/media_source/com_media/scss/components/_media-breadcrumb.scss
similarity index 100%
rename from administrator/components/com_media/resources/styles/components/_media-breadcrumb.scss
rename to build/media_source/com_media/scss/components/_media-breadcrumb.scss
diff --git a/administrator/components/com_media/resources/styles/components/_media-browser.scss b/build/media_source/com_media/scss/components/_media-browser.scss
similarity index 100%
rename from administrator/components/com_media/resources/styles/components/_media-browser.scss
rename to build/media_source/com_media/scss/components/_media-browser.scss
diff --git a/administrator/components/com_media/resources/styles/components/_media-edit.scss b/build/media_source/com_media/scss/components/_media-edit.scss
similarity index 100%
rename from administrator/components/com_media/resources/styles/components/_media-edit.scss
rename to build/media_source/com_media/scss/components/_media-edit.scss
diff --git a/administrator/components/com_media/resources/styles/components/_media-infobar.scss b/build/media_source/com_media/scss/components/_media-infobar.scss
similarity index 100%
rename from administrator/components/com_media/resources/styles/components/_media-infobar.scss
rename to build/media_source/com_media/scss/components/_media-infobar.scss
diff --git a/administrator/components/com_media/resources/styles/components/_media-modal.scss b/build/media_source/com_media/scss/components/_media-modal.scss
similarity index 100%
rename from administrator/components/com_media/resources/styles/components/_media-modal.scss
rename to build/media_source/com_media/scss/components/_media-modal.scss
diff --git a/administrator/components/com_media/resources/styles/components/_media-toolbar.scss b/build/media_source/com_media/scss/components/_media-toolbar.scss
similarity index 100%
rename from administrator/components/com_media/resources/styles/components/_media-toolbar.scss
rename to build/media_source/com_media/scss/components/_media-toolbar.scss
diff --git a/administrator/components/com_media/resources/styles/components/_media-tree.scss b/build/media_source/com_media/scss/components/_media-tree.scss
similarity index 100%
rename from administrator/components/com_media/resources/styles/components/_media-tree.scss
rename to build/media_source/com_media/scss/components/_media-tree.scss
diff --git a/administrator/components/com_media/resources/styles/mediamanager.scss b/build/media_source/com_media/scss/media-manager.scss
similarity index 100%
rename from administrator/components/com_media/resources/styles/mediamanager.scss
rename to build/media_source/com_media/scss/media-manager.scss
diff --git a/build/media_source/com_workflow/js/admin-items-workflow-buttons.es6.js b/build/media_source/com_workflow/js/admin-items-workflow-buttons.es6.js
index b5bf3af1c168f..0ceb58f8e3e7a 100644
--- a/build/media_source/com_workflow/js/admin-items-workflow-buttons.es6.js
+++ b/build/media_source/com_workflow/js/admin-items-workflow-buttons.es6.js
@@ -39,6 +39,11 @@ Joomla.toggleAllNextElements = (element, className) => {
document.addEventListener('DOMContentLoaded', () => {
const dropDownBtn = document.getElementById('toolbar-status-group');
+
+ if (!dropDownBtn) {
+ return;
+ }
+
const transitions = [].slice.call(dropDownBtn.querySelectorAll('.button-transition'));
const headline = dropDownBtn.querySelector('.button-transition-headline');
const separator = dropDownBtn.querySelector('.button-transition-separator');
diff --git a/build/media_source/mod_multilangstatus/js/admin-multilangstatus.es6.js b/build/media_source/mod_multilangstatus/js/admin-multilangstatus.es6.js
index 6ed4c77f5a18b..d86966a68ad90 100644
--- a/build/media_source/mod_multilangstatus/js/admin-multilangstatus.es6.js
+++ b/build/media_source/mod_multilangstatus/js/admin-multilangstatus.es6.js
@@ -21,7 +21,7 @@
document.body.appendChild(clone);
// Modal was moved so it needs to be re initialised
- Joomla.Bootstrap.Initialise.Modal(clone);
+ Joomla.initialiseModal(clone);
}
});
})();
diff --git a/build/media_source/plg_editors_tinymce/js/tinymce-builder.es6.js b/build/media_source/plg_editors_tinymce/js/tinymce-builder.es6.js
index c82606aee1aaf..398d3bbd03b0d 100644
--- a/build/media_source/plg_editors_tinymce/js/tinymce-builder.es6.js
+++ b/build/media_source/plg_editors_tinymce/js/tinymce-builder.es6.js
@@ -201,11 +201,11 @@ Joomla = window.Joomla || {};
window.tinymce = tinymce;
const TinyMCEBuilder = (container, options) => {
- const $sourceMenu = container.querySelector('.timymce-builder-menu.source');
- const $sourceToolbar = container.querySelector('.timymce-builder-toolbar.source');
+ const $sourceMenu = container.querySelector('.tinymce-builder-menu.source');
+ const $sourceToolbar = container.querySelector('.tinymce-builder-toolbar.source');
- const $targetMenu = container.querySelectorAll('.timymce-builder-menu.target');
- const $targetToolbar = container.querySelectorAll('.timymce-builder-toolbar.target');
+ const $targetMenu = container.querySelectorAll('.tinymce-builder-menu.target');
+ const $targetToolbar = container.querySelectorAll('.tinymce-builder-toolbar.target');
/**
* Append input to the button item
diff --git a/build/media_source/plg_installer_urlinstaller/js/urlinstaller.es6.js b/build/media_source/plg_installer_urlinstaller/js/urlinstaller.es6.js
index a8f53c99674aa..ba2d6650a01c1 100644
--- a/build/media_source/plg_installer_urlinstaller/js/urlinstaller.es6.js
+++ b/build/media_source/plg_installer_urlinstaller/js/urlinstaller.es6.js
@@ -12,18 +12,13 @@ Joomla = window.Joomla || {};
Joomla.submitbuttonurl = () => {
const form = document.getElementById('adminForm');
- // do field validation
- if (form.install_url.value === '' || form.install_url.value === 'http://' || form.install_url.value === 'https://') {
- Joomla.renderMessages({ warning: [Joomla.Text._('PLG_INSTALLER_URLINSTALLER_NO_URL')] });
- } else {
- const loading = document.getElementById('loading');
- if (loading) {
- loading.classList.remove('hidden');
- }
-
- form.installtype.value = 'url';
- form.submit();
+ const loading = document.getElementById('loading');
+ if (loading) {
+ loading.classList.remove('hidden');
}
+
+ form.installtype.value = 'url';
+ form.submit();
};
});
})(Joomla);
diff --git a/build/media_source/system/joomla.asset.json b/build/media_source/system/joomla.asset.json
index 05ef7bdfcfd52..6319261fef327 100644
--- a/build/media_source/system/joomla.asset.json
+++ b/build/media_source/system/joomla.asset.json
@@ -195,128 +195,303 @@
"defer": true
}
},
+ {
+ "name": "webcomponent.field-fancy-select-legacy",
+ "type": "script",
+ "uri": "system/fields/joomla-field-fancy-select-es5.min.js",
+ "attributes": {
+ "nomodule": true,
+ "defer": true
+ },
+ "dependencies": [
+ "wcpolyfill",
+ "choicesjs"
+ ]
+ },
{
"name": "webcomponent.field-fancy-select",
"type": "script",
"uri": "system/fields/joomla-field-fancy-select.min.js",
- "webcomponent": true,
+ "attributes": {
+ "type": "module"
+ },
"dependencies": [
- "choicesjs"
+ "choicesjs",
+ "webcomponent.field-fancy-select-legacy"
]
},
{
"name": "webcomponent.field-media",
"type": "style",
- "uri": "system/fields/joomla-field-media.min.css",
- "webcomponent": true
+ "uri": "system/fields/joomla-field-media.min.css"
},
{
"name": "webcomponent.image-select",
"type": "style",
- "uri": "system/fields/joomla-image-select.min.css",
- "webcomponent": true
+ "uri": "system/fields/joomla-image-select.min.css"
+ },
+ {
+ "name": "webcomponent.image-select-legacy",
+ "type": "script",
+ "uri": "system/fields/joomla-image-select-es5.min.js",
+ "attributes": {
+ "nomodule": true,
+ "defer": true
+ },
+ "dependencies": [
+ "wcpolyfill"
+ ]
},
{
"name": "webcomponent.image-select",
"type": "script",
"uri": "system/fields/joomla-image-select.min.js",
- "webcomponent": true
+ "attributes": {
+ "type": "module"
+ },
+ "dependencies": [
+ "webcomponent.image-select-legacy"
+ ]
+ },
+ {
+ "name": "webcomponent.field-media-legacy",
+ "type": "script",
+ "uri": "system/fields/joomla-field-media-es5.min.js",
+ "attributes": {
+ "nomodule": true,
+ "defer": true
+ },
+ "dependencies": [
+ "wcpolyfill"
+ ]
},
{
"name": "webcomponent.field-media",
"type": "script",
"uri": "system/fields/joomla-field-media.min.js",
- "webcomponent": true
+ "attributes": {
+ "type": "module"
+ },
+ "dependencies": [
+ "webcomponent.field-media-legacy"
+ ]
+ },
+ {
+ "name": "webcomponent.field-module-order-legacy",
+ "type": "script",
+ "uri": "system/fields/joomla-field-module-order-es5.min.js",
+ "attributes": {
+ "nomodule": true,
+ "defer": true
+ },
+ "dependencies": [
+ "wcpolyfill"
+ ]
},
{
"name": "webcomponent.field-module-order",
"type": "script",
"uri": "system/fields/joomla-field-module-order.min.js",
- "webcomponent": true
+ "attributes": {
+ "type": "module"
+ },
+ "dependencies": [
+ "webcomponent.field-module-order-legacy"
+ ]
},
{
"name": "webcomponent.field-permissions",
"type": "style",
- "uri": "system/fields/joomla-field-permissions.min.css",
- "webcomponent": true
+ "uri": "system/fields/joomla-field-permissions.min.css"
+ },
+ {
+ "name": "webcomponent.field-permissions-legacy",
+ "type": "script",
+ "uri": "system/fields/joomla-field-permissions-es5.min.js",
+ "attributes": {
+ "nomodule": true,
+ "defer": true
+ },
+ "dependencies": [
+ "wcpolyfill"
+ ]
},
{
"name": "webcomponent.field-permissions",
"type": "script",
"uri": "system/fields/joomla-field-permissions.min.js",
- "webcomponent": true
+ "attributes": {
+ "type": "module"
+ },
+ "dependencies": [
+ "webcomponent.field-permissions-legacy"
+ ]
+ },
+ {
+ "name": "webcomponent.field-send-test-mail-legacy",
+ "type": "script",
+ "uri": "system/fields/joomla-field-send-test-mail-es5.min.js",
+ "attributes": {
+ "nomodule": true,
+ "defer": true
+ },
+ "dependencies": [
+ "wcpolyfill"
+ ]
},
{
"name": "webcomponent.field-send-test-mail",
"type": "script",
"uri": "system/fields/joomla-field-send-test-mail.min.js",
- "webcomponent": true
+ "attributes": {
+ "type": "module"
+ },
+ "dependencies": [
+ "webcomponent.field-send-test-mail-legacy"
+ ]
},
{
"name": "webcomponent.field-simple-color",
"type": "style",
- "uri": "system/fields/joomla-field-simple-color.min.css",
- "webcomponent": true
+ "uri": "system/fields/joomla-field-simple-color.min.css"
+ },
+ {
+ "name": "webcomponent.field-simple-color-legacy",
+ "type": "script",
+ "uri": "system/fields/joomla-field-simple-color-es5.min.js",
+ "attributes": {
+ "nomodule": true,
+ "defer": true
+ },
+ "dependencies": [
+ "wcpolyfill"
+ ]
},
{
"name": "webcomponent.field-simple-color",
"type": "script",
"uri": "system/fields/joomla-field-simple-color.min.js",
- "webcomponent": true
+ "attributes": {
+ "type": "module"
+ },
+ "dependencies": [
+ "webcomponent.field-simple-color-legacy"
+ ]
+ },
+ {
+ "name": "webcomponent.field-subform-legacy",
+ "type": "script",
+ "uri": "system/fields/joomla-field-subform-es5.min.js",
+ "attributes": {
+ "nomodule": true,
+ "defer": true
+ },
+ "dependencies": [
+ "wcpolyfill"
+ ]
},
{
"name": "webcomponent.field-subform",
"type": "script",
"uri": "system/fields/joomla-field-subform.min.js",
- "webcomponent": true
+ "attributes": {
+ "type": "module"
+ },
+ "dependencies": [
+ "webcomponent.field-subform-legacy"
+ ]
},
{
- "name": "webcomponent.field-user",
+ "name": "webcomponent.field-user-legacy",
"type": "script",
- "uri": "system/fields/joomla-field-user.min.js",
- "webcomponent": true
+ "uri": "system/fields/joomla-field-user-es5.min.js",
+ "attributes": {
+ "nomodule": true,
+ "defer": true
+ },
+ "dependencies": [
+ "wcpolyfill"
+ ]
},
{
- "name": "webcomponent.core-loader",
+ "name": "webcomponent.field-user",
"type": "script",
- "uri": "system/joomla-core-loader.min.js",
- "webcomponent": true
+ "uri": "system/fields/joomla-field-user.min.js",
+ "attributes": {
+ "type": "module"
+ },
+ "dependencies": [
+ "webcomponent.field-user-legacy"
+ ]
},
{
- "name": "webcomponent.hidden-mail",
+ "name": "webcomponent.core-loader-legacy",
"type": "script",
- "uri": "system/joomla-hidden-mail.min.js",
- "webcomponent": true
+ "uri": "system/joomla-core-loader-es5.min.js",
+ "attributes": {
+ "nomodule": true,
+ "defer": true
+ },
+ "dependencies": [
+ "wcpolyfill"
+ ]
},
{
- "name": "webcomponent.toolbar-button",
+ "name": "webcomponent.core-loader",
"type": "script",
- "uri": "system/joomla-toolbar-button.min.js",
- "webcomponent": true
+ "uri": "system/joomla-core-loader.min.js",
+ "attributes": {
+ "type": "module"
+ },
+ "dependencies": [
+ "webcomponent.core-loader-legacy"
+ ]
},
{
- "name": "webcomponent.joomla-alert",
- "type": "style",
- "uri": "vendor/joomla-custom-elements/joomla-alert.min.css",
- "webcomponent": true
+ "name": "webcomponent.hidden-mail-legacy",
+ "type": "script",
+ "uri": "system/joomla-hidden-mail-es5.min.js",
+ "attributes": {
+ "nomodule": true,
+ "defer": true
+ },
+ "dependencies": [
+ "wcpolyfill"
+ ]
},
{
- "name": "webcomponent.joomla-alert",
+ "name": "webcomponent.hidden-mail",
"type": "script",
- "uri": "vendor/joomla-custom-elements/joomla-alert.min.js",
- "webcomponent": true
+ "uri": "system/joomla-hidden-mail.min.js",
+ "attributes": {
+ "type": "module"
+ },
+ "dependencies": [
+ "webcomponent.hidden-mail-legacy"
+ ]
},
{
- "name": "webcomponent.joomla-tab",
- "type": "style",
- "uri": "vendor/joomla-custom-elements/joomla-tab.min.css",
- "webcomponent": true
+ "name": "webcomponent.toolbar-button-legacy",
+ "type": "script",
+ "uri": "system/joomla-toolbar-button-es5.min.js",
+ "attributes": {
+ "nomodule": true,
+ "defer": true
+ },
+ "dependencies": [
+ "wcpolyfill"
+ ]
},
{
- "name": "webcomponent.joomla-tab",
+ "name": "webcomponent.toolbar-button",
"type": "script",
- "uri": "vendor/joomla-custom-elements/joomla-tab.min.js",
- "webcomponent": true
+ "uri": "system/joomla-toolbar-button.min.js",
+ "attributes": {
+ "type": "module"
+ },
+ "dependencies": [
+ "webcomponent.toolbar-button-legacy"
+ ]
}
]
}
diff --git a/build/media_source/system/js/core.es6/customevent.es6 b/build/media_source/system/js/core.es6/customevent.es6
deleted file mode 100644
index f3593cb081ac3..0000000000000
--- a/build/media_source/system/js/core.es6/customevent.es6
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * @copyright (C) 2020 Open Source Matters, Inc.
- * @license GNU General Public License version 2 or later; see LICENSE.txt
- */
-
-// eslint-disable max-len
-/**
- * Patch Custom Events
- * https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent
- */
-(() => {
- if (typeof window.CustomEvent === 'function') {
- return false;
- }
-
- const CustomEvent = (event, params) => {
- const evt = document.createEvent('CustomEvent');
- const newParams = params
- || {
- bubbles: false,
- cancelable: false,
- detail: undefined,
- };
-
- evt.initCustomEvent(event, newParams.bubbles, newParams.cancelable, newParams.detail);
- return evt;
- };
-
- CustomEvent.prototype = window.Event.prototype;
-
- window.CustomEvent = CustomEvent;
- return true;
-})();
diff --git a/build/media_source/system/js/core.es6/webcomponent.es6 b/build/media_source/system/js/core.es6/webcomponent.es6
deleted file mode 100644
index 25d4e818aa13a..0000000000000
--- a/build/media_source/system/js/core.es6/webcomponent.es6
+++ /dev/null
@@ -1,290 +0,0 @@
-/**
- * @license
- * Copyright (c) 2018 The Polymer Project Authors. All rights reserved.
- * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
- * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
- * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
- * Code distributed by Google as part of the polymer project is also
- * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
- *
- * LICENSE.txt from http://polymer.github.io/LICENSE.txt
- *
- * Copyright (c) 2014 The Polymer Authors. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * @note This file has been modified by the Joomla! Project
- * and no longer reflects the original work of its author.
- */
-
-((Joomla, document) => {
- 'use strict';
-
- /**
- * Basic flow of the loader process
- *
- * There are 4 flows the loader can take when booting up
- *
- * - Synchronous script, no polyfills needed
- * - wait for `DOMContentLoaded`
- * - fire WCR event, as there could not be any callbacks passed to `waitFor`
- *
- * - Synchronous script, polyfills needed
- * - document.write the polyfill bundle
- * - wait on the `load` event of the bundle to batch Custom Element upgrades
- * - wait for `DOMContentLoaded`
- * - run callbacks passed to `waitFor`
- * - fire WCR event
- *
- * - Asynchronous script, no polyfills needed
- * - wait for `DOMContentLoaded`
- * - run callbacks passed to `waitFor`
- * - fire WCR event
- *
- * - Asynchronous script, polyfills needed
- * - Append the polyfill bundle script
- * - wait for `load` event of the bundle
- * - batch Custom Element Upgrades
- * - run callbacks pass to `waitFor`
- * - fire WCR event
- *
- * @since 4.0.0
- */
- Joomla.WebComponents = () => {
- const wc = Joomla.getOptions('webcomponents');
-
- // Return early
- if (!wc || !wc.length) {
- return;
- }
-
- let polyfillsLoaded = false;
- const whenLoadedFns = [];
- let allowUpgrades = false;
- let flushFn;
-
- const fireEvent = () => {
- window.WebComponents.ready = true;
- document.dispatchEvent(new CustomEvent('WebComponentsReady', { bubbles: true }));
- // eslint-disable-next-line no-use-before-define
- loadWC();
- };
-
- const batchCustomElements = () => {
- if (window.customElements && customElements.polyfillWrapFlushCallback) {
- customElements.polyfillWrapFlushCallback((flushCallback) => {
- flushFn = flushCallback;
- if (allowUpgrades) {
- flushFn();
- }
- });
- }
- };
-
- const asyncReady = () => {
- // eslint-disable-next-line no-use-before-define
- batchCustomElements();
- // eslint-disable-next-line no-use-before-define
- ready();
- };
-
- const ready = () => {
- // bootstrap elements before custom elements
- if (window.HTMLTemplateElement && HTMLTemplateElement.bootstrap) {
- HTMLTemplateElement.bootstrap(window.document);
- }
-
- polyfillsLoaded = true;
- // eslint-disable-next-line no-use-before-define
- runWhenLoadedFns().then(fireEvent);
- };
-
- const runWhenLoadedFns = () => {
- allowUpgrades = false;
- const done = () => {
- allowUpgrades = true;
- whenLoadedFns.length = 0;
- // eslint-disable-next-line no-unused-expressions
- flushFn && flushFn();
- };
- return Promise.all(whenLoadedFns.map((fn) => (fn instanceof Function ? fn() : fn)))
- .then(() => {
- done();
- }).catch((err) => {
- // eslint-disable-next-line no-console
- console.error(err);
- });
- };
-
- window.WebComponents = window.WebComponents || {
- ready: false,
- _batchCustomElements: batchCustomElements,
- waitFor: (waitFn) => {
- if (!waitFn) {
- return;
- }
- whenLoadedFns.push(waitFn);
- if (polyfillsLoaded) {
- runWhenLoadedFns();
- }
- },
- };
-
- /* Check if ES6 then apply the shim */
- const checkES6 = () => {
- try {
- // eslint-disable-next-line no-new-func, no-new
- new Function('(a = 0) => a');
- return true;
- } catch (err) {
- return false;
- }
- };
-
- /* Load web components async */
- const loadWC = () => {
- if (wc && wc.length) {
- wc.forEach((component) => {
- let el;
- if (component.match(/\.js/g)) {
- el = document.createElement('script');
- if (!checkES6()) {
- let es5;
- // Browser is not ES6!
- if (component.match(/\.min\.js/g)) {
- es5 = component.replace(/\.min\.js/g, '-es5.min.js');
- } else if (component.match(/\.js/g)) {
- es5 = component.replace(/\.js/g, '-es5.js');
- }
- el.src = es5;
- } else {
- el.src = component;
- }
- }
- if (el) {
- document.head.appendChild(el);
- }
- });
- }
- };
-
- // Get the core.js src attribute
- let name = 'core.min.js';
- let script = document.querySelector(`script[src*="${name}"]`);
-
- if (!script) {
- name = 'core.js';
- script = document.querySelector(`script[src*="${name}"]`);
- }
-
- if (!script) {
- throw new Error('core(.min).js is not registered correctly!');
- }
-
- // Feature detect which polyfill needs to be imported.
- let polyfills = [];
- if (!('attachShadow' in Element.prototype && 'getRootNode' in Element.prototype)
- || (window.ShadyDOM && window.ShadyDOM.force)) {
- polyfills.push('sd');
- }
- if (!window.customElements || window.customElements.forcePolyfill) {
- polyfills.push('ce');
- }
-
- const needsTemplate = (() => {
- // no real because no `content` property (IE and older browsers)
- const t = document.createElement('template');
- if (!('content' in t)) {
- return true;
- }
- // broken doc fragment (older Edge)
- if (!(t.content.cloneNode() instanceof DocumentFragment)) {
- return true;
- }
- // broken cloning (Edge up to at least version 17)
- const t2 = document.createElement('template');
- t2.content.appendChild(document.createElement('div'));
- t.content.appendChild(t2);
- const clone = t.cloneNode(true);
- return (clone.content.childNodes.length === 0
- || clone.content.firstChild.content.childNodes.length === 0);
- })();
-
- // NOTE: any browser that does not have template or ES6 features
- // must load the full suite of polyfills.
- if (!window.Promise || !Array.from || !window.URL || !window.Symbol || needsTemplate) {
- polyfills = ['sd-ce-pf'];
- }
-
- if (polyfills.length) {
- const newScript = document.createElement('script');
- // Load it from the right place.
- const replacement = `media/vendor/webcomponentsjs/js/webcomponents-${polyfills.join('-')}.min.js`;
-
- const mediaVersion = script.src.match(/\?.*/);
- const base = Joomla.getOptions('system.paths');
-
- if (!base) {
- throw new Error('core(.min).js is not registered correctly!');
- }
-
- newScript.src = base.rootFull + replacement + (mediaVersion ? mediaVersion[0] : '');
-
- // if readyState is 'loading', this script is synchronous
- if (document.readyState === 'loading') {
- // make sure custom elements are batched whenever parser gets to the injected script
- newScript.setAttribute('onload', 'window.WebComponents._batchCustomElements()');
- document.write(newScript.outerHTML);
- document.addEventListener('DOMContentLoaded', ready);
- } else {
- newScript.addEventListener('load', asyncReady);
- newScript.addEventListener('error', () => {
- throw new Error(`Could not load polyfill bundle ${base.rootFull + replacement}`);
- });
- document.head.appendChild(newScript);
- }
- } else {
- polyfillsLoaded = true;
- if (document.readyState === 'complete') {
- fireEvent();
- } else {
- // this script may come between DCL and load, so listen for both
- // and cancel load listener if DCL fires
- window.addEventListener('load', ready);
- window.addEventListener('DOMContentLoaded', () => {
- window.removeEventListener('load', ready);
- ready();
- });
- }
- }
- };
-})(Joomla, document);
-
-/**
- * Load any web components and any polyfills required
- */
-document.addEventListener('DOMContentLoaded', Joomla.WebComponents);
diff --git a/build/media_source/system/js/fields/calendar-locales/bg.js b/build/media_source/system/js/fields/calendar-locales/bg.es5.js
similarity index 100%
rename from build/media_source/system/js/fields/calendar-locales/bg.js
rename to build/media_source/system/js/fields/calendar-locales/bg.es5.js
diff --git a/build/media_source/system/js/fields/calendar-locales/bn.js b/build/media_source/system/js/fields/calendar-locales/bn.es5.js
similarity index 100%
rename from build/media_source/system/js/fields/calendar-locales/bn.js
rename to build/media_source/system/js/fields/calendar-locales/bn.es5.js
diff --git a/build/media_source/system/js/fields/calendar-locales/bs.js b/build/media_source/system/js/fields/calendar-locales/bs.es5.js
similarity index 100%
rename from build/media_source/system/js/fields/calendar-locales/bs.js
rename to build/media_source/system/js/fields/calendar-locales/bs.es5.js
diff --git a/build/media_source/system/js/fields/calendar-locales/ca.js b/build/media_source/system/js/fields/calendar-locales/ca.es5.js
similarity index 100%
rename from build/media_source/system/js/fields/calendar-locales/ca.js
rename to build/media_source/system/js/fields/calendar-locales/ca.es5.js
diff --git a/build/media_source/system/js/fields/calendar-locales/cs.js b/build/media_source/system/js/fields/calendar-locales/cs.es5.js
similarity index 100%
rename from build/media_source/system/js/fields/calendar-locales/cs.js
rename to build/media_source/system/js/fields/calendar-locales/cs.es5.js
diff --git a/build/media_source/system/js/fields/calendar-locales/cy.js b/build/media_source/system/js/fields/calendar-locales/cy.es5.js
similarity index 100%
rename from build/media_source/system/js/fields/calendar-locales/cy.js
rename to build/media_source/system/js/fields/calendar-locales/cy.es5.js
diff --git a/build/media_source/system/js/fields/calendar-locales/da.js b/build/media_source/system/js/fields/calendar-locales/da.es5.js
similarity index 100%
rename from build/media_source/system/js/fields/calendar-locales/da.js
rename to build/media_source/system/js/fields/calendar-locales/da.es5.js
diff --git a/build/media_source/system/js/fields/calendar-locales/kk.js b/build/media_source/system/js/fields/calendar-locales/kk.es5.js
similarity index 100%
rename from build/media_source/system/js/fields/calendar-locales/kk.js
rename to build/media_source/system/js/fields/calendar-locales/kk.es5.js
diff --git a/build/media_source/system/js/fields/calendar-locales/lt.js b/build/media_source/system/js/fields/calendar-locales/lt.es5.js
similarity index 100%
rename from build/media_source/system/js/fields/calendar-locales/lt.js
rename to build/media_source/system/js/fields/calendar-locales/lt.es5.js
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 0bd84616a5663..4d8d673d14829 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
@@ -98,11 +98,10 @@
// Bootstrap modal init
if (this.modalElement
- && Joomla.Bootstrap
- && Joomla.Bootstrap.Instances
- && Joomla.Bootstrap.Instances.Modal
- && Joomla.Bootstrap.Instances.Modal.get(this.modalElement) === undefined) {
- Joomla.Bootstrap.Initialise.Modal(this.modalElement, { isJoomla: true });
+ && window.bootstrap
+ && window.bootstrap.Modal
+ && window.bootstrap.Modal.getInstance(this.modalElement) === undefined) {
+ Joomla.initialiseModal(this.modalElement, { isJoomla: true });
}
if (this.buttonClearEl) {
@@ -153,6 +152,13 @@
setValue(value) {
this.inputElement.value = value;
this.updatePreview();
+
+ // trigger change event both on the input and on the custom element
+ this.inputElement.dispatchEvent(new Event('change'));
+ this.dispatchEvent(new CustomEvent('change', {
+ detail: { value },
+ bubbles: true,
+ }));
}
clearValue() {
diff --git a/build/media_source/system/js/fields/joomla-field-module-order.w-c.es6.js b/build/media_source/system/js/fields/joomla-field-module-order.w-c.es6.js
index 1bedbd611fd36..22b10455cb480 100644
--- a/build/media_source/system/js/fields/joomla-field-module-order.w-c.es6.js
+++ b/build/media_source/system/js/fields/joomla-field-module-order.w-c.es6.js
@@ -96,11 +96,12 @@ customElements.define('joomla-field-module-order', class extends HTMLElement {
const name = this.getAttribute('data-name');
const attr = this.getAttribute('data-client-attr') ? this.getAttribute('data-client-attr') : 'form-select';
const id = `${this.getAttribute('data-id')}`;
+ const moduleId = `${this.getAttribute('data-module-id')}`;
const orders = [];
const that = this;
Joomla.request({
- url: `${url}&client_id=${clientId}&position=${originalPosition}`,
+ url: `${url}&client_id=${clientId}&position=${originalPosition}&module_id=${moduleId}`,
method: 'GET',
perform: true,
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
diff --git a/build/media_source/system/js/fields/joomla-field-send-test-mail.w-c.es6.js b/build/media_source/system/js/fields/joomla-field-send-test-mail.w-c.es6.js
index 669625c707649..d2daf4ed32b5e 100644
--- a/build/media_source/system/js/fields/joomla-field-send-test-mail.w-c.es6.js
+++ b/build/media_source/system/js/fields/joomla-field-send-test-mail.w-c.es6.js
@@ -62,9 +62,13 @@
if (typeof response.messages === 'object' && response.messages !== null) {
Joomla.renderMessages(response.messages);
}
+
+ document.body.scrollIntoView({ behavior: 'smooth' });
},
onError: (xhr) => {
Joomla.renderMessages(Joomla.ajaxErrorsMessages(xhr));
+
+ document.body.scrollIntoView({ behavior: 'smooth' });
},
});
}
diff --git a/build/media_source/system/js/fields/joomla-field-simple-color.w-c.es6.js b/build/media_source/system/js/fields/joomla-field-simple-color.w-c.es6.js
index ee526c0ff5dc5..f8a1fe96006f1 100644
--- a/build/media_source/system/js/fields/joomla-field-simple-color.w-c.es6.js
+++ b/build/media_source/system/js/fields/joomla-field-simple-color.w-c.es6.js
@@ -365,6 +365,13 @@
this.icon.setAttribute('class', clss);
this.icon.style.backgroundColor = bgcolor;
+ // trigger change event both on the select and on the custom element
+ this.select.dispatchEvent(new Event('change'));
+ this.dispatchEvent(new CustomEvent('change', {
+ detail: { value: color },
+ bubbles: true,
+ }));
+
// Hide the panel
this.hide();
diff --git a/build/media_source/system/js/fields/joomla-field-user.w-c.es6.js b/build/media_source/system/js/fields/joomla-field-user.w-c.es6.js
index 4716b1895cd2f..c4e5176d441fb 100644
--- a/build/media_source/system/js/fields/joomla-field-user.w-c.es6.js
+++ b/build/media_source/system/js/fields/joomla-field-user.w-c.es6.js
@@ -1,4 +1,4 @@
-(() => {
+((customElements, Joomla) => {
class JoomlaFieldUser extends HTMLElement {
constructor() {
super();
@@ -55,11 +55,10 @@
// Bootstrap modal init
if (this.modal
- && Joomla.Bootstrap
- && Joomla.Bootstrap.Instances
- && Joomla.Bootstrap.Instances.Modal
- && Joomla.Bootstrap.Instances.Modal.get(this.modal) === undefined) {
- Joomla.Bootstrap.Initialise.Modal(this.modal, { isJoomla: true });
+ && window.bootstrap
+ && window.bootstrap.Modal
+ && window.bootstrap.Modal.getInstance(this.modal) === undefined) {
+ Joomla.initialiseModal(this.modal, { isJoomla: true });
}
if (this.buttonSelect) {
@@ -140,10 +139,14 @@
setValue(value, name) {
this.input.setAttribute('value', value);
this.inputName.setAttribute('value', name || value);
- // trigger change event
+ // trigger change event both on the input and on the custom element
this.input.dispatchEvent(new Event('change'));
+ this.dispatchEvent(new CustomEvent('change', {
+ detail: { value, name },
+ bubbles: true,
+ }));
}
}
customElements.define('joomla-field-user', JoomlaFieldUser);
-})();
+})(customElements, Joomla);
diff --git a/build/media_source/system/js/searchtools.es6.js b/build/media_source/system/js/searchtools.es6.js
index 3567115b4a46d..49873a110359f 100644
--- a/build/media_source/system/js/searchtools.es6.js
+++ b/build/media_source/system/js/searchtools.es6.js
@@ -322,9 +322,10 @@ Joomla = window.Joomla || {};
// Add all active filters to the table caption for screen-readers
const filteredByCaption = document.getElementById('filteredBy');
+ const isHidden = Object.prototype.hasOwnProperty.call(element.attributes, 'type') && element.attributes.type.value === 'hidden';
// The caption won't exist if no items match the filters so check for the element first
- if (filteredByCaption) {
+ if (filteredByCaption && !isHidden) {
let captionContent = '';
if (element.tagName.toLowerCase() === 'select') {
@@ -439,7 +440,7 @@ Joomla = window.Joomla || {};
this.orderField.setAttribute('name', self.options.orderFieldName);
this.orderField.setAttribute('value', `${self.activeOrder} ${this.activeDirection}`);
- this.theForm.innerHTML += this.orderField.outerHTML;
+ this.theForm.append(this.orderField);
}
// Add missing columns to the order select
diff --git a/build/media_source/system/js/showon.es6.js b/build/media_source/system/js/showon.es6.js
index 51a62487b8093..6e1dd07b8ca39 100644
--- a/build/media_source/system/js/showon.es6.js
+++ b/build/media_source/system/js/showon.es6.js
@@ -29,6 +29,12 @@
if (this.showonFields.length) {
// @todo refactor this, dry
this.showonFields.forEach((field) => {
+ // Set up only once
+ if (field.hasAttribute('data-showon-initialised')) {
+ return;
+ }
+ field.setAttribute('data-showon-initialised', '');
+
const jsondata = field.getAttribute('data-showon') || '';
const showonData = JSON.parse(jsondata);
let localFields;
@@ -204,12 +210,20 @@
}
}
+ // Provide a public API
+ window.Joomla = window.Joomla || {};
+
+ if (!Joomla.Showon) {
+ Joomla.Showon = {
+ initialise: (container) => new Showon(container),
+ };
+ }
+
/**
* Initialize 'showon' feature at an initial page load
*/
document.addEventListener('DOMContentLoaded', () => {
- // eslint-disable-next-line no-new
- new Showon(document);
+ Joomla.Showon.initialise(document);
});
/**
@@ -229,7 +243,6 @@
});
}
- // eslint-disable-next-line no-new
- new Showon(target);
+ Joomla.Showon.initialise(target);
});
})(document);
diff --git a/build/media_source/system/scss/fields/switcher.scss b/build/media_source/system/scss/fields/switcher.scss
index 95d7f3a3985b3..600673874aa1f 100644
--- a/build/media_source/system/scss/fields/switcher.scss
+++ b/build/media_source/system/scss/fields/switcher.scss
@@ -100,10 +100,3 @@ $switcher-height: 28px;
.switcher input ~ input:checked ~ .toggle-outside .toggle-inside {
left: ($switcher-width / 2) - 1;
}
-
-.switcher__legend {
- padding: 5px 0;
- margin-bottom: 1rem;
- font-size: 1rem;
- font-weight: 400;
-}
diff --git a/build/media_source/templates/atum/js/template.es6.js b/build/media_source/templates/atum/js/template.es6.js
index 1edce8252d50e..fd630f2a70411 100644
--- a/build/media_source/templates/atum/js/template.es6.js
+++ b/build/media_source/templates/atum/js/template.es6.js
@@ -103,6 +103,10 @@
svg.setAttribute('viewBox', `0 0 ${svg.getAttribute('height')} ${svg.getAttribute('width')}`);
}
+ // SVG needs to have a role of presentation and focusable set to false
+ svg.setAttribute('role', 'presentation');
+ svg.setAttribute('focusable', 'false');
+
// Replace image with new SVG
img.parentElement.replaceChild(svg, img);
},
diff --git a/build/media_source/vendor/bootstrap/js/alert.es6.js b/build/media_source/vendor/bootstrap/js/alert.es6.js
index c677fd9024bd6..c5c5f08d597f7 100644
--- a/build/media_source/vendor/bootstrap/js/alert.es6.js
+++ b/build/media_source/vendor/bootstrap/js/alert.es6.js
@@ -1,39 +1,18 @@
import Alert from '../../../../../node_modules/bootstrap/js/src/alert';
-Joomla = Joomla || {};
-Joomla.Bootstrap = Joomla.Bootstrap || {};
-Joomla.Bootstrap.Initialise = Joomla.Bootstrap.Initialise || {};
-Joomla.Bootstrap.Instances = Joomla.Bootstrap.Instances || {};
-Joomla.Bootstrap.Instances.Alert = new WeakMap();
+window.bootstrap = window.bootstrap || {};
+window.bootstrap.Alert = Alert;
-/**
- * Initialise the Alert iteractivity
- *
- * @param {HTMLElement} el The element that will become an Alert
- */
-Joomla.Bootstrap.Initialise.Alert = (el) => {
- if (!(el instanceof Element)) {
- return;
+if (Joomla && Joomla.getOptions) {
+ // Get the elements/configurations from the PHP
+ const alerts = Joomla.getOptions('bootstrap.alert');
+ // Initialise the elements
+ if (alerts && alerts.length) {
+ alerts.forEach((selector) => {
+ Array.from(document.querySelectorAll(selector))
+ .map((el) => new window.bootstrap.Alert(el));
+ });
}
- if (Joomla.Bootstrap.Instances.Alert.get(el) && el.dispose) {
- el.dispose();
- }
- Joomla.Bootstrap.Instances.Alert.set(el, new Alert(el));
-};
-
-// Ensure vanilla mode, for consistency of the events
-if (!Object.prototype.hasOwnProperty.call(document.body.dataset, 'bsNoJquery')) {
- document.body.dataset.bsNoJquery = '';
-}
-
-// Get the elements/configurations from the PHP
-const alerts = Joomla.getOptions('bootstrap.alert');
-// Initialise the elements
-if (alerts && alerts.length) {
- alerts.forEach((selector) => {
- Array.from(document.querySelectorAll(selector))
- .map((el) => Joomla.Bootstrap.Initialise.Alert(el));
- });
}
export default Alert;
diff --git a/build/media_source/vendor/bootstrap/js/button.es6.js b/build/media_source/vendor/bootstrap/js/button.es6.js
index 2384f2af28748..fddfe18aaf28f 100644
--- a/build/media_source/vendor/bootstrap/js/button.es6.js
+++ b/build/media_source/vendor/bootstrap/js/button.es6.js
@@ -1,39 +1,18 @@
import Button from '../../../../../node_modules/bootstrap/js/src/button';
-Joomla = Joomla || {};
-Joomla.Bootstrap = Joomla.Bootstrap || {};
-Joomla.Bootstrap.Initialise = Joomla.Bootstrap.Initialise || {};
-Joomla.Bootstrap.Instances = Joomla.Bootstrap.Instances || {};
-Joomla.Bootstrap.Instances.Button = new WeakMap();
+window.bootstrap = window.bootstrap || {};
+window.bootstrap.Button = Button;
-/**
- * Initialise the Button iteractivity
- *
- * @param {HTMLElement} el The element that will become an Button
- */
-Joomla.Bootstrap.Initialise.Button = (el) => {
- if (!(el instanceof Element)) {
- return;
+if (Joomla && Joomla.getOptions) {
+ // Get the elements/configurations from the PHP
+ const buttons = Joomla.getOptions('bootstrap.button');
+ // Initialise the elements
+ if (buttons && buttons.length) {
+ buttons.forEach((selector) => {
+ Array.from(document.querySelectorAll(selector))
+ .map((el) => new window.bootstrap.Button(el));
+ });
}
- if (Joomla.Bootstrap.Instances.Button.get(el) && el.dispose) {
- el.dispose();
- }
- Joomla.Bootstrap.Instances.Button.set(el, new Button(el));
-};
-
-// Ensure vanilla mode, for consistency of the events
-if (!Object.prototype.hasOwnProperty.call(document.body.dataset, 'bsNoJquery')) {
- document.body.dataset.bsNoJquery = '';
-}
-
-// Get the elements/configurations from the PHP
-const buttons = Joomla.getOptions('bootstrap.button');
-// Initialise the elements
-if (buttons && buttons.length) {
- buttons.forEach((selector) => {
- Array.from(document.querySelectorAll(selector))
- .map((el) => Joomla.Bootstrap.Initialise.Button(el));
- });
}
export default Button;
diff --git a/build/media_source/vendor/bootstrap/js/carousel.es6.js b/build/media_source/vendor/bootstrap/js/carousel.es6.js
index 6392fd1a0ba8e..db681b2bbeca1 100644
--- a/build/media_source/vendor/bootstrap/js/carousel.es6.js
+++ b/build/media_source/vendor/bootstrap/js/carousel.es6.js
@@ -1,52 +1,30 @@
import Carousel from '../../../../../node_modules/bootstrap/js/src/carousel';
-Joomla = Joomla || {};
-Joomla.Bootstrap = Joomla.Bootstrap || {};
-Joomla.Bootstrap.Initialise = Joomla.Bootstrap.Initialise || {};
-Joomla.Bootstrap.Instances = Joomla.Bootstrap.Instances || {};
-Joomla.Bootstrap.Instances.Carousel = new WeakMap();
+window.bootstrap = window.bootstrap || {};
+window.bootstrap.Carousel = Carousel;
-/**
- * Initialise the Carousel iteractivity
- *
- * @param {HTMLElement} el The element that will become an Carousel
- * @param {object} options The options for this carousel
- */
-Joomla.Bootstrap.Initialise.Carousel = (el, options) => {
- if (!(el instanceof Element)) {
- return;
- }
- if (Joomla.Bootstrap.Instances.Carousel.get(el) && el.dispose) {
- el.dispose();
- }
- Joomla.Bootstrap.Instances.Carousel.set(el, new Carousel(el, options));
-};
-
-// Get the elements/configurations from the PHP
-const carousels = Joomla.getOptions('bootstrap.carousel');
+if (Joomla && Joomla.getOptions) {
+ // Get the elements/configurations from the PHP
+ const carousels = Joomla.getOptions('bootstrap.carousel');
+ // Initialise the elements
+ if (typeof carousels === 'object' && carousels !== null) {
+ Object.keys(carousels).forEach((carousel) => {
+ const opt = carousels[carousel];
+ const options = {
+ interval: opt.interval ? opt.interval : 5000,
+ keyboard: opt.keyboard ? opt.keyboard : true,
+ pause: opt.pause ? opt.pause : 'hover',
+ slide: opt.slide ? opt.slide : false,
+ wrap: opt.wrap ? opt.wrap : true,
+ touch: opt.touch ? opt.touch : true,
+ };
-// Force Vanilla mode!
-if (!Object.prototype.hasOwnProperty.call(document.body.dataset, 'bsNoJquery')) {
- document.body.dataset.bsNoJquery = '';
-}
-// Initialise the elements
-if (typeof carousels === 'object' && carousels !== null) {
- Object.keys(carousels).forEach((carousel) => {
- const opt = carousels[carousel];
- const options = {
- interval: opt.interval ? opt.interval : 5000,
- keyboard: opt.keyboard ? opt.keyboard : true,
- pause: opt.pause ? opt.pause : 'hover',
- slide: opt.slide ? opt.slide : false,
- wrap: opt.wrap ? opt.wrap : true,
- touch: opt.touch ? opt.touch : true,
- };
-
- const elements = Array.from(document.querySelectorAll(carousel));
- if (elements.length) {
- elements.map((el) => Joomla.Bootstrap.Initialise.Carousel(el, options));
- }
- });
+ const elements = Array.from(document.querySelectorAll(carousel));
+ if (elements.length) {
+ elements.map((el) => new window.bootstrap.Carousel(el, options));
+ }
+ });
+ }
}
export default Carousel;
diff --git a/build/media_source/vendor/bootstrap/js/collapse.es6.js b/build/media_source/vendor/bootstrap/js/collapse.es6.js
index 567c999821f57..297ecc2526256 100644
--- a/build/media_source/vendor/bootstrap/js/collapse.es6.js
+++ b/build/media_source/vendor/bootstrap/js/collapse.es6.js
@@ -1,36 +1,12 @@
import Collapse from '../../../../../node_modules/bootstrap/js/src/collapse';
-Joomla = Joomla || {};
-Joomla.Bootstrap = Joomla.Bootstrap || {};
-Joomla.Bootstrap.Initialise = Joomla.Bootstrap.Initialise || {};
-Joomla.Bootstrap.Instances = Joomla.Bootstrap.Instances || {};
-Joomla.Bootstrap.Instances.Collapse = new WeakMap();
+window.bootstrap = window.bootstrap || {};
+window.bootstrap.Collapse = Collapse;
-/**
- * Initialise the Collapse iteractivity
- *
- * @param {HTMLElement} el The element that will become an collapse
- * @param {object} options The options for this collapse
- */
-Joomla.Bootstrap.Initialise.Collapse = (el, options) => {
- if (!(el instanceof Element)) {
- return;
- }
- if (Joomla.Bootstrap.Instances.Collapse.get(el) && el.dispose) {
- el.dispose();
- }
- Joomla.Bootstrap.Instances.Collapse.set(el, new Collapse(el, options));
-};
-
-// Ensure vanilla mode, for consistency of the events
-if (!Object.prototype.hasOwnProperty.call(document.body.dataset, 'bsNoJquery')) {
- document.body.dataset.bsNoJquery = '';
-}
-
-// Get the elements/configurations from the PHP
-const collapses = { ...Joomla.getOptions('bootstrap.collapse'), ...Joomla.getOptions('bootstrap.accordion') };
-// Initialise the elements
-if (typeof collapses === 'object' && collapses !== null) {
+if (Joomla && Joomla.getOptions) {
+ // Get the elements/configurations from the PHP
+ const collapses = { ...Joomla.getOptions('bootstrap.collapse'), ...Joomla.getOptions('bootstrap.accordion') };
+ // Initialise the elements
Object.keys(collapses).forEach((collapse) => {
const opt = collapses[collapse];
const options = {
@@ -43,7 +19,7 @@ if (typeof collapses === 'object' && collapses !== null) {
const elements = Array.from(document.querySelectorAll(collapse));
if (elements.length) {
- elements.map((el) => Joomla.Bootstrap.Initialise.Collapse(el, options));
+ elements.map((el) => new window.bootstrap.Collapse(el, options));
}
});
}
diff --git a/build/media_source/vendor/bootstrap/js/dropdown.es6.js b/build/media_source/vendor/bootstrap/js/dropdown.es6.js
index 8cba264334d30..aa39a156e039d 100644
--- a/build/media_source/vendor/bootstrap/js/dropdown.es6.js
+++ b/build/media_source/vendor/bootstrap/js/dropdown.es6.js
@@ -1,48 +1,26 @@
import Dropdown from '../../../../../node_modules/bootstrap/js/src/dropdown';
-Joomla = Joomla || {};
-Joomla.Bootstrap = Joomla.Bootstrap || {};
-Joomla.Bootstrap.Initialise = Joomla.Bootstrap.Initialise || {};
-Joomla.Bootstrap.Instances = Joomla.Bootstrap.Instances || {};
-Joomla.Bootstrap.Instances.Dropdown = new WeakMap();
+window.bootstrap = window.bootstrap || {};
+window.bootstrap.Dropdown = Dropdown;
-/**
- * Initialise the iteractivity
- *
- * @param {HTMLElement} el The element that will become an dropdown
- * @param {object} options The options for this dropdown
- */
-Joomla.Bootstrap.Initialise.Dropdown = (el, options) => {
- if (!(el instanceof Element)) {
- return;
- }
- if (Joomla.Bootstrap.Instances.Dropdown.get(el) && el.dispose) {
- el.dispose();
- }
- Joomla.Bootstrap.Instances.Dropdown.set(el, new Dropdown(el, options));
-};
-
-// Ensure vanilla mode, for consistency of the events
-if (!Object.prototype.hasOwnProperty.call(document.body.dataset, 'bsNoJquery')) {
- document.body.dataset.bsNoJquery = '';
-}
-
-// Get the elements/configurations from the PHP
-const dropdowns = Joomla.getOptions('bootstrap.dropdown');
-// Initialise the elements
-if (typeof dropdowns === 'object' && dropdowns !== null) {
- Object.keys(dropdowns).forEach((dropdown) => {
- const opt = dropdowns[dropdown];
- const options = {
- interval: opt.interval ? opt.interval : 5000,
- pause: opt.pause ? opt.pause : 'hover',
- };
+if (Joomla && Joomla.getOptions) {
+ // Get the elements/configurations from the PHP
+ const dropdowns = Joomla.getOptions('bootstrap.dropdown');
+ // Initialise the elements
+ if (typeof dropdowns === 'object' && dropdowns !== null) {
+ Object.keys(dropdowns).forEach((dropdown) => {
+ const opt = dropdowns[dropdown];
+ const options = {
+ interval: opt.interval ? opt.interval : 5000,
+ pause: opt.pause ? opt.pause : 'hover',
+ };
- const elements = Array.from(document.querySelectorAll(dropdown));
- if (elements.length) {
- elements.map((el) => Joomla.Bootstrap.Initialise.Dropdown(el, options));
- }
- });
+ const elements = Array.from(document.querySelectorAll(dropdown));
+ if (elements.length) {
+ elements.map((el) => new window.bootstrap.Dropdown(el, options));
+ }
+ });
+ }
}
export default Dropdown;
diff --git a/build/media_source/vendor/bootstrap/js/modal.es6.js b/build/media_source/vendor/bootstrap/js/modal.es6.js
index b8da50cc82ac8..8519e091e4b77 100644
--- a/build/media_source/vendor/bootstrap/js/modal.es6.js
+++ b/build/media_source/vendor/bootstrap/js/modal.es6.js
@@ -1,23 +1,21 @@
import Modal from '../../../../../node_modules/bootstrap/js/src/modal';
Joomla = Joomla || {};
-Joomla.Bootstrap = Joomla.Bootstrap || {};
-Joomla.Bootstrap.Initialise = Joomla.Bootstrap.Initialise || {};
-Joomla.Bootstrap.Instances = Joomla.Bootstrap.Instances || {};
-Joomla.Bootstrap.Instances.Modal = new WeakMap();
+Joomla.Modal = Joomla.Modal || {};
+window.bootstrap = window.bootstrap || {};
+window.bootstrap.Modal = Modal;
-Joomla.Bootstrap.Initialise.Modal = (modal, options) => {
+Joomla.initialiseModal = (modal, options) => {
if (!(modal instanceof Element)) {
return;
}
- if (Joomla.Bootstrap.Instances.Modal.get(modal) && modal.dispose) {
- modal.dispose();
- }
- Joomla.Bootstrap.Instances.Modal.set(modal, new Modal(modal, options));
+
+ // eslint-disable-next-line no-new
+ new window.bootstrap.Modal(modal, options);
// Comply with the Joomla API - Bound element.open/close
- modal.open = () => { Joomla.Bootstrap.Instances.Modal.get(modal).show(modal); };
- modal.close = () => { Joomla.Bootstrap.Instances.Modal.get(modal).hide(); };
+ modal.open = () => { window.bootstrap.Modal.getInstance(modal).show(modal); };
+ modal.close = () => { window.bootstrap.Modal.getInstance(modal).hide(); };
// Do some Joomla specific changes
modal.addEventListener('show.bs.modal', () => {
@@ -49,7 +47,8 @@ Joomla.Bootstrap.Initialise.Modal = (modal, options) => {
if (!document.getElementById(idFieldArr[1])) {
// eslint-disable-next-line no-new-func
- el = new Function(idFieldArr[0]); // This is UNSAFE!!!!
+ const fn = new Function(`return ${idFieldArr[0]}`); // This is UNSAFE!!!!
+ el = fn.call(null);
} else {
el = document.getElementById(idFieldArr[1]).value;
}
@@ -135,28 +134,23 @@ Joomla.iframeButtonClick = (options) => {
}
};
-// Ensure vanilla mode, for consistency of the events
-if (!Object.prototype.hasOwnProperty.call(document.body.dataset, 'bsNoJquery')) {
- document.body.dataset.bsNoJquery = '';
-}
-
-// Get the elements/configurations from the PHP
-const modals = Joomla.getOptions('bootstrap.modal');
-// Initialise the elements
-if (typeof modals === 'object' && modals !== null) {
- Object.keys(modals).forEach((modal) => {
- const modalEl = document.querySelector(modal);
- const opt = modals[modal];
- const options = {
- backdrop: opt.backdrop ? opt.backdrop : true,
- keyboard: opt.keyboard ? opt.keyboard : true,
- focus: opt.focus ? opt.focus : true,
- };
-
- if (modalEl) {
- Joomla.Bootstrap.Initialise.Modal(modalEl, options);
- }
- });
+if (Joomla && Joomla.getOptions) {
+ // Get the elements/configurations from the PHP
+ const modals = Joomla.getOptions('bootstrap.modal');
+ // Initialise the elements
+ if (typeof modals === 'object' && modals !== null) {
+ Object.keys(modals).forEach((modal) => {
+ const opt = modals[modal];
+ const options = {
+ backdrop: opt.backdrop ? opt.backdrop : true,
+ keyboard: opt.keyboard ? opt.keyboard : true,
+ focus: opt.focus ? opt.focus : true,
+ };
+
+ Array.from(document.querySelectorAll(modal))
+ .map((modalEl) => Joomla.initialiseModal(modalEl, options));
+ });
+ }
}
export default Modal;
diff --git a/build/media_source/vendor/bootstrap/js/popover.es6.js b/build/media_source/vendor/bootstrap/js/popover.es6.js
index e47c49150d9c8..8402ef4bf05e9 100644
--- a/build/media_source/vendor/bootstrap/js/popover.es6.js
+++ b/build/media_source/vendor/bootstrap/js/popover.es6.js
@@ -1,121 +1,86 @@
import Popover from '../../../../../node_modules/bootstrap/js/src/popover';
import Tooltip from '../../../../../node_modules/bootstrap/js/src/tooltip';
-Joomla = Joomla || {};
-Joomla.Bootstrap = Joomla.Bootstrap || {};
-Joomla.Bootstrap.Initialise = Joomla.Bootstrap.Initialise || {};
-Joomla.Bootstrap.Instances = Joomla.Bootstrap.Instances || {};
-Joomla.Bootstrap.Instances.Popover = new WeakMap();
-Joomla.Bootstrap.Instances.Tooltip = new WeakMap();
+window.bootstrap = window.bootstrap || {};
+window.bootstrap.Popover = Popover;
+window.bootstrap.Tooltip = Tooltip;
-/**
- * Initialise the Popover iteractivity
- *
- * @param {HTMLElement} el The element that will become an popover
- * @param {object} options The options for this popover
- */
-Joomla.Bootstrap.Initialise.Popover = (el, options) => {
- if (!(el instanceof Element)) {
- return;
- }
- if (Joomla.Bootstrap.Instances.Popover.get(el) && el.dispose) {
- el.dispose();
- }
- Joomla.Bootstrap.Instances.Popover.set(el, new Popover(el, options));
-};
-
-/**
- * Initialise the Tooltip iteractivity
- *
- * @param {HTMLElement} el The element that will become an tooltip
- * @param {object} options The options for this tooltip
- */
-Joomla.Bootstrap.Initialise.Tooltip = (el, options) => {
- if (Joomla.Bootstrap.Instances.Tooltip.get(el) && el.dispose) {
- el.dispose();
- }
- Joomla.Bootstrap.Instances.Tooltip.set(el, new Tooltip(el, options));
-};
-
-// Ensure vanilla mode, for consistency of the events
-if (!Object.prototype.hasOwnProperty.call(document.body.dataset, 'bsNoJquery')) {
- document.body.dataset.bsNoJquery = '';
-}
-
-// Get the elements/configurations from the PHP
-const tooltips = Joomla.getOptions('bootstrap.tooltip');
-const popovers = Joomla.getOptions('bootstrap.popover');
-// Initialise the elements
-if (typeof popovers === 'object' && popovers !== null) {
- Object.keys(popovers).forEach((popover) => {
- const opt = popovers[popover];
- const options = {
- animation: opt.animation ? opt.animation : true,
- container: opt.container ? opt.container : false,
- content: opt.content ? opt.content : '',
- delay: opt.delay ? opt.delay : 0,
- html: opt.html ? opt.html : false,
- placement: opt.placement ? opt.placement : 'top',
- selector: opt.selector ? opt.selector : false,
- title: opt.title ? opt.title : '',
- trigger: opt.trigger ? opt.trigger : 'click',
- offset: opt.offset ? opt.offset : 0,
- fallbackPlacement: opt.fallbackPlacement ? opt.fallbackPlacement : 'flip',
- boundary: opt.boundary ? opt.boundary : 'scrollParent',
- customClass: opt.customClass ? opt.customClass : '',
- sanitize: opt.sanitize ? opt.sanitize : true,
- sanitizeFn: opt.sanitizeFn ? opt.sanitizeFn : null,
- popperConfig: opt.popperConfig ? opt.popperConfig : null,
- };
+if (Joomla && Joomla.getOptions) {
+ // Get the elements/configurations from the PHP
+ const tooltips = Joomla.getOptions('bootstrap.tooltip');
+ const popovers = Joomla.getOptions('bootstrap.popover');
+ // Initialise the elements
+ if (typeof popovers === 'object' && popovers !== null) {
+ Object.keys(popovers).forEach((popover) => {
+ const opt = popovers[popover];
+ const options = {
+ animation: opt.animation ? opt.animation : true,
+ container: opt.container ? opt.container : false,
+ content: opt.content ? opt.content : '',
+ delay: opt.delay ? opt.delay : 0,
+ html: opt.html ? opt.html : false,
+ placement: opt.placement ? opt.placement : 'top',
+ selector: opt.selector ? opt.selector : false,
+ title: opt.title ? opt.title : '',
+ trigger: opt.trigger ? opt.trigger : 'click',
+ offset: opt.offset ? opt.offset : 0,
+ fallbackPlacement: opt.fallbackPlacement ? opt.fallbackPlacement : 'flip',
+ boundary: opt.boundary ? opt.boundary : 'scrollParent',
+ customClass: opt.customClass ? opt.customClass : '',
+ sanitize: opt.sanitize ? opt.sanitize : true,
+ sanitizeFn: opt.sanitizeFn ? opt.sanitizeFn : null,
+ popperConfig: opt.popperConfig ? opt.popperConfig : null,
+ };
- if (opt.template) {
- options.template = opt.template;
- }
- if (opt.allowList) {
- options.allowList = opt.allowList;
- }
+ if (opt.template) {
+ options.template = opt.template;
+ }
+ if (opt.allowList) {
+ options.allowList = opt.allowList;
+ }
- const elements = Array.from(document.querySelectorAll(popover));
- if (elements.length) {
- elements.map((el) => Joomla.Bootstrap.Initialise.Popover(el, options));
- }
- });
-}
-// Initialise the elements
-if (typeof tooltips === 'object' && tooltips !== null) {
- Object.keys(tooltips).forEach((tooltip) => {
- const opt = tooltips[tooltip];
- const options = {
- animation: opt.animation ? opt.animation : true,
- container: opt.container ? opt.container : false,
- delay: opt.delay ? opt.delay : 0,
- html: opt.html ? opt.html : false,
- selector: opt.selector ? opt.selector : false,
- trigger: opt.trigger ? opt.trigger : 'hover focus',
- fallbackPlacement: opt.fallbackPlacement ? opt.fallbackPlacement : null,
- boundary: opt.boundary ? opt.boundary : 'clippingParents',
- title: opt.title ? opt.title : '',
- customClass: opt.customClass ? opt.customClass : '',
- sanitize: opt.sanitize ? opt.sanitize : true,
- sanitizeFn: opt.sanitizeFn ? opt.sanitizeFn : null,
- popperConfig: opt.popperConfig ? opt.popperConfig : null,
- };
+ const elements = Array.from(document.querySelectorAll(popover));
+ if (elements.length) {
+ elements.map((el) => new window.bootstrap.Popover(el, options));
+ }
+ });
+ }
+ // Initialise the elements
+ if (typeof tooltips === 'object' && tooltips !== null) {
+ Object.keys(tooltips).forEach((tooltip) => {
+ const opt = tooltips[tooltip];
+ const options = {
+ animation: opt.animation ? opt.animation : true,
+ container: opt.container ? opt.container : false,
+ delay: opt.delay ? opt.delay : 0,
+ html: opt.html ? opt.html : false,
+ selector: opt.selector ? opt.selector : false,
+ trigger: opt.trigger ? opt.trigger : 'hover focus',
+ fallbackPlacement: opt.fallbackPlacement ? opt.fallbackPlacement : null,
+ boundary: opt.boundary ? opt.boundary : 'clippingParents',
+ title: opt.title ? opt.title : '',
+ customClass: opt.customClass ? opt.customClass : '',
+ sanitize: opt.sanitize ? opt.sanitize : true,
+ sanitizeFn: opt.sanitizeFn ? opt.sanitizeFn : null,
+ popperConfig: opt.popperConfig ? opt.popperConfig : null,
+ };
- if (opt.placement) {
- options.placement = opt.placement;
- }
- if (opt.template) {
- options.template = opt.template;
- }
- if (opt.allowList) {
- options.allowList = opt.allowList;
- }
+ if (opt.placement) {
+ options.placement = opt.placement;
+ }
+ if (opt.template) {
+ options.template = opt.template;
+ }
+ if (opt.allowList) {
+ options.allowList = opt.allowList;
+ }
- const elements = Array.from(document.querySelectorAll(tooltip));
- if (elements.length) {
- elements.map((el) => Joomla.Bootstrap.Initialise.Tooltip(el, options));
- }
- });
+ const elements = Array.from(document.querySelectorAll(tooltip));
+ if (elements.length) {
+ elements.map((el) => new window.bootstrap.Tooltip(el, options));
+ }
+ });
+ }
}
export { Tooltip, Popover };
diff --git a/build/media_source/vendor/bootstrap/js/scrollspy.es6.js b/build/media_source/vendor/bootstrap/js/scrollspy.es6.js
index db650453ce118..5f6b90842663d 100644
--- a/build/media_source/vendor/bootstrap/js/scrollspy.es6.js
+++ b/build/media_source/vendor/bootstrap/js/scrollspy.es6.js
@@ -1,52 +1,30 @@
import Scrollspy from '../../../../../node_modules/bootstrap/js/src/scrollspy';
-Joomla = Joomla || {};
-Joomla.Bootstrap = Joomla.Bootstrap || {};
-Joomla.Bootstrap.Initialise = Joomla.Bootstrap.Initialise || {};
-Joomla.Bootstrap.Instances = Joomla.Bootstrap.Instances || {};
-Joomla.Bootstrap.Instances.Scrollspy = new WeakMap();
+window.bootstrap = window.bootstrap || {};
+window.bootstrap.Scrollspy = Scrollspy;
-/**
- * Initialise the Scrollspy iteractivity
- *
- * @param {HTMLElement} el The element that will become a scrollspy
- * @param {object} options The options for this scrollspy
- */
-Joomla.Bootstrap.Initialise.Scrollspy = (el, options) => {
- if (!(el instanceof Element)) {
- return;
- }
- if (Joomla.Bootstrap.Instances.Scrollspy.get(el) && el.dispose) {
- el.dispose();
- }
- Joomla.Bootstrap.Instances.Scrollspy.set(el, new Scrollspy(el, options));
-};
-
-// Ensure vanilla mode, for consistency of the events
-if (!Object.prototype.hasOwnProperty.call(document.body.dataset, 'bsNoJquery')) {
- document.body.dataset.bsNoJquery = '';
-}
-
-// Get the elements/configurations from the PHP
-const scrollspys = Joomla.getOptions('bootstrap.scrollspy');
-// Initialise the elements
-if (typeof scrollspys === 'object' && scrollspys !== null) {
- Object.keys(scrollspys).forEach((scrollspy) => {
- const opt = scrollspys[scrollspy];
- const options = {
- offset: opt.offset ? opt.offset : 10,
- method: opt.method ? opt.method : 'auto',
- };
+if (Joomla && Joomla.getOptions) {
+ // Get the elements/configurations from the PHP
+ const scrollspys = Joomla.getOptions('bootstrap.scrollspy');
+ // Initialise the elements
+ if (typeof scrollspys === 'object' && scrollspys !== null) {
+ Object.keys(scrollspys).forEach((scrollspy) => {
+ const opt = scrollspys[scrollspy];
+ const options = {
+ offset: opt.offset ? opt.offset : 10,
+ method: opt.method ? opt.method : 'auto',
+ };
- if (opt.target) {
- options.target = opt.target;
- }
+ if (opt.target) {
+ options.target = opt.target;
+ }
- const elements = Array.from(document.querySelectorAll(scrollspy));
- if (elements.length) {
- elements.map((el) => Joomla.Bootstrap.Initialise.Scrollspy(el, options));
- }
- });
+ const elements = Array.from(document.querySelectorAll(scrollspy));
+ if (elements.length) {
+ elements.map((el) => new window.bootstrap.Scrollspy(el, options));
+ }
+ });
+ }
}
export default Scrollspy;
diff --git a/build/media_source/vendor/bootstrap/js/tab.es6.js b/build/media_source/vendor/bootstrap/js/tab.es6.js
index 9293cb9df1d34..72a75c823a055 100644
--- a/build/media_source/vendor/bootstrap/js/tab.es6.js
+++ b/build/media_source/vendor/bootstrap/js/tab.es6.js
@@ -1,10 +1,8 @@
import Tab from '../../../../../node_modules/bootstrap/js/src/tab';
-Joomla = Joomla || {};
-Joomla.Bootstrap = Joomla.Bootstrap || {};
-Joomla.Bootstrap.Initialise = Joomla.Bootstrap.Initialise || {};
-Joomla.Bootstrap.Instances = Joomla.Bootstrap.Instances || {};
-Joomla.Bootstrap.Instances.Tab = new WeakMap();
+window.Joomla = window.Joomla || {};
+window.bootstrap = window.bootstrap || {};
+window.bootstrap.Tab = Tab;
/**
* Initialise the Tabs interactivity
@@ -12,13 +10,9 @@ Joomla.Bootstrap.Instances.Tab = new WeakMap();
* @param {HTMLElement} el The element that will become an collapse
* @param {object} options The options for this collapse
*/
-Joomla.Bootstrap.Initialise.Tab = (el, options) => {
+Joomla.initialiseTabs = (el, options) => {
if (!(el instanceof Element) && options.isJoomla) {
- const nSelector = el.split('.')[1];
- if (!nSelector) {
- throw new Error('The selector is invalid, check your PHP side');
- }
- const tab = document.querySelector(`#${nSelector}Content`);
+ const tab = document.querySelector(`${el}Content`);
if (tab) {
const related = Array.from(tab.children);
@@ -30,7 +24,7 @@ Joomla.Bootstrap.Initialise.Tab = (el, options) => {
}
const isActive = element.dataset.active !== '';
- const ul = document.querySelector(`#${nSelector}Tabs`);
+ const ul = document.querySelector(`${el}Tabs`);
if (ul) {
const link = document.createElement('a');
@@ -57,40 +51,26 @@ Joomla.Bootstrap.Initialise.Tab = (el, options) => {
li.appendChild(link);
ul.appendChild(li);
+
+ // eslint-disable-next-line no-new
+ new window.bootstrap.Tab(li);
}
});
}
-
- if (Joomla.Bootstrap.Instances.Tab.get(tab) && tab.dispose) {
- tab.dispose();
- }
-
- Joomla.Bootstrap.Instances.Tab.set(tab, new Tab(tab));
}
} else {
- if (!(el instanceof Element)) {
- return;
- }
- if (Joomla.Bootstrap.Instances.Tab.get(el) && el.dispose) {
- el.dispose();
- }
-
- Joomla.Bootstrap.Instances.Tab.set(el, new Tab(el, options));
+ Array.from(document.querySelectorAll(`${el} a`))
+ .map((tab) => new window.bootstrap.Tab(tab, options));
}
};
-// Ensure vanilla mode, for consistency of the events
-if (!Object.prototype.hasOwnProperty.call(document.body.dataset, 'bsNoJquery')) {
- document.body.dataset.bsNoJquery = '';
-}
-
-// Get the elements/configurations from the PHP
-const tabs = Joomla.getOptions('bootstrap.tabs');
-// Initialise the elements
-if (typeof tabs === 'object' && tabs !== null) {
- Object.keys(tabs).forEach((tab) => {
- Joomla.Bootstrap.Initialise.Tab(tab, tabs[tab]);
- });
+if (Joomla && Joomla.getOptions) {
+ // Get the elements/configurations from the PHP
+ const tabs = Joomla.getOptions('bootstrap.tabs');
+ // Initialise the elements
+ if (typeof tabs === 'object' && tabs !== null) {
+ Object.keys(tabs).map((tab) => Joomla.initialiseTabs(tab, tabs[tab]));
+ }
}
export default Tab;
diff --git a/build/media_source/vendor/bootstrap/js/toast.es6.js b/build/media_source/vendor/bootstrap/js/toast.es6.js
index 4bc561ae8a9e0..25ad63d99cefd 100644
--- a/build/media_source/vendor/bootstrap/js/toast.es6.js
+++ b/build/media_source/vendor/bootstrap/js/toast.es6.js
@@ -1,49 +1,27 @@
import Toast from '../../../../../node_modules/bootstrap/js/src/toast';
-Joomla = Joomla || {};
-Joomla.Bootstrap = Joomla.Bootstrap || {};
-Joomla.Bootstrap.Initialise = Joomla.Bootstrap.Initialise || {};
-Joomla.Bootstrap.Instances = Joomla.Bootstrap.Instances || {};
-Joomla.Bootstrap.Instances.Toast = new WeakMap();
+window.bootstrap = window.bootstrap || {};
+window.bootstrap.Toast = Toast;
-/**
- * Initialise the iteractivity
- *
- * @param {HTMLElement} el The element that will become an toast
- * @param {object} options The options for this toast
- */
-Joomla.Bootstrap.Initialise.Toast = (el, options) => {
- if (!(el instanceof Element)) {
- return;
- }
- if (Joomla.Bootstrap.Instances.Toast.get(el) && el.dispose) {
- el.dispose();
- }
- Joomla.Bootstrap.Instances.Toast.set(el, new Toast(el, options));
-};
-
-// Ensure vanilla mode, for consistency of the events
-if (!Object.prototype.hasOwnProperty.call(document.body.dataset, 'bsNoJquery')) {
- document.body.dataset.bsNoJquery = '';
-}
-
-// Get the elements/configurations from the PHP
-const toasts = Joomla.getOptions('bootstrap.toast');
-// Initialise the elements
-if (typeof toasts === 'object' && toasts !== null) {
- Object.keys(toasts).forEach((toast) => {
- const opt = toasts[toast];
- const options = {
- animation: opt.animation ? opt.animation : true,
- autohide: opt.autohide ? opt.autohide : true,
- delay: opt.delay ? opt.delay : 5000,
- };
+if (Joomla && Joomla.getOptions) {
+ // Get the elements/configurations from the PHP
+ const toasts = Joomla.getOptions('bootstrap.toast');
+ // Initialise the elements
+ if (typeof toasts === 'object' && toasts !== null) {
+ Object.keys(toasts).forEach((toast) => {
+ const opt = toasts[toast];
+ const options = {
+ animation: opt.animation ? opt.animation : true,
+ autohide: opt.autohide ? opt.autohide : true,
+ delay: opt.delay ? opt.delay : 5000,
+ };
- const elements = Array.from(document.querySelectorAll(toast));
- if (elements.length) {
- elements.map((el) => Joomla.Bootstrap.Initialise.Toast(el, options));
- }
- });
+ const elements = Array.from(document.querySelectorAll(toast));
+ if (elements.length) {
+ elements.map((el) => new window.bootstrap.Toast(el, options));
+ }
+ });
+ }
}
export default Toast;
diff --git a/build/media_source/vendor/tinymce/langs/kk.js b/build/media_source/vendor/tinymce/langs/kk.es5.js
similarity index 100%
rename from build/media_source/vendor/tinymce/langs/kk.js
rename to build/media_source/vendor/tinymce/langs/kk.es5.js
diff --git a/build/warning_page/template.css b/build/warning_page/template.css
index 74d5b0dee690a..91d69f52ef633 100644
--- a/build/warning_page/template.css
+++ b/build/warning_page/template.css
@@ -1,3 +1,12 @@
+html {
+ background: #ee2a00;
+ background: -moz-radial-gradient(center, ellipse cover, rgba(241, 241, 241, 1) 0, rgb(238, 42, 0) 100%);
+ background: -webkit-radial-gradient(center, ellipse cover, rgba(241, 241, 241, 1) 0, rgb(238, 42, 0) 100%);
+ background: radial-gradient(ellipse at center, rgba(241, 241, 241, 1) 0, rgb(238, 42, 0) 100%);
+ background-repeat: no-repeat;
+ background-attachment: fixed
+}
+
body {
margin: 0;
padding: 0;
@@ -6,15 +15,6 @@ body {
background-color: transparent
}
-html {
- background: rgb(241,241,241);
- background: -moz-radial-gradient(center, ellipse cover, rgba(241,241,241,1) 0%, rgba(58,146,200,1) 100%);
- background: -webkit-radial-gradient(center, ellipse cover, rgba(241,241,241,1) 0%,rgba(58,146,200,1) 100%);
- background: radial-gradient(ellipse at center, rgba(241,241,241,1) 0%,rgba(58,146,200,1) 100%);
- background-repeat: no-repeat;
- background-attachment: fixed;
-}
-
ol, ul {
padding: 0;
margin: 0;
diff --git a/build/warning_page/template.html b/build/warning_page/template.html
index 95e03353390b2..b490bf9be32d5 100644
--- a/build/warning_page/template.html
+++ b/build/warning_page/template.html
@@ -1,38 +1,37 @@
-
-
-
-
- {{Title}}
-
-
+
+
+
+
+ {{Title}}
+
+
-
+
-
-
-
- {{Description}}
- {{LinkText}}
-
-
-
-
+
+
+
+ {{Description}}
+ {{LinkText}}
+
+
+
+
diff --git a/components/com_config/src/Model/TemplatesModel.php b/components/com_config/src/Model/TemplatesModel.php
index 53562f5047a9f..a2403799e13ec 100644
--- a/components/com_config/src/Model/TemplatesModel.php
+++ b/components/com_config/src/Model/TemplatesModel.php
@@ -55,7 +55,7 @@ public function getForm($data = array(), $loadData = true)
try
{
// Get the form.
- $form = $this->loadForm('com_config.templates', 'templates', array('control' => 'jform', 'load_data' => $loadData));
+ $form = $this->loadForm('com_config.templates', 'templates', array('load_data' => $loadData));
$data = array();
$this->preprocessForm($form, $data);
diff --git a/components/com_contact/src/View/Contact/HtmlView.php b/components/com_contact/src/View/Contact/HtmlView.php
index 90e72aee74b16..957c3adbbe200 100644
--- a/components/com_contact/src/View/Contact/HtmlView.php
+++ b/components/com_contact/src/View/Contact/HtmlView.php
@@ -416,7 +416,6 @@ protected function _prepareDocument()
$app = Factory::getApplication();
$menus = $app->getMenu();
$pathway = $app->getPathway();
- $title = null;
// Because the application sets a default page title,
// we need to get it from the menu item itself
@@ -463,25 +462,12 @@ protected function _prepareDocument()
}
}
- if (empty($title))
- {
- $title = $app->get('sitename');
- }
- elseif ($app->get('sitename_pagetitles', 0) == 1)
- {
- $title = Text::sprintf('JPAGETITLE', $app->get('sitename'), $title);
- }
- elseif ($app->get('sitename_pagetitles', 0) == 2)
- {
- $title = Text::sprintf('JPAGETITLE', $title, $app->get('sitename'));
- }
-
if (empty($title))
{
$title = $this->item->name;
}
- $this->document->setTitle($title);
+ $this->setDocumentTitle($title);
if ($this->item->metadesc)
{
diff --git a/components/com_contact/src/View/Featured/HtmlView.php b/components/com_contact/src/View/Featured/HtmlView.php
index 89e1f233a60de..b8d2674b97742 100644
--- a/components/com_contact/src/View/Featured/HtmlView.php
+++ b/components/com_contact/src/View/Featured/HtmlView.php
@@ -148,13 +148,9 @@ public function display($tpl = null)
*/
protected function _prepareDocument()
{
- $app = Factory::getApplication();
- $menus = $app->getMenu();
- $title = null;
-
// Because the application sets a default page title,
// we need to get it from the menu item itself
- $menu = $menus->getActive();
+ $menu = Factory::getApplication()->getMenu()->getActive();
if ($menu)
{
@@ -165,22 +161,7 @@ protected function _prepareDocument()
$this->params->def('page_heading', Text::_('COM_CONTACT_DEFAULT_PAGE_TITLE'));
}
- $title = $this->params->get('page_title', '');
-
- if (empty($title))
- {
- $title = $app->get('sitename');
- }
- elseif ($app->get('sitename_pagetitles', 0) == 1)
- {
- $title = Text::sprintf('JPAGETITLE', $app->get('sitename'), $title);
- }
- elseif ($app->get('sitename_pagetitles', 0) == 2)
- {
- $title = Text::sprintf('JPAGETITLE', $title, $app->get('sitename'));
- }
-
- $this->document->setTitle($title);
+ $this->setDocumentTitle($this->params->get('page_title', ''));
if ($this->params->get('menu-meta_description'))
{
diff --git a/components/com_contact/tmpl/category/default_items.php b/components/com_contact/tmpl/category/default_items.php
index 95e29e866d7ac..050c2644077af 100644
--- a/components/com_contact/tmpl/category/default_items.php
+++ b/components/com_contact/tmpl/category/default_items.php
@@ -188,7 +188,7 @@ class="inputbox" onchange="document.adminForm.submit();"
params->get('show_pagination', 2)) : ?>
|