diff --git a/.github/ISSUE_TEMPLATE/Feature_request.md b/.github/ISSUE_TEMPLATE/Feature_request.md
new file mode 100644
index 00000000000..3dbbcce8ab9
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/Feature_request.md
@@ -0,0 +1,9 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+
+---
+
+Feature requests should **NOT** be submitted as an issue.
+
+The correct place for a feature request is the Discussion area. More in depth information on the feature request process can be found here: https://github.com/joomla/joomla-cms/discussions/46934
diff --git a/.github/ISSUE_TEMPLATE/Feature_request.yml b/.github/ISSUE_TEMPLATE/Feature_request.yml
deleted file mode 100644
index b837bec63ed..00000000000
--- a/.github/ISSUE_TEMPLATE/Feature_request.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-name: Feature
-description: Suggest an idea for this project
-labels: ["Feature"]
-type: feature
-body:
- - type: markdown
- attributes:
- value: |
- Suggest an idea for this project
- - type: textarea
- id: problem-description
- attributes:
- label: Problem description
- description: Is your feature request related to a problem? Please describe.
- validations:
- required: true
- - type: textarea
- id: solution
- attributes:
- label: Solution
- description: Describe the solution you'd like to suggest
- - type: textarea
- id: additional-context
- attributes:
- label: Additional Context
- description: Additional comments which are important to find the issue
-
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 1a9d6f67917..9f98957d039 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -14,8 +14,8 @@ jobs:
runs-on: ubuntu-latest
container: joomlaprojects/docker-images:php8.4
steps:
- - uses: actions/checkout@v4
- - uses: actions/cache@v4
+ - uses: actions/checkout@v6
+ - uses: actions/cache@v5
id: cache-php
with:
path: libraries/vendor
@@ -39,18 +39,22 @@ jobs:
container: joomlaprojects/docker-images:php8.4
needs: [composer]
steps:
- - uses: actions/setup-node@v4
+ - uses: actions/setup-node@v6
with:
node-version: latest
- - uses: actions/checkout@v4
- - uses: actions/cache@v4
+ - uses: actions/checkout@v6
+ - uses: actions/cache@v5
id: cache-assets
with:
path: |
node_modules
media
- key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json', 'build/media_source/**', 'administrator/components/com_media/resources/**') }}
- - uses: actions/cache/restore@v4
+ installation/template/css
+ installation/template/images
+ installation/template/js
+ installation/template/scss
+ key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json', 'build/build.mjs', 'build/build-modules-js/**', 'media_source/**') }}
+ - uses: actions/cache/restore@v5
with:
path: libraries/vendor
key: ${{ runner.os }}-composer-${{ hashFiles('composer.lock') }}
@@ -71,8 +75,8 @@ jobs:
matrix:
command: ['php-cs-fixer fix -vvv --dry-run --diff', 'phpcs --extensions=php -p --standard=ruleset.xml .']
steps:
- - uses: actions/checkout@v4
- - uses: actions/cache/restore@v4
+ - uses: actions/checkout@v6
+ - uses: actions/cache/restore@v5
with:
path: libraries/vendor
key: ${{ runner.os }}-composer-${{ hashFiles('composer.lock') }}
@@ -94,16 +98,20 @@ jobs:
matrix:
check: ['lint:js', 'lint:testjs', 'lint:css']
steps:
- - uses: actions/setup-node@v4
+ - uses: actions/setup-node@v6
with:
node-version: latest
- - uses: actions/checkout@v4
- - uses: actions/cache/restore@v4
+ - uses: actions/checkout@v6
+ - uses: actions/cache/restore@v5
with:
path: |
node_modules
media
- key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json', 'build/media_source/**', 'administrator/components/com_media/resources/**') }}
+ installation/template/css
+ installation/template/images
+ installation/template/js
+ installation/template/scss
+ key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json', 'build/build.mjs', 'build/build-modules-js/**', 'media_source/**') }}
- name: Check code style
run: npm run ${{ matrix.check }}
@@ -113,8 +121,8 @@ jobs:
container: joomlaprojects/docker-images:php8.4
needs: [code-style-php]
steps:
- - uses: actions/checkout@v4
- - uses: actions/cache/restore@v4
+ - uses: actions/checkout@v6
+ - uses: actions/cache/restore@v5
with:
path: libraries/vendor
key: ${{ runner.os }}-composer-${{ hashFiles('composer.lock') }}
@@ -135,8 +143,8 @@ jobs:
matrix:
php_version: ['8.3', '8.4', '8.5']
steps:
- - uses: actions/checkout@v4
- - uses: actions/cache/restore@v4
+ - uses: actions/checkout@v6
+ - uses: actions/cache/restore@v5
with:
path: libraries/vendor
key: ${{ runner.os }}-composer-${{ hashFiles('composer.lock') }}
@@ -181,12 +189,12 @@ jobs:
host: 'postgres'
user: 'root'
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6
- name: Start LDAP container
uses: docker://docker
with:
args: docker run -d --name openldap --network ${{ job.container.network }} --network-alias openldap -e "LDAP_ADMIN_USERNAME=admin" -e "LDAP_ADMIN_PASSWORD=adminpassword" -e "LDAP_USERS=customuser" -e "LDAP_PASSWORDS=custompassword" -e "LDAP_ENABLE_TLS=yes" -e "LDAP_TLS_CERT_FILE=/certs/openldap.crt" -e "LDAP_TLS_KEY_FILE=/certs/openldap.key" -e "LDAP_TLS_CA_FILE=/certs/CA.crt" -e "BITNAMI_DEBUG=true" -e "LDAP_CONFIG_ADMIN_ENABLED=yes" -e "LDAP_CONFIG_ADMIN_USERNAME=admin" -e "LDAP_CONFIG_ADMIN_PASSWORD=configpassword" -v "${{ github.workspace }}/tests/certs/openldap.crt":"/certs/openldap.crt" -v "${{ github.workspace }}/tests/certs/openldap.key":"/certs/openldap.key" -v "${{ github.workspace }}/tests/certs/CA.crt":"/certs/CA.crt" ghcr.io/joomla-projects/mirror-bitnami-openldap:latest
- - uses: actions/cache/restore@v4
+ - uses: actions/cache/restore@v5
with:
path: libraries/vendor
key: ${{ runner.os }}-composer-${{ hashFiles('composer.lock') }}
@@ -238,8 +246,8 @@ jobs:
matrix:
php_version: ['8.3', '8.4', '8.5']
steps:
- - uses: actions/checkout@v4
- - uses: actions/cache/restore@v4
+ - uses: actions/checkout@v6
+ - uses: actions/cache/restore@v5
id: cache-php-windows
with:
path: libraries/vendor
@@ -269,8 +277,8 @@ jobs:
matrix:
php_version: ['8.3', '8.4', '8.5']
steps:
- - uses: actions/checkout@v4
- - uses: actions/cache/restore@v4
+ - uses: actions/checkout@v6
+ - uses: actions/cache/restore@v5
with:
path: libraries/vendor
key: ${{ runner.os }}-composer-${{ hashFiles('composer.lock') }}
@@ -308,14 +316,18 @@ jobs:
env:
CYPRESS_VERIFY_TIMEOUT: 100000
steps:
- - uses: actions/checkout@v4
- - uses: actions/cache/restore@v4
+ - uses: actions/checkout@v6
+ - uses: actions/cache/restore@v5
with:
path: |
node_modules
media
- key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json', 'build/media_source/**', 'administrator/components/com_media/resources/**') }}
- - uses: actions/cache@v4
+ installation/template/css
+ installation/template/images
+ installation/template/js
+ installation/template/scss
+ key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json', 'build/build.mjs', 'build/build-modules-js/**', 'media_source/**') }}
+ - uses: actions/cache@v5
id: cache-cypress
with:
path: |
@@ -370,12 +382,12 @@ jobs:
env:
JOOMLA_INSTALLATION_DISABLE_LOCALHOST_CHECK: 1
steps:
- - uses: actions/checkout@v4
- - uses: actions/cache/restore@v4
+ - uses: actions/checkout@v6
+ - uses: actions/cache/restore@v5
with:
path: libraries/vendor
key: ${{ runner.os }}-composer-${{ hashFiles('composer.lock') }}
- - uses: actions/cache/restore@v4
+ - uses: actions/cache/restore@v5
with:
path: plugins/system/webauthn/fido.jwt
key: ${{ runner.os }}-webauthn-${{ hashFiles('composer.lock') }}
@@ -384,8 +396,12 @@ jobs:
path: |
node_modules
media
- key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json', 'build/media_source/**', 'administrator/components/com_media/resources/**') }}
- - uses: actions/cache/restore@v4
+ installation/template/css
+ installation/template/images
+ installation/template/js
+ installation/template/scss
+ key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json', 'build/build.mjs', 'build/build-modules-js/**', 'media_source/**') }}
+ - uses: actions/cache/restore@v5
with:
path: |
/root/.cache/Cypress
@@ -394,7 +410,7 @@ jobs:
- name: Run System tests
run: bash tests/System/entrypoint.sh "$(pwd)" ${{ matrix.config.test_group }} ${{ matrix.config.db_engine }} ${{ matrix.config.db_host }} ${{ matrix.browser }}
- name: Archive test results results
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v7
if: always()
with:
name: system-test-output
@@ -427,7 +443,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Actions Repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
- name: Spell Check Repository
uses: crate-ci/typos@v1.34.0
with:
diff --git a/.github/workflows/create-translation-pull-request-v5.yml b/.github/workflows/create-translation-pull-request-v5.yml
index 962a94ec018..22d0ed20921 100644
--- a/.github/workflows/create-translation-pull-request-v5.yml
+++ b/.github/workflows/create-translation-pull-request-v5.yml
@@ -26,13 +26,13 @@ jobs:
if: ${{ github.repository == 'joomla-translation-bot/joomla-cms' && github.ref == 'refs/heads/translation5' }}
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
# We need the full depth to create / update the pull request against the main repo
with:
ref: translation5
fetch-depth: 0
token: ${{ secrets.PAT_WORKFLOW }}
- - uses: actions/setup-node@v5
+ - uses: actions/setup-node@v6
with:
node-version: 24
diff --git a/.github/workflows/create-translation-pull-request-v6.yml b/.github/workflows/create-translation-pull-request-v6.yml
index ec703dd3f28..3e0d29cbcc3 100644
--- a/.github/workflows/create-translation-pull-request-v6.yml
+++ b/.github/workflows/create-translation-pull-request-v6.yml
@@ -12,7 +12,7 @@ on:
env:
JOOMLA_MAJOR_VERSION: 6
- JOOMLA_MINOR_VERSION: '6.0'
+ JOOMLA_MINOR_VERSION: '6.1'
permissions:
contents: read
@@ -26,13 +26,13 @@ jobs:
if: ${{ github.repository == 'joomla-translation-bot/joomla-cms' && github.ref == 'refs/heads/translation6' }}
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
# We need the full depth to create / update the pull request against the main repo
with:
ref: translation6
fetch-depth: 0
- token: ${{ secrets.PAT_WORKFLOW }}
- - uses: actions/setup-node@v5
+ token: ${{ secrets.PAT_WORKFLOW }}
+ - uses: actions/setup-node@v6
with:
node-version: 24
diff --git a/.gitignore b/.gitignore
index 15a8ef72150..84cb6e7be0e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,6 +26,9 @@
# Template CSS files generated by NPM
/installation/template/css
+/installation/template/images
+/installation/template/js
+/installation/template/scss
# Test Related Files
/phpunit.xml
diff --git a/administrator/components/com_associations/tmpl/association/edit.php b/administrator/components/com_associations/tmpl/association/edit.php
index 3a37267c822..a31da3dd72f 100644
--- a/administrator/components/com_associations/tmpl/association/edit.php
+++ b/administrator/components/com_associations/tmpl/association/edit.php
@@ -42,11 +42,11 @@
src="editUri . '&task=' . $this->typeName . '.edit&id=' . (int) $this->referenceId); ?>"
height="400" width="400"
data-action="edit"
- data-item="typeName; ?>"
- data-id="referenceId; ?>"
- data-title="referenceTitle; ?>"
- data-title-value="referenceTitleValue; ?>"
- data-language="referenceLanguage; ?>"
+ data-item="escape($this->typeName); ?>"
+ data-id="escape($this->referenceId); ?>"
+ data-title="escape($this->referenceTitle); ?>"
+ data-title-value="escape($this->referenceTitleValue); ?>"
+ data-language="escape($this->referenceLanguage); ?>"
data-editurl="editUri); ?>">
diff --git a/administrator/components/com_content/src/View/Article/HtmlView.php b/administrator/components/com_content/src/View/Article/HtmlView.php
index ce888e406f8..cdebf91aaca 100644
--- a/administrator/components/com_content/src/View/Article/HtmlView.php
+++ b/administrator/components/com_content/src/View/Article/HtmlView.php
@@ -128,6 +128,9 @@ protected function initializeView()
*/
protected function addToolbar()
{
+ if ($this->getLayout() === 'pagebreak') {
+ return;
+ }
if ($this->getLayout() === 'modal') {
$this->addModalToolbar();
diff --git a/administrator/components/com_fields/src/Model/FieldModel.php b/administrator/components/com_fields/src/Model/FieldModel.php
index 379a4ee09b5..061819f0c23 100644
--- a/administrator/components/com_fields/src/Model/FieldModel.php
+++ b/administrator/components/com_fields/src/Model/FieldModel.php
@@ -111,12 +111,30 @@ public function __construct($config = [], ?MVCFactoryInterface $factory = null)
*/
public function save($data)
{
- $field = null;
+ $field = null;
+ $hasDuplicateSubformFields = false;
if (isset($data['id']) && $data['id']) {
$field = $this->getItem($data['id']);
}
+ $fieldType = $data['type'] ?? ($field->type ?? null);
+
+ if ($fieldType === 'subform' && isset($data['fieldparams']['options']) && \is_array($data['fieldparams']['options'])) {
+ $seenCustomFields = [];
+
+ foreach ($data['fieldparams']['options'] as $option) {
+ $customField = (string) ($option['customfield'] ?? '');
+
+ if (isset($seenCustomFields[$customField])) {
+ $hasDuplicateSubformFields = true;
+ break;
+ }
+
+ $seenCustomFields[$customField] = true;
+ }
+ }
+
if (isset($data['params']['searchindex'])) {
if (\is_null($field)) {
if ($data['params']['searchindex'] > 0) {
@@ -172,6 +190,10 @@ public function save($data)
return false;
}
+ if ($hasDuplicateSubformFields) {
+ Factory::getApplication()->enqueueMessage(Text::_('COM_FIELDS_FIELD_SUBFORM_DUPLICATE_FIELDS_REMOVED'), 'warning');
+ }
+
// Save the assigned categories into #__fields_categories
$db = $this->getDatabase();
$id = (int) $this->getState('field.id');
diff --git a/administrator/components/com_media/tmpl/media/default.php b/administrator/components/com_media/tmpl/media/default.php
index f27642583d6..7a48955d94e 100644
--- a/administrator/components/com_media/tmpl/media/default.php
+++ b/administrator/components/com_media/tmpl/media/default.php
@@ -12,6 +12,7 @@
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory;
+use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\Session\Session;
use Joomla\CMS\Uri\Uri;
@@ -34,6 +35,7 @@
$tmpl = $input->getCmd('tmpl');
$mediaTypes = '&mediatypes=' . $input->getString('mediatypes', '0,1,2,3');
+$hasMediaActionPlugins = !empty(PluginHelper::getPlugin('media-action'));
// Populate the media config
$config = [
@@ -54,6 +56,7 @@
'canCreate' => $user->authorise('core.create', 'com_media'),
'canEdit' => $user->authorise('core.edit', 'com_media'),
'canDelete' => $user->authorise('core.delete', 'com_media'),
+ 'hasMediaActionPlugins' => $hasMediaActionPlugins,
];
$this->getDocument()->addScriptOptions('com_media', $config);
?>
diff --git a/administrator/language/en-GB/com_fields.ini b/administrator/language/en-GB/com_fields.ini
index d2f141ab70b..d262ead0d9a 100644
--- a/administrator/language/en-GB/com_fields.ini
+++ b/administrator/language/en-GB/com_fields.ini
@@ -67,6 +67,7 @@ COM_FIELDS_FIELD_SHOWLABEL_LABEL="Label"
COM_FIELDS_FIELD_SHOWON_DESC="Conditionally show or hide the field depending on the value of other fields."
COM_FIELDS_FIELD_SHOWON_LABEL="Showon Attribute"
COM_FIELDS_FIELD_SMARTSEARCHOPTIONS_HEADING="Smart Search"
+COM_FIELDS_FIELD_SUBFORM_DUPLICATE_FIELDS_REMOVED="Duplicate subform fields were removed. Each field can only be used once."
COM_FIELDS_FIELD_SUFFIX_LABEL="Suffix"
COM_FIELDS_FIELD_TYPE_LABEL="Type"
COM_FIELDS_FIELD_USE_GLOBAL="Use settings from Plugin"
diff --git a/administrator/language/en-GB/plg_editors_codemirror.ini b/administrator/language/en-GB/plg_editors_codemirror.ini
index f5c56021d5b..6409f720fc1 100644
--- a/administrator/language/en-GB/plg_editors_codemirror.ini
+++ b/administrator/language/en-GB/plg_editors_codemirror.ini
@@ -3,15 +3,16 @@
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
+PLG_CODEMIRROR_FIELD_ACTIVELINE_LABEL="Highlight Active Line"
PLG_CODEMIRROR_FIELD_AUTOCLOSEBRACKET_LABEL="Bracket Completion"
PLG_CODEMIRROR_FIELD_CODEFOLDING_LABEL="Code Folding"
PLG_CODEMIRROR_FIELD_CUSTOM_EXTENSIONS_LABEL="Custom Extensions"
PLG_CODEMIRROR_FIELD_CUSTOM_EXTENSIONS_METHOD_DESC="Method name, provided by module for extension initialisation. Or multiple, separated by comma. Eg: bracketMatching (from module @codemirror/language)."
-; deprecated will be removed in 6.0
+; deprecated will be removed in 7.0
PLG_CODEMIRROR_FIELD_CUSTOM_EXTENSIONS_METHOD_DESCR="Method name, provided by module for extension initialisation. Or multiple, separated by comma. Eg: bracketMatching (from module @codemirror/language)."
PLG_CODEMIRROR_FIELD_CUSTOM_EXTENSIONS_METHOD_LABEL="Initialisation Method(s)"
PLG_CODEMIRROR_FIELD_CUSTOM_EXTENSIONS_MODULE_DESC="Relative path to the module file, eg: media/my-assets/js/my-codemirror-module.js. Or module name, eg: @codemirror/language."
-; deprecated will be removed in 6.0
+; deprecated will be removed in 7.0
PLG_CODEMIRROR_FIELD_CUSTOM_EXTENSIONS_MODULE_DESCR="Relative path to the module file, eg: media/my-assets/js/my-codemirror-module.js. Or module name, eg: @codemirror/language."
PLG_CODEMIRROR_FIELD_CUSTOM_EXTENSIONS_MODULE_LABEL="Module File or Module Name"
PLG_CODEMIRROR_FIELD_FULLSCREEN_LABEL="Toggle Fullscreen"
diff --git a/administrator/language/en-GB/plg_system_stats.ini b/administrator/language/en-GB/plg_system_stats.ini
index 60ef4610ae0..72dcb311673 100644
--- a/administrator/language/en-GB/plg_system_stats.ini
+++ b/administrator/language/en-GB/plg_system_stats.ini
@@ -20,7 +20,7 @@ PLG_SYSTEM_STATS_MODE_OPTION_ALWAYS_SEND="Always send"
PLG_SYSTEM_STATS_MODE_OPTION_NEVER_SEND="Never send"
PLG_SYSTEM_STATS_MODE_OPTION_ON_DEMAND="Ask again"
PLG_SYSTEM_STATS_MSG_ALLOW_SENDING_DATA="Enable Joomla Statistics?"
-PLG_SYSTEM_STATS_MSG_JOOMLA_WANTS_TO_SEND_DATA="We want to increase the compatibility of our Joomla! software with our user's server settings. Therefore we need anonymous data from your site to better understand the install base and end user environments. All data is anonymised and only sent to a Joomla! controlled central server. You can change these settings later from Plugins → System - Joomla! Statistics."
+PLG_SYSTEM_STATS_MSG_JOOMLA_WANTS_TO_SEND_DATA="We want to increase the compatibility of our Joomla! software with our users' server settings. Therefore we need anonymous data from your site to better understand the install base and end user environments. All data is anonymised and only sent to a Joomla! controlled central server. You can change these settings later from Plugins → System - Joomla! Statistics."
PLG_SYSTEM_STATS_MSG_WHAT_DATA_WILL_BE_SENT="No identifying data is captured at any point. Select here to review."
PLG_SYSTEM_STATS_RESET_UNIQUE_ID="Reset Unique ID"
PLG_SYSTEM_STATS_SETTING="Setting"
diff --git a/administrator/modules/mod_menu/src/Menu/CssMenu.php b/administrator/modules/mod_menu/src/Menu/CssMenu.php
index 4e930c38e74..0b6fa25f280 100644
--- a/administrator/modules/mod_menu/src/Menu/CssMenu.php
+++ b/administrator/modules/mod_menu/src/Menu/CssMenu.php
@@ -504,7 +504,7 @@ protected function preprocess($parent)
*
* @return void
*
- * @since 6.1.0
+ * @since 5.4.4
*/
protected function setActivePath()
{
diff --git a/api/components/com_config/src/Controller/ApplicationController.php b/api/components/com_config/src/Controller/ApplicationController.php
index 5026eaacc04..9c989c04930 100644
--- a/api/components/com_config/src/Controller/ApplicationController.php
+++ b/api/components/com_config/src/Controller/ApplicationController.php
@@ -57,6 +57,11 @@ public function displayList()
$viewType = $this->app->getDocument()->getType();
$viewLayout = $this->input->get('layout', 'default', 'string');
+ // Access check.
+ if (!$this->allowEdit()) {
+ throw new NotAllowed('JLIB_APPLICATION_ERROR_CREATE_RECORD_NOT_PERMITTED', 403);
+ }
+
try {
/** @var JsonapiView $view */
$view = $this->getView(
@@ -143,4 +148,21 @@ public function edit()
return $this;
}
+
+ /**
+ * Method to check if you can edit an existing record.
+ *
+ * Extended classes can override this if necessary.
+ *
+ * @param array $data An array of input data.
+ * @param string $key The name of the key for the primary key; default is id.
+ *
+ * @return boolean
+ *
+ * @since 5.4.4
+ */
+ protected function allowEdit($data = [], $key = 'id')
+ {
+ return $this->app->getIdentity()->authorise('core.admin', $this->option);
+ }
}
diff --git a/api/components/com_joomlaupdate/src/Controller/UpdatesController.php b/api/components/com_joomlaupdate/src/Controller/UpdatesController.php
index b517a7c7341..439ca639559 100644
--- a/api/components/com_joomlaupdate/src/Controller/UpdatesController.php
+++ b/api/components/com_joomlaupdate/src/Controller/UpdatesController.php
@@ -96,8 +96,11 @@ public function finalizeUpdate()
{
$this->validateUpdateToken();
- $fromVersion = $this->input->json->getString('fromVersion', null);
- $updateFileName = $this->input->json->getString('updateFileName', null);
+ $fromVersion = $this->input->json->getString('fromVersion', '');
+ $updateFileName = $this->input->json->getString('updateFileName', '');
+
+ // Sanitize provided file name
+ $updateFileName = pathinfo($updateFileName, PATHINFO_BASENAME);
$view = $this->prepareView();
diff --git a/build/README.md b/build/README.md
index d9509e73624..a878fe93a0a 100644
--- a/build/README.md
+++ b/build/README.md
@@ -6,65 +6,32 @@ Joomla provides a set of tools for managing static assets and dependencies based
The responsibilities of these tools are:
- To copy files from the `node-modules` folder to the `media` folder.
- Do any transformations on the copied files.
-- Update the version numbers on the XML files of the TinyMCE and CodeMirror editors.
-- Copy files from the `build/media_source` folder to the `media` folder.
+- Copy files from the `media_source/` folder to the `media` folder.
- Transform any modern JS to ES2017 and transpile it to ES5.
- Transform any SCSS file to the respective CSS file.
For some of these operations, conventions were established to simplify and speed up the process.
-## Javascript
-There are three options here:
-- Modern Javascript files must have an extension `.es6.js`.
- This allows ESLint to check the code style, Joomla is using the Airbnb preset https://github.com/airbnb/javascript.
- It also instructs Rollup to do the transforms for ES2017. This step creates both normal and minified files.
- Production code WILL NOT have the `.es6` part for ES2017+ files.
+Read more at [CMS Media source](../media_source/README.md).
-- Web Component Javascript files must have an extension `.w-c.es6.js`.
- This allows ESLint to check the code style and instructs Rollup to do the transforms for ES2017. This step creates normal and minified files. The difference with the `.es6` files is that the tools will automate the minification of the CSS (assuming that the appropriate SCSS file exists), which is then injected into the JS file in place of the placeholder `{{CSS_CONTENTS_PLACEHOLDER}}` (ie: `build/media_source/system/js/joomla-core-loader.w-c.es6.js`)
- Production code WILL NOT have the `.w-c.es6` part for ES2017+.
-- Legacy Javascript files must have an extension `.es5.js`.
- This instructs ESLint to skip checking this file.
- Also, it instructs the tools to create a minified version (production code WILL NOT have the `.es5` part)
-
-- Javascript files with only an extension `.js`.
- These files will be ignored by the build tools.
-
-## SCSS
-- SCSS files starting with `_` will not become entry points for SCSS.
- SCSS files will be transformed to CSS, both normal and minified versions.
-
-## CSS
-- CSS files will only get minified.
+## NPM Commands
+- `npm run builders-list` Show list of available builders in order of execution.
+- `npm run build` Build assets with production env. Extra arguments are required. Check [CMS Media source](../media_source/README.md#building-assets).
+- `npm run build:dev` Build assets with development env. Extra arguments are required. Check [CMS Media source](../media_source/README.md#building-assets).
+- `npm run watch` Start files watcher for specified asset with production env. Example `npm run watch -- -n com_content` for `com_content` assets.
+- `npm run watch:dev` Start files watcher for specified asset with development env.
+- `npm run lint:js` Checks the code style for the JavaScript/Vue files
+- `npm run lint:testjs` Checks the code style for the JavaScript/Vue files under `tests/System` used for testing.
+- `npm run lint:css` Checks the code style for all SCSS files.
+- `npm run gzip` Creates `.gz` files for all the `.min.js` and `.min.css`.
-## NPM Commands
-- `npm run build:js`: compiles ALL the JS (excluding Bootstrap and Media Manager).
-- `npm run build:js -- build/media_source/com_actionlogs`: compiles ALL the JS ONLY in the folder `build/media_source/com_actionlogs`.
-- `npm run build:css`: compiles ALL the SCSS.
-- `npm run build:css -- templates/cassiopeia`: compiles ALL the SCSS ONLY in the folder `templates/cassiopeia`.
-- `npm run build:bs5`: Builds the Bootstrap Javascript components.
-- `npm run build:com_media`: Builds the Media Manager Vue Application.
-- `npm run build:com_media:dev`: Builds the Media Manager Vue Application but in DEV mode, (no minification, no es5 and all flags for the vue devtools)
-- `npm run lint:js`: Checks the code style for all the Javascript/Vue files.
-- `npm run lint:js -- --fix`: Checks and fixes the code style for all the Javascript/Vue files (might not fix everything).
-- `npm run lint:css`: Checks the code style for all SCSS files.
-- `npm run lint:css -- --fix`: Checks and fixes the code style for all SCSS files (might not fix everything).
-- `npm run gzip`: Creates `.gz` files for all the `.min.js` and `.min.css`.
-- `npm run versioning`: Creates the correct version hash for all the assets inside the joomla.asset.json files (excluding templates).
## Working Efficiently with the Joomla Build Tools
Usually, the scope of a single contribution to the project should be limited. For example: fixing a CSS bug, a Javascript bug, some Markup, or a bug that involves changes in all these areas. The build tools were created so that you spend less time on compiling assets than testing a possible solution.
-*Embrace the watchers*
-Let the computer help you succeed faster and safer. There are 2 watchers at the moment: one for the Media Manager (client app based on VueJS) and another one that handles templates and the source (build) folder.
-
-Assuming that you are working on the Media Manager, you can run in your terminal (already in the root folder of the Joomla repo) `npm run watch:com_media`. This watcher will automatically recompile the app on every save (there is a debounce of 0.3s, so if you have autosave it will be a clever way to minimise the wait).
-
-Assuming that you are working on the Web Authentication JavaScript, you can run in your terminal (already in the root folder of the Joomla repo) `npm run watch -- build/media_source/plg_system_webauthn`. This watcher will automatically recompile any JavaScript file inside the folder `build/media_source/plg_system_webauthn/js` on every save. But there's more! Since you asked the watcher to check the parent folder (eg `build/media_source/plg_system_webauthn`), you can also edit the SCSS files in the `build/media_source/plg_system_webauthn/scss` or the CSS files in `build/media_source/plg_system_webauthn/css`. The same example for editing some SCSS in the Cassiopeia template would require a command like: `npm run watch -- templates/cassiopeia/scss`.
-
Once you get your code doing what it is meant to do, make sure that you check you are not breaking any of the Code Style rules by running `npm run lint:css -- --fix` and `npm run lint:js -- --fix` (the `-- --fix` will try to fix anything that's not trivial).
Happy coding
diff --git a/build/build-modules-js/builder/builder-factory.mjs b/build/build-modules-js/builder/builder-factory.mjs
new file mode 100644
index 00000000000..28fddecc833
--- /dev/null
+++ b/build/build-modules-js/builder/builder-factory.mjs
@@ -0,0 +1,79 @@
+/**
+ * Builder factory class
+ */
+import path from 'node:path';
+import fs from 'node:fs';
+import DefaultModuleBuilder from './default-module-builder.mjs';
+
+export class BuilderFactory{
+ constructor(basePath = '', targetPath = '', cmdOptions = {}) {
+ this.basePath = basePath;
+ this.targetPath = targetPath;
+ this.cmdOptions = cmdOptions;
+ }
+
+ async createBuilder(name) {
+ // Module path
+ let modulePath = path.join(this.basePath, name, 'builder.mjs');
+
+ // Check if we have the builder module
+ if (!fs.existsSync(modulePath)) {
+ // Use default module
+ return new DefaultModuleBuilder(name, this.basePath, this.targetPath, this.cmdOptions);
+ }
+
+ return import(modulePath).then((module) => {
+ return new module.default(name, this.basePath, this.targetPath, this.cmdOptions);
+ });
+ }
+}
+
+/**
+ * Create and run the builder
+ *
+ * @param { Command } program
+ * @param { String } name
+ * @param { BuilderFactory } factory
+ * @param { string[] } tasksToRun
+ * @param { boolean } skipUndefinedTask
+ * @return { Promise }
+ */
+export const createAndRunBuilder = async (program, name, factory, tasksToRun = [], skipUndefinedTask = false) => {
+ return factory.createBuilder(name)
+ .then((builder) => {
+ if (!builder.getBuildTasks) {
+ program.error(`Builder module for "${name}" should provide "getBuildTasks()" method. This is used to determine which task can be run for the builder.`)
+ }
+ console.log(`Initialize build [${name}]`);
+
+ // Run tasks for given builder
+ const allTasks = builder.getAllTasks ? builder.getAllTasks() : builder.getBuildTasks();
+ let lastPromise = Promise.resolve();
+ (tasksToRun.length ? tasksToRun : builder.getBuildTasks()).forEach((taskName) => {
+ // Check whether the task is allowed for active builder
+ if (!allTasks.includes(taskName)) {
+ // Show error when the builder and the task was specified, and it is not applicable for active builder.
+ if (!skipUndefinedTask) {
+ program.error(`Task "${taskName}" is not applicable for "${name}" builder.`);
+ }
+ return;
+ }
+
+ // Execute the task sequentially, this is needed because task may depend on each other
+ lastPromise = lastPromise.then(() => {
+ console.log(`Start task [${name}::${taskName}]`);
+
+ return builder[taskName]().then(async () => {
+ console.log('\x1b[32m%s\x1b[0m', `Completed task [${name}::${taskName}]`);
+ }).catch((error) => {
+ console.log('\x1b[31m%s\x1b[0m', `Failed Task [${name}::${taskName}]`);
+ console.trace(error);
+ program.error(error.message);
+ });
+ });
+ });
+ return lastPromise;
+ }).then(() => {
+ console.log('\x1b[32m%s\x1b[0m', `Completed build [${name}]`);
+ });
+};
diff --git a/build/build-modules-js/builder/default-module-builder.mjs b/build/build-modules-js/builder/default-module-builder.mjs
new file mode 100644
index 00000000000..f66ae5588b6
--- /dev/null
+++ b/build/build-modules-js/builder/default-module-builder.mjs
@@ -0,0 +1,305 @@
+/**
+ * Default Assets Builder
+ */
+
+import fs from 'node:fs';
+import fsp from 'node:fs/promises';
+import path, { sep } from 'node:path';
+import chokidar from 'chokidar';
+import { handleCSSFile } from '../stylesheets/css-handler.mjs';
+import { handleSCSSFile } from '../stylesheets/scss-handler.mjs';
+import { handleMJSFile, handleJSFile } from "../javascript/js-handle.mjs";
+import { compressFileAndSave } from '../utils/compressFile.mjs';
+
+export default class DefaultModuleBuilder{
+
+ /**
+ * List of tasks to be executed by default for the build process.
+ * Basically list all of the class methods that are allowed to be called from CLI.
+ *
+ * @type {string[]}
+ */
+ tasksBuild = ['clear', 'copy', 'css', 'js'];
+
+ /**
+ * List of extra tasks that the builder can run, but which are not executed during the build process.
+ *
+ * @type {string[]}
+ */
+ tasksExtras = ['gzip'];
+
+ /**
+ * Class constructor.
+ *
+ * @param { string } name The folder (builder) name. Relative to media/.
+ * @param { string } basePath Base path to the media source, without builder name.
+ * @param { string } targetPath Path to the media target, without builder name.
+ * @param { object } options Options object, from cmd or etc.
+ */
+ constructor(name = '', basePath = '', targetPath = '', options = {}) {
+ if (!name) {
+ throw new Error(`Argument "name" is required for ModuleBuilder.`);
+ }
+
+ if (!basePath || !targetPath) {
+ throw new Error(`Arguments "basePath" and "targetPath" is required for "${name}" ModuleBuilder.`);
+ }
+
+ this.name = name;
+ this.basePath = path.join(basePath, name);
+ this.targetPath = path.join(targetPath, name);
+ this.options = options;
+ }
+
+ getAllTasks() {
+ return [ ...this.tasksBuild, ...this.tasksExtras ];
+ }
+
+ getBuildTasks() {
+ return this.tasksBuild;
+ }
+
+ /**
+ * Remove files on target location
+ * @returns { Promise }
+ */
+ async clear() {
+ if (!fs.existsSync(this.targetPath)) {
+ return;
+ }
+
+ return fsp.rm(this.targetPath, { recursive: true });
+ }
+
+ /**
+ * Copy files to target location.
+ * Skip:
+ * - css and js files
+ * - build.mjs and src/ and folders contain builder.mjs or .buildignore
+ *
+ * @returns { Promise }
+ */
+ async copy() {
+ const ignoreName = {
+ 'builder.mjs': true,
+ 'src': true,
+ '.buildignore': true,
+ };
+ const ignoreExt = {
+ '.js': true,
+ '.css': true,
+ }
+
+ const filterFunc = (src, dest) => {
+ if (dest === this.targetPath) {
+ return true;
+ }
+
+ const baseName = path.basename(src);
+ const fileStat = fs.statSync(src);
+
+ // Skip ignored files/folders
+ if (ignoreName[baseName]) {
+ return false;
+ }
+
+ // Skip files with extensions
+ if (fileStat.isFile() && ignoreExt[path.extname(baseName)]){
+ return false;
+ }
+
+ // Skip folders for child modules or explicitly ignored
+ if (fs.existsSync(path.join(src, 'builder.mjs')) || fs.existsSync(path.join(src, '.buildignore'))) {
+ return false;
+ }
+
+ return true;
+ };
+
+ return fsp.cp(this.basePath, this.targetPath, { filter: filterFunc, recursive: true });
+ }
+
+ /**
+ * Process CSS files
+ * @returns { Promise }
+ */
+ async css() {
+ // Collect files
+ const cssFiles = [];
+ const scssFiles = [];
+
+ return fsp.readdir(this.basePath, { recursive: true, withFileTypes: true })
+ .then((files) => {
+ // Filter and handle the files
+ files.forEach((file) => {
+ if (!file.isFile()) return;
+
+ const baseName = file.name;
+ const ext = path.extname(baseName);
+ const fullSrcPath = path.join(file.parentPath, file.name);
+ const relativePath = fullSrcPath.replace(this.basePath, '');
+
+ // Ignore paths from src/ those requiring custom builder
+ if (relativePath.includes(`${sep}src${sep}`)) return;
+
+ if (ext === '.css' && !baseName.endsWith('.min.css')){
+ // Handle the CSS file
+ cssFiles.push(handleCSSFile(
+ fullSrcPath,
+ path.join(this.targetPath, relativePath))
+ );
+ } else if (ext === '.scss' && baseName[0] !== '_') {
+ // Handle the SCSS file
+ scssFiles.push(handleSCSSFile(
+ fullSrcPath,
+ path.join(this.targetPath, relativePath.replace(`${sep}scss${sep}`, `${sep}css${sep}`).replace('.scss', '.css')),
+ this.options.sassSilent
+ ));
+ }
+ });
+
+ return Promise.all([...cssFiles, ...scssFiles]);
+ });
+ }
+
+ /**
+ * Process JavaScript files and Modules
+ * @returns { Promise }
+ */
+ async js() {
+ // Collect files
+ const jsFiles = [];
+ const mjsFiles = [];
+
+ return fsp.readdir(this.basePath, { recursive: true, withFileTypes: true })
+ .then((files) => {
+ // Filter and handle the files
+ files.forEach((file) => {
+ if (!file.isFile()) return;
+
+ const baseName = file.name;
+ const ext = path.extname(baseName);
+ const fullSrcPath = path.join(file.parentPath, file.name);
+ const relativePath = fullSrcPath.replace(this.basePath, '');
+
+ // Ignore paths from src/ those requiring custom builder
+ if (relativePath.includes(`${sep}src${sep}`)) return;
+
+ // Pick only js files
+ if ((ext !== '.js' && ext !== '.mjs') || baseName.endsWith('.min.js')) return;
+
+ if (baseName === 'builder.mjs') {
+ // Ignore builders of active asset, which is in the root of the asset folder
+ if (relativePath.replace('/', '').replace('\\', '') === 'builder.mjs') {
+ return;
+ }
+
+ // This should never happen
+ throw new Error(`Trying to build script from another builder "${fullSrcPath}". Make sure that each builder is separated.`);
+ }
+
+ if ((ext === '.mjs' || baseName.endsWith('.es6.js') || baseName.endsWith('.w-c.es6.js')) && !baseName.startsWith('_')) {
+ mjsFiles.push(handleMJSFile(
+ fullSrcPath,
+ path.join(this.targetPath, relativePath.replace(/\.w-c\.es6\.js$/, '.js').replace(/\.es6\.js$/, '.js'))
+ ));
+ } else {
+ jsFiles.push(handleJSFile(
+ fullSrcPath,
+ path.join(this.targetPath, relativePath.replace(/\.es5\.js$/, '.js'))
+ ));
+ }
+ });
+
+ return Promise.all([...jsFiles, ...mjsFiles]);
+ });
+ }
+
+ /**
+ * Create compressed (gzip) .css/.js files
+ * @returns { Promise }
+ */
+ async gzip() {
+ return fsp.readdir(this.targetPath, { recursive: true, withFileTypes: true }).then((files) => {
+ const promises = [];
+
+ files.forEach((file) => {
+ if (!file.isFile()) return;
+
+ const fullSrcPath = path.join(file.parentPath, file.name);
+
+ // Compress only minified
+ if (!file.name.endsWith('.min.js') && !file.name.endsWith('.min.css')) return;
+
+ promises.push(compressFileAndSave(fullSrcPath));
+ });
+
+ return Promise.all(promises);
+ });
+ }
+
+ /**
+ * Watch handler
+ * @returns { Promise }
+ */
+ async watch() {
+ const watcher = chokidar.watch(this.basePath, {
+ ignored: /(^|[/\\])\../, // ignore dotfiles
+ persistent: true,
+ ignoreInitial: true,
+ });
+
+ // Rebuild everything
+ const rebuild = () => {
+ console.log(`Watcher rebuild everything in [${this.name}]...`);
+
+ const buildTasks = this.getBuildTasks();
+ const nextTask = () => {
+ if (!buildTasks.length) return;
+ const task = buildTasks.shift();
+
+ return this[task]().then(() => nextTask());
+ }
+ return nextTask();
+ };
+ // Wait for initial rebuild
+ await rebuild();
+
+ // File type checker
+ let lastPromise = Promise.resolve();
+ const checkFile = (file) => {
+ const ext = path.extname(file);
+
+ switch (ext) {
+ case '.css':
+ case '.scss':
+ console.log(`Watcher updating css/scss for [${this.name}]...`);
+ lastPromise = lastPromise.then(() => this.css().catch((error) => {
+ console.error(`Watcher for [${this.name}] got an error:`);
+ console.error(error);
+ }));
+ break;
+
+ case '.js':
+ case '.vue':
+ console.log(`Watcher updating js for [${this.name}]...`);
+ lastPromise = lastPromise.then(() => this.js().catch((error) => {
+ console.error(`Watcher for [${this.name}] got an error:`);
+ console.error(error);
+ }));
+ break;
+
+ default:
+ console.log(`Watcher updating static files for [${this.name}]...`);
+ lastPromise = lastPromise.then(() => this.copy());
+ break;
+ }
+ };
+
+ // Go and watch
+ watcher
+ .on('add', checkFile)
+ .on('change', checkFile)
+ .on('unlink', rebuild);
+ }
+}
diff --git a/build/build-modules-js/builders-registry.mjs b/build/build-modules-js/builders-registry.mjs
new file mode 100644
index 00000000000..2df2aa2339f
--- /dev/null
+++ b/build/build-modules-js/builders-registry.mjs
@@ -0,0 +1,107 @@
+/**
+ * Builders registry for Media resources
+ */
+
+// List of media resources. A folder (extension) name under media_source/
+// By default, is used DefaultModuleBuilder class.
+// However, each resource may have own builder.mjs script, for this it should be placed in root of its folder.
+export const builders = [
+ // Libraries
+ 'vendor', // Many extensions depending on it, should be run first
+ 'system',
+ 'vendor/bootstrap', // Customised bootstrap
+ 'vendor/jquery', // jQuery extras
+ 'vendor/short-and-sweet', // Customised short-and-sweet
+ 'layouts',
+ 'legacy',
+ 'mailto',
+
+ // Components
+ 'cache',
+ 'com_actionlogs',
+ 'com_admin',
+ 'com_associations',
+ 'com_banners',
+ 'com_cache',
+ 'com_categories',
+ 'com_config',
+ 'com_contact',
+ 'com_content',
+ 'com_contenthistory',
+ 'com_cpanel',
+ 'com_fields',
+ 'com_finder',
+ 'com_guidedtours',
+ 'com_installer',
+ 'com_joomlaupdate',
+ 'com_languages',
+ 'com_mails',
+ 'com_media',
+ 'com_menus',
+ 'com_modules',
+ 'com_scheduler',
+ 'com_tags',
+ 'com_templates',
+ 'com_users',
+ 'com_workflow',
+ 'com_wrapper',
+
+ // Modules
+ 'mod_articles',
+ 'mod_articles_news',
+ 'mod_languages',
+ 'mod_login',
+ 'mod_menu',
+ 'mod_quickicon',
+ 'mod_sampledata',
+
+ // Plugins
+ 'plg_behaviour_compat6',
+ 'plg_content_vote',
+ 'plg_editors-xtd_image',
+ 'plg_editors_codemirror',
+ 'plg_editors_none',
+ 'plg_editors_tinymce',
+ 'plg_installer_folderinstaller',
+ 'plg_installer_packageinstaller',
+ 'plg_installer_urlinstaller',
+ 'plg_installer_webinstaller',
+ 'plg_media-action_crop',
+ 'plg_media-action_resize',
+ 'plg_media-action_rotate',
+ 'plg_multifactorauth_email',
+ 'plg_multifactorauth_fixed',
+ 'plg_multifactorauth_totp',
+ 'plg_multifactorauth_webauthn',
+ 'plg_multifactorauth_yubikey',
+ 'plg_quickicon_autoupdate',
+ 'plg_quickicon_eos',
+ 'plg_quickicon_extensionupdate',
+ 'plg_quickicon_joomlaupdate',
+ 'plg_quickicon_overridecheck',
+ 'plg_quickicon_privacycheck',
+ 'plg_system_debug',
+ 'plg_system_guidedtours',
+ 'plg_system_jooa11y',
+ 'plg_system_schedulerunner',
+ 'plg_system_shortcut',
+ 'plg_system_stats',
+ 'plg_system_webauthn',
+ 'plg_user_token',
+
+ // Templates
+ 'templates/administrator/atum',
+ 'templates/site/cassiopeia',
+ 'templates/site/cassiopeia_extended',
+ 'installation/template',
+
+ // Additional builders, which are not distributed under media/
+ 'error-pages',
+];
+
+// Builders which should be completed before any following builder starts.
+// Used for mass-execution to prevent collisions.
+export const blockingBuilders = [
+ 'vendor', // Blocking many extensions depending on it
+ 'system', // Blocking because 'error-pages' writes in to the same folder, so 'system' should be completed before that
+];
diff --git a/build/build-modules-js/command/build-command.mjs b/build/build-modules-js/command/build-command.mjs
new file mode 100644
index 00000000000..90525372d65
--- /dev/null
+++ b/build/build-modules-js/command/build-command.mjs
@@ -0,0 +1,88 @@
+/**
+ * Build command module
+ */
+
+import path from 'node:path';
+import { BuilderFactory, createAndRunBuilder } from '../builder/builder-factory.mjs';
+
+/**
+ * Build command:
+ * build -a
+ * build -n builder1,builder2
+ * build -t css,js
+ * build -n builder1,builder2 -t css,js
+ *
+ * @param { Command } program CMD program instance
+ * @param { Object } cmdOptions Command options and arguments
+ * @param { Array } builders List of builder names
+ * @param { Array } blockingBuilders List of blocking builder names
+ *
+ * @return { Promise }
+ */
+export default async function buildCommand(program, cmdOptions = {}, builders = [], blockingBuilders = []) {
+ // Get list of builders to run
+ let buildersToRun = [];
+ let runAll = false;
+ if (cmdOptions.all) {
+ runAll = true;
+ buildersToRun = builders;
+ } else if (cmdOptions.name) {
+ cmdOptions.name.split(',').forEach((name) => {
+ // Check if builder exists
+ if (!builders.includes(name)) {
+ program.error(`Builder "${name}" does not exists.`);
+ }
+ buildersToRun.push(name);
+ });
+ }
+
+ // Get list of tasks to run
+ let tasksToRun = [];
+ if (cmdOptions.task) {
+ cmdOptions.task.split(',').forEach((name) => {
+ tasksToRun.push(name);
+ });
+ }
+
+ if (!buildersToRun.length) {
+ console.log('Nothing to run. Please specify the builder name or use -a to run all builders.');
+ return;
+ }
+
+ const factory = new BuilderFactory(
+ path.resolve('./media_source'),
+ path.resolve('./media'),
+ cmdOptions,
+ );
+
+ // Create builder queue
+ const queue = [];
+ buildersToRun.forEach((name) => {
+ queue.push([
+ name,
+ blockingBuilders.includes(name),
+ ]);
+ });
+
+ // Go through queue and execute each builder.
+ // The blocking builder will halt Queue lookup.
+ const danglingPromises = [];
+ const checkQueue = async () => {
+ if (!queue.length) return;
+ const [ name, isBlocking ] = queue.shift();
+
+ if (isBlocking) {
+ // Halt Queue lookup until the builder completes
+ return createAndRunBuilder(program, name, factory, tasksToRun, runAll).then(() => checkQueue())
+ }
+
+ // Collect dangling promises to be sure all are resolved in the end
+ danglingPromises.push(createAndRunBuilder(program, name, factory, tasksToRun, runAll));
+
+ return checkQueue();
+ };
+
+ return checkQueue().then(() => {
+ return Promise.all(danglingPromises);
+ });
+};
diff --git a/build/build-modules-js/command/watch-command.mjs b/build/build-modules-js/command/watch-command.mjs
new file mode 100644
index 00000000000..fb07504f9ac
--- /dev/null
+++ b/build/build-modules-js/command/watch-command.mjs
@@ -0,0 +1,51 @@
+/**
+ * Watch command module
+ */
+import path from 'node:path';
+import { BuilderFactory } from '../builder/builder-factory.mjs';
+
+
+export default async function watchCommand(program, cmdOptions = {}, builders = []) {
+ let buildersToWatch = [];
+
+ if (cmdOptions.name) {
+ cmdOptions.name.split(',').forEach((name) => {
+ // Check if builder exists
+ if (!builders.includes(name)) {
+ program.error(`Builder "${name}" does not exists.`);
+ }
+ buildersToWatch.push(name);
+ });
+ }
+
+ if (!buildersToWatch.length) {
+ console.log('Nothing to watch. Please specify the builder name to watch.');
+ return;
+ }
+
+ const factory = new BuilderFactory(
+ path.resolve('./media_source'),
+ path.resolve('./media'),
+ cmdOptions,
+ );
+
+ const watchers = [];
+ buildersToWatch.forEach((name) => {
+ const watcher = factory.createBuilder(name)
+ .then((builder) => {
+ if (!builder.watch) {
+ program.error(`Builder module for "${name}" should implement "watch()" method.`)
+ }
+ console.log(`Initialize watch [${name}]`);
+
+ return builder.watch().catch((error) => {
+ console.log('\x1b[31m%s\x1b[0m', `Failed Watch [${name}]`);
+ console.trace(error);
+ program.error(error.message);
+ });
+ });
+ watchers.push(watcher);
+ });
+
+ return Promise.all(watchers);
+};
diff --git a/build/build-modules-js/compilecss.mjs b/build/build-modules-js/compilecss.mjs
deleted file mode 100644
index f1caa3758c8..00000000000
--- a/build/build-modules-js/compilecss.mjs
+++ /dev/null
@@ -1,88 +0,0 @@
-import { sep } from 'node:path';
-
-import recursive from 'recursive-readdir';
-import pkg from 'fs-extra';
-
-import { handleScssFile } from './stylesheets/handle-scss.mjs';
-import { handleCssFile } from './stylesheets/handle-css.mjs';
-
-const { stat } = pkg;
-const RootPath = process.cwd();
-
-/**
- * Method that will crawl the media_source folder
- * and compile any scss files to css and .min.css
- * copy any css files to the appropriate destination and
- * minify them in place
- *
- * Expects scss files to have ext: .scss
- * css files to have ext: .css
- * Ignores scss files that their filename starts with `_`
- *
- * @param {object} options The options
- * @param {string} path The folder that needs to be compiled, optional
- */
-export const stylesheets = async (options, path) => {
- const files = [];
- let folders = [];
-
- if (path) {
- const stats = await stat(`${RootPath}/${path}`);
-
- if (stats.isDirectory()) {
- folders.push(`${RootPath}/${path}`);
- } else if (stats.isFile()) {
- files.push(`${RootPath}/${path}`);
- } else {
- console.error(`Unknown path ${path}`);
- process.exitCode = 1;
- }
- } else {
- folders = [
- `${RootPath}/build/media_source`,
- `${RootPath}/templates`,
- `${RootPath}/administrator/templates`,
- `${RootPath}/installation/template`,
- `${RootPath}/media/vendor/debugbar`,
- ];
- }
-
- const folderPromises = [];
-
- // Loop to get the files that should be compiled via parameter
- for (const folder of folders) {
- folderPromises.push(recursive(folder, ['!*.+(scss|css)']));
- }
-
- const computedFiles = await Promise.all(folderPromises);
-
- const cssFilesPromises = [];
- const scssFilesPromises = [];
-
- // 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);
- }
- });
-
- 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));
- }
-
- return Promise.all([...cssFilesPromises, ...scssFilesPromises]);
-};
diff --git a/build/build-modules-js/compilejs.mjs b/build/build-modules-js/compilejs.mjs
deleted file mode 100644
index e8c4c2644ec..00000000000
--- a/build/build-modules-js/compilejs.mjs
+++ /dev/null
@@ -1,74 +0,0 @@
-import { stat } from 'node:fs/promises';
-import { sep } from 'node:path';
-
-import recursive from 'recursive-readdir';
-
-import { handleES5File } from './javascript/handle-es5.mjs';
-import { handleESMFile } from './javascript/compile-to-es2017.mjs';
-
-const RootPath = process.cwd();
-
-/**
- * Method that will crawl the media_source folder and
- * compile ES6 to ES5 and ES6
- * copy any ES5 files to the appropriate destination and
- * minify them in place
- * compile any custom elements/webcomponents
- *
- * Expects ES6 files to have ext: .es6.js
- * ES5 files to have ext: .es5.js
- * WC/CE files to have ext: .w-c.es6.js
- *
- * @param { object } options The options from settings.json
- * @param { string } path The folder that needs to be compiled, optional
- * @param { string } mode esm for ES2017, es5 for ES5, both for both
- */
-export const scripts = async (options, path) => {
- const files = [];
- let folders = [];
-
- if (path) {
- const stats = await stat(`${RootPath}/${path}`);
-
- if (stats.isDirectory()) {
- folders.push(`${RootPath}/${path}`);
- } else if (stats.isFile()) {
- files.push(`${RootPath}/${path}`);
- } else {
- console.error(`Unknown path ${path}`);
- process.exitCode = 1;
- }
- } else {
- folders = [
- `${RootPath}/build/media_source`,
- `${RootPath}/templates/cassiopeia`,
- ];
- }
-
- const folderPromises = [];
-
- // Loop to get the files that should be compiled via parameter
- for (const folder of folders) {
- folderPromises.push(recursive(folder, ['!*.+(m|js)']));
- }
-
- const computedFiles = await Promise.all(folderPromises);
- const computedFilesFlat = [].concat(...computedFiles);
- const jsFilesPromises = [];
- 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.endsWith('.es5.js')) {
- jsFilesPromises.push(handleES5File(file));
- } else if ((file.endsWith('.es6.js') || file.endsWith('.w-c.es6.js')) && !file.startsWith('_')) {
- esmFilesPromises.push(handleESMFile(file));
- }
- });
-
- Promise.all([...jsFilesPromises, ...esmFilesPromises]);
-};
diff --git a/build/build-modules-js/compress.mjs b/build/build-modules-js/compress.mjs
deleted file mode 100644
index a7ba3b91640..00000000000
--- a/build/build-modules-js/compress.mjs
+++ /dev/null
@@ -1,39 +0,0 @@
-import { readdir } from 'node:fs/promises';
-import { extname } from 'node:path';
-
-import { compressFile } from './utils/compressFile.mjs';
-import { Timer } from './utils/timer.mjs';
-
-/**
- * Get files recursively
- *
- * @param {string} path The path
- */
-async function getFiles(path) {
- // Get files within the current directory
- return (await readdir(path, { withFileTypes: true, recursive: true }))
- .filter((file) => !file.isDirectory() && ['.js', '.css'].includes(extname(file.name)))
- .map((file) => `${file.parentPath}/${file.name}`);
-}
-
-/**
- * Method that will pre compress (gzip) all .css/.js files
- * in the templates and in the media folder
- */
-export const compressFiles = async (enableBrotli = false) => {
- const bench = new Timer('Gzip');
- const paths = [
- `${process.cwd()}/media`,
- `${process.cwd()}/installation/template`,
- `${process.cwd()}/templates`,
- `${process.cwd()}/administrator/templates`,
- ];
-
- const compressTasks = [];
- const files = await Promise.all(paths.map((path) => getFiles(`${path}`)));
- [].concat(...files).map((file) => compressTasks.push(compressFile(file, enableBrotli)));
-
- await Promise.all(compressTasks);
- console.log('✅ Done 👍');
- bench.stop();
-};
diff --git a/build/build-modules-js/error-pages.mjs b/build/build-modules-js/error-pages.mjs
deleted file mode 100644
index 544bab2c6f8..00000000000
--- a/build/build-modules-js/error-pages.mjs
+++ /dev/null
@@ -1,164 +0,0 @@
-import {
- access, mkdir, readFile, writeFile,
-} from 'node:fs/promises';
-import { dirname } from 'node:path';
-
-import Ini from 'ini';
-import Recurs from 'recursive-readdir';
-import { transform } from 'esbuild';
-import { transform as transformCss } from 'lightningcss';
-
-const RootPath = process.cwd();
-const dir = `${RootPath}/installation/language`;
-const srcPath = `${RootPath}/build/warning_page`;
-
-/**
- * Will produce as many .html files as defined in settings.json
- * Expects three files:
- * build/warning_page/template.css
- * build/warning_page/template.html
- * build/warning_page/template.js
- *
- * And also specific strings in the languages in the installation folder!
- * Also the base strings are held in build/build-modules-js/settings.json
- */
-export const 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 { code } = transformCss({
- code: Buffer.from(cssContent),
- minify: true,
- });
-
- cssContent = code;
- jsContent = await transform(jsContent, { minify: true });
-
- const processIni = async (file) => {
- const languageStrings = Ini.parse(await readFile(file, { encoding: 'utf8' }));
-
- // Build the variables into json for the unsupported page
- if (languageStrings.BUILD_MIN_PHP_ERROR_LANGUAGE) {
- const name = dirname(file).replace(/.+\//, '').replace(/.+\\/, '');
- global.unsupportedObj = {
- ...global.unsupportedObj,
- [name]: {
- language: Ini.unsafe(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: Ini.unsafe(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: Ini.unsafe(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: Ini.unsafe(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) => {
- if (file.endsWith('langmetadata.xml')) {
- return;
- }
- iniFilesProcess.push(processIni(file));
- });
-
- await Promise.all(iniFilesProcess).catch((err) => {
- console.error(err);
- process.exitCode = -1;
- });
-
- const processPage = async (name) => {
- const sortedJson = Object.fromEntries(Object.entries(global[`${name}Obj`]).sort());
- const jsonContent = `window.errorLocale=${JSON.stringify(sortedJson)};`;
-
- 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);
- }
-
- options.settings.errorPages[name].destFile.forEach(async (folder) => {
- let mediaExists = false;
- try {
- await access(dirname(`${RootPath}${folder}`));
- mediaExists = true;
- } catch (err) {
- // Do nothing
- }
-
- if (!mediaExists) {
- await mkdir(dirname(`${RootPath}${folder}`), { recursive: true, mode: 0o755 });
- }
-
- await writeFile(`${RootPath}${folder}`, template, { encoding: 'utf8', mode: 0o644 });
-
- console.error(`✅ Created the file: ${folder}`);
- });
- };
-
- Object.keys(options.settings.errorPages).forEach((name) => processPages.push(processPage(name)));
-
- return Promise.all(processPages).catch((err) => {
- console.error(err);
- process.exitCode = -1;
- });
-};
diff --git a/build/build-modules-js/init/cleanup-media.mjs b/build/build-modules-js/init/cleanup-media.mjs
deleted file mode 100644
index 184ae41ab0c..00000000000
--- a/build/build-modules-js/init/cleanup-media.mjs
+++ /dev/null
@@ -1,43 +0,0 @@
-import { join } from 'node:path';
-
-import pkg from 'fs-extra';
-
-const RootPath = process.cwd();
-const {
- stat, mkdir, copy, remove,
-} = pkg;
-
-/**
- * Method that will erase the media/vendor folder
- * and populate the debugbar assets
- *
- * @returns {Promise}
- */
-export const cleanVendors = async () => {
- if (process.env.SKIP_COMPOSER_CHECK === 'YES') {
- await mkdir('media/vendor/debugbar', { recursive: true, mode: 0o755 });
- console.log('Skipping the DebugBar assets...');
- return;
- }
-
- console.log('Cleanup the Vendor ');
-
- const mediaFolder = await stat(join(RootPath, 'libraries/vendor/php-debugbar/php-debugbar/src/DebugBar/Resources'));
-
- if (await mediaFolder.isDirectory()) {
- // Remove the vendor folder
- // await remove(join(RootPath, 'media'));
- // console.error('/media has been removed.');
-
- // Recreate the media folder
- await mkdir(join(RootPath, 'media/vendor/debugbar'), { recursive: true, mode: 0o755 });
-
- // Copy some assets from a PHP package
- await copy(join(RootPath, 'libraries/vendor/php-debugbar/php-debugbar/src/DebugBar/Resources'), join(RootPath, 'media/vendor/debugbar'), { preserveTimestamps: true });
- await remove(join(RootPath, 'media/vendor/debugbar/vendor/font-awesome'));
- await remove(join(RootPath, 'media/vendor/debugbar/vendor/jquery'));
- } else {
- 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.exitCode = 1;
- }
-};
diff --git a/build/build-modules-js/init/common/concat-files.mjs b/build/build-modules-js/init/common/concat-files.mjs
deleted file mode 100644
index a611ed92a10..00000000000
--- a/build/build-modules-js/init/common/concat-files.mjs
+++ /dev/null
@@ -1,25 +0,0 @@
-import { readFile, writeFile, existsSync } from '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}
- */
-export const concatFiles = async (files, output) => {
- const promises = [];
-
- 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(' '), { encoding: 'utf8', mode: 0o644 });
-};
diff --git a/build/build-modules-js/init/common/copy-all-files.mjs b/build/build-modules-js/init/common/copy-all-files.mjs
deleted file mode 100644
index 3037ec32d5c..00000000000
--- a/build/build-modules-js/init/common/copy-all-files.mjs
+++ /dev/null
@@ -1,25 +0,0 @@
-import { join } from 'node:path';
-
-import { copy } from 'fs-extra';
-
-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 }
- */
-export const copyAllFiles = async (dirName, name, type) => {
- const folderName = dirName === '/' ? '/' : `/${dirName}`;
- await copy(
- join(RootPath, `node_modules/${name}/${folderName}`),
- join(RootPath, `media/vendor/${name.replace(/.+\//, '')}/${type}`),
- {
- preserveTimestamps: true,
- },
- );
-};
diff --git a/build/build-modules-js/init/exemptions/tinymce.mjs b/build/build-modules-js/init/exemptions/tinymce.mjs
deleted file mode 100644
index 611580c372b..00000000000
--- a/build/build-modules-js/init/exemptions/tinymce.mjs
+++ /dev/null
@@ -1,88 +0,0 @@
-import { existsSync } from 'node:fs';
-import { mkdir, readFile, writeFile } from 'node:fs/promises';
-import { join } from 'node:path';
-
-import pkg from 'fs-extra';
-
-import { copyAllFiles } from '../common/copy-all-files.mjs';
-
-const { copy, removeSync } = pkg;
-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 = [];
- 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}`, { preserveTimestamps: true }));
- }
- }
-
- await Promise.all(promises);
-};
-
-/**
- * tinyMCE needs special treatment
- */
-export const tinyMCE = async (packageName, version) => {
- const itemvendorPath = join(RootPath, `media/vendor/${packageName}`);
-
- if (!(await existsSync(itemvendorPath))) {
- await mkdir(itemvendorPath, { mode: 0o755 });
- await mkdir(join(itemvendorPath, 'icons'), { mode: 0o755 });
- await mkdir(join(itemvendorPath, 'plugins'), { mode: 0o755 });
- await mkdir(join(itemvendorPath, 'langs'), { mode: 0o755 });
- await mkdir(join(itemvendorPath, 'skins'), { mode: 0o755 });
- await mkdir(join(itemvendorPath, 'themes'), { mode: 0o755 });
- await mkdir(join(itemvendorPath, 'templates'), { mode: 0o755 });
- await mkdir(join(itemvendorPath, 'models'), { mode: 0o755 });
- }
-
- await copyAllFiles('icons', 'tinymce', 'icons');
- await copyAllFiles('plugins', 'tinymce', 'plugins');
- await copyAllFiles('skins', 'tinymce', 'skins');
- await copyAllFiles('themes', 'tinymce', 'themes');
- await copyAllFiles('models', 'tinymce', 'models');
-
- await copyArrayFiles('', ['tinymce.js', 'tinymce.min.js', 'changelog.txt', 'license.txt'], 'tinymce', '');
-
- // Copy translation files
- const promises = [];
- const majorVersion = version.split('.')[0];
- if (existsSync(join(RootPath, `node_modules/tinymce-i18n/langs${majorVersion}`))) {
- promises.push(copy(join(RootPath, `node_modules/tinymce-i18n/langs${majorVersion}`), join(RootPath, `media/vendor/${packageName.replace(/.+\//, '')}/langs`), { preserveTimestamps: true }));
- }
- await Promise.all(promises);
-
- // 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', mode: 0o644 });
-
- // 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', mode: 0o644 });
-
- // Restore our code on the vendor folders
- await copy(join(RootPath, 'build/media_source/vendor/tinymce/templates'), join(RootPath, 'media/vendor/tinymce/templates'), { preserveTimestamps: true });
- // Drop the template plugin
- if (existsSync(join(RootPath, 'media/vendor/tinymce/plugins/template'))) {
- removeSync(join(RootPath, 'media/vendor/tinymce/plugins/template'));
- }
-};
diff --git a/build/build-modules-js/init/localise-packages.mjs b/build/build-modules-js/init/localise-packages.mjs
deleted file mode 100644
index e155761405b..00000000000
--- a/build/build-modules-js/init/localise-packages.mjs
+++ /dev/null
@@ -1,144 +0,0 @@
-import { dirname, join } from 'node:path';
-import { createRequire } from 'node:module';
-import { existsSync } from 'node:fs';
-
-import pkg from 'fs-extra';
-
-import { tinyMCE } from './exemptions/tinymce.mjs';
-import { resolvePackageFile } from './common/resolve-package.cjs';
-
-const require = createRequire(import.meta.url);
-const {
- copy, mkdirs, mkdir, ensureDir, writeFile,
-} = pkg;
-
-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, { preserveTimestamps: true });
- }
-
- // Copy each file
- 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 = resolvePackageFile(`${packageName}/package.json`);
- const modulePathRoot = dirname(modulePathJson);
- const moduleOptions = require(modulePathJson);
-
- const promises = [];
-
- 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}`,
- { preserveTimestamps: true },
- );
- }
-
- 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);
- });
- }
-
- 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}
- */
-export const 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, mode: 0o755 });
- }
-
- // Loop to get some text for the package.json
- 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', mode: 0o644 });
-};
diff --git a/build/build-modules-js/init/minify-vendor.mjs b/build/build-modules-js/init/minify-vendor.mjs
deleted file mode 100644
index 97c0d237ef0..00000000000
--- a/build/build-modules-js/init/minify-vendor.mjs
+++ /dev/null
@@ -1,91 +0,0 @@
-import { sep, basename } from 'node:path';
-import { lstat, readFile, writeFile } from 'node:fs/promises';
-
-import recursive from 'recursive-readdir';
-import { transform } from 'esbuild';
-
-const RootPath = process.cwd();
-
-const folders = [
- 'media/vendor/accessibility/js',
- 'media/vendor/debugbar',
- 'media/vendor/diff/js',
- 'media/vendor/es-module-shims/js',
- 'media/vendor/qrcode/js',
- 'media/vendor/tinymce/langs',
-];
-
-let allFiles = [];
-
-const noMinified = ['accessibility.min.js'];
-
-const alreadyMinified = [
- 'media/vendor/webcomponentsjs/js/webcomponents-bundle.js',
- 'media/vendor/debugbar/vendor/highlightjs/highlight.pack.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(basename(file));
- if (file.endsWith('.min.js') && !needsDotJS) {
- return;
- }
-
- 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 transform(content, { minify: true })).code;
- }
-
- const newFile = needsDotJS ? file.replace('.min.js', '.js') : file.replace('.js', '.min.js');
- // Write the file
- await writeFile(newFile, minified, { encoding: 'utf8', mode: 0o644 });
-};
-
-/**
- * Method that will minify a set of vendor javascript files
- *
- * @returns {Promise}
- */
-export const minifyVendor = async () => {
- 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.mjs b/build/build-modules-js/init/patches.mjs
deleted file mode 100644
index d18f546ff79..00000000000
--- a/build/build-modules-js/init/patches.mjs
+++ /dev/null
@@ -1,22 +0,0 @@
-import { join } from 'node:path';
-import { readFile, writeFile } from 'node:fs/promises';
-
-const RootPath = process.cwd();
-
-/**
- * Main method that will patch files...
- *
- * @param options The options from setting.json
- *
- * @returns {Promise}
- */
-export const patchPackages = async () => {
- const mediaVendorPath = join(RootPath, 'media/vendor');
-
- // Include the v5 shim for Font Awesome
- const faPath = join(mediaVendorPath, 'fontawesome-free/scss/fontawesome.scss');
- const newScss = (await readFile(faPath, { encoding: 'utf8' })).concat(`
-@import 'shims';
-`);
- await writeFile(faPath, newScss, { encoding: 'utf8', mode: 0o644 });
-};
diff --git a/build/build-modules-js/init/recreate-media.mjs b/build/build-modules-js/init/recreate-media.mjs
deleted file mode 100644
index e30a66220a4..00000000000
--- a/build/build-modules-js/init/recreate-media.mjs
+++ /dev/null
@@ -1,85 +0,0 @@
-import {
- stat, readFile, writeFile, readdir,
-} from 'node:fs/promises';
-import { join, extname } from 'node:path';
-
-import pkg from 'fs-extra';
-import recursive from 'recursive-readdir';
-
-const { copy, existsSync, emptyDirSync } = pkg;
-const RootPath = process.cwd();
-const knownDirs = [
- 'templates/site/cassiopeia',
- 'templates/administrator/atum',
-];
-
-/**
- * Will scan all the installed extensions and rebuild the cleanUpFolders registry.
- */
-const updateSettings = async (options) => {
- const extensionsScanned = await readdir(`${RootPath}/build/media_source`, { withFileTypes: true });
- const extensions = [...extensionsScanned]
- .filter((x) => !['.DS_Store', 'templates', 'vendor', 'cache'].includes(x.name) && x.isDirectory())
- .map((x) => x.name);
-
- options.settings.cleanUpFolders = [...extensions, ...knownDirs];
-};
-
-/**
- * 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}
- */
-export const recreateMediaFolder = async (options) => {
- await updateSettings(options);
- const installedVendors = Object.keys(options.settings.vendors).map((vendor) => {
- if (vendor === 'choices.js') {
- return 'vendor/choicesjs';
- }
- if (vendor === '@fortawesome/fontawesome-free') {
- return 'vendor/fontawesome-free';
- }
- if (vendor === '@claviska/jquery-minicolors') {
- return 'vendor/minicolors';
- }
- if (vendor === '@webcomponents/webcomponentsjs') {
- return 'vendor/webcomponentsjs';
- }
- if (vendor === 'joomla-ui-custom-elements') {
- return 'vendor/joomla-custom-elements';
- }
- return `vendor/${vendor}`;
- });
-
- // Clean up existing folders
- [...options.settings.cleanUpFolders, ...installedVendors].forEach((folder) => {
- const folderPath = join(`${RootPath}/media`, folder);
- if (existsSync(folderPath)) {
- emptyDirSync(folderPath);
- }
- });
-
- console.log('Recreating the media folder...');
-
- const filterFunc = async (src) => {
- const fileStat = await stat(src);
- 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, preserveTimestamps: true });
-
- const SCSSMediafolders = await recursive(join(RootPath, 'media/templates'), ['!*.+(scss)']);
-
- // Patch the scss files
- Object.keys(SCSSMediafolders).forEach(async (file) => {
- const contents = await readFile(SCSSMediafolders[file], 'utf8');
- // Transform this `../../../../../../media/` to `../../../../`
- await writeFile(SCSSMediafolders[file], contents.replace(/\.\.\/\.\.\/\.\.\/\.\.\/\.\.\/\.\.\/media\//g, '../../../../'));
- });
-};
diff --git a/build/build-modules-js/javascript/build-bootstrap-js.mjs b/build/build-modules-js/javascript/build-bootstrap-js.mjs
deleted file mode 100644
index 7c4e7506359..00000000000
--- a/build/build-modules-js/javascript/build-bootstrap-js.mjs
+++ /dev/null
@@ -1,118 +0,0 @@
-import {
- readdir, readFile, writeFile, unlink,
-} from 'node:fs/promises';
-import { resolve } from 'node:path';
-import { transform } from 'esbuild';
-import { rimrafSync } from 'rimraf';
-import { rollup } from 'rollup';
-import { nodeResolve } from '@rollup/plugin-node-resolve';
-import replace from '@rollup/plugin-replace';
-import { babel } from '@rollup/plugin-babel';
-import { createRequire } from 'node:module';
-
-const require = createRequire(import.meta.url);
-const opts = require('../../../package.json');
-
-const bsVersion = opts.dependencies.bootstrap.replace(/^\^|~/, '');
-const tasks = [];
-const inputFolder = 'build/media_source/vendor/bootstrap/js';
-const outputFolder = 'media/vendor/bootstrap/js';
-
-const createMinified = async (file) => {
- const initial = await readFile(resolve(outputFolder, file), {
- encoding: 'utf8',
- });
- const mini = await transform(
- initial.replace('./popper.js', `./popper.min.js?${bsVersion}`).replace('./dom.js', `./dom.min.js?${bsVersion}`),
- { minify: true },
- );
- await writeFile(
- resolve(outputFolder, file),
- initial.replace('./popper.js', `./popper.js?${bsVersion}`).replace('./dom.js', `./dom.js?${bsVersion}`),
- { encoding: 'utf8', mode: 0o644 },
- );
- await writeFile(resolve(outputFolder, file.replace('.js', '.min.js')), mini.code, { encoding: 'utf8', mode: 0o644 });
-};
-
-const build = async () => {
- console.log('Building ES6 Components...');
-
- const domImports = await readdir(resolve('node_modules/bootstrap', 'js/src/dom'));
- const utilImports = await readdir(resolve('node_modules/bootstrap', 'js/src/util'));
-
- const bundle = await rollup({
- input: resolve(inputFolder, 'index.es6.js'),
- plugins: [
- nodeResolve(),
- replace({
- preventAssignment: true,
- 'process.env.NODE_ENV': "'production'",
- }),
- babel({
- exclude: 'node_modules/core-js/**',
- babelHelpers: 'bundled',
- babelrc: false,
- presets: [
- [
- '@babel/preset-env',
- {
- targets: {
- browsers: ['> 1%', 'not op_mini all'],
- },
- },
- ],
- ],
- }),
- ],
- });
-
- await bundle.write({
- format: 'es',
- sourcemap: false,
- dir: outputFolder,
- chunkFileNames: '[name].js',
- manualChunks: {
- alert: ['build/media_source/vendor/bootstrap/js/alert.es6.js'],
- button: ['build/media_source/vendor/bootstrap/js/button.es6.js'],
- carousel: ['build/media_source/vendor/bootstrap/js/carousel.es6.js'],
- collapse: ['build/media_source/vendor/bootstrap/js/collapse.es6.js'],
- dropdown: ['build/media_source/vendor/bootstrap/js/dropdown.es6.js'],
- modal: ['build/media_source/vendor/bootstrap/js/modal.es6.js'],
- offcanvas: ['build/media_source/vendor/bootstrap/js/offcanvas.es6.js'],
- popover: ['build/media_source/vendor/bootstrap/js/popover.es6.js'],
- scrollspy: ['build/media_source/vendor/bootstrap/js/scrollspy.es6.js'],
- tab: ['build/media_source/vendor/bootstrap/js/tab.es6.js'],
- toast: ['build/media_source/vendor/bootstrap/js/toast.es6.js'],
- popper: ['@popperjs/core'],
- dom: [
- 'node_modules/bootstrap/js/src/base-component.js',
- ...domImports.map((file) => `node_modules/bootstrap/js/src/dom/${file}`),
- ...utilImports.map((file) => `node_modules/bootstrap/js/src/util/${file}`),
- ],
- },
- });
-
- // closes the bundle
- await bundle.close();
-};
-
-export const bootstrapJs = async () => {
- rimrafSync(resolve(outputFolder));
-
- try {
- await build(resolve(inputFolder, 'index.es6.js'));
- await unlink(resolve(outputFolder, 'index.es6.js'));
- } catch (error) {
- console.error(error);
- process.exitCode = 1;
- }
-
- (await readdir(outputFolder)).forEach((file) => {
- tasks.push(createMinified(file));
- });
-
- return Promise.all(tasks).catch((er) => {
- console.log(er);
- process.exitCode = 1;
- });
-};
diff --git a/build/build-modules-js/javascript/build-codemirror.mjs b/build/build-modules-js/javascript/build-codemirror.mjs
deleted file mode 100644
index 0801efeaef2..00000000000
--- a/build/build-modules-js/javascript/build-codemirror.mjs
+++ /dev/null
@@ -1,137 +0,0 @@
-/**
- * Build codemirror modules
- */
-import { readFileSync } from 'node:fs';
-import { writeFile } from 'node:fs/promises';
-import { createRequire } from 'node:module';
-
-import cliProgress from 'cli-progress';
-import { rollup } from 'rollup';
-import { nodeResolve } from '@rollup/plugin-node-resolve';
-import replace from '@rollup/plugin-replace';
-import { transform } from 'esbuild';
-
-const require = createRequire(import.meta.url);
-
-const {
- resolvePackageFile,
- getPackagesUnderScope,
-} = require('../init/common/resolve-package.cjs');
-
-// Build the module
-const buildModule = async (module, externalModules, destFile) => {
- const build = await rollup({
- input: module,
- external: externalModules || [],
- plugins: [
- nodeResolve(),
- replace({ preventAssignment: true, 'process.env.NODE_ENV': '"production"' }),
- ],
- });
-
- await build.write({
- format: 'es',
- sourcemap: false,
- file: destFile,
- });
- await build.close();
-};
-
-// Minify a js file
-const createMinified = async (filePath) => {
- const destFile = filePath.replace('.js', '.min.js');
- // Read source
- const src = readFileSync(filePath, { encoding: 'utf8' });
- // Minify
- const min = await transform(src, { minify: true });
- // Save result
- await writeFile(destFile, min.code, { encoding: 'utf8', mode: 0o644 });
-};
-
-// Update joomla.asset.json for codemirror
-const updateAssetRegistry = async (modules, externalModules) => {
- const srcPath = 'build/media_source/plg_editors_codemirror/joomla.asset.json';
- const destPath = 'media/plg_editors_codemirror/joomla.asset.json';
-
- // Get base JSON and update
- const registry = JSON.parse(readFileSync(srcPath, { encoding: 'utf8' }));
-
- // Add dependencies to base codemirror asset
- registry.assets.forEach((asset) => {
- if (asset.name === 'codemirror' && asset.type === 'script') {
- asset.dependencies = externalModules;
- }
- });
-
- // Create asset for each module
- modules.forEach((module) => {
- const packageName = module.package;
- const modulePathJson = resolvePackageFile(`${packageName}/package.json`);
- const moduleOptions = require(modulePathJson);
- const asset = {
- type: 'script',
- name: module.package,
- uri: module.uri.replace('.js', '.min.js'),
- importmap: true,
- version: moduleOptions.version,
- };
-
- registry.assets.push(asset);
- });
-
- // Write assets registry
- await writeFile(destPath, JSON.stringify(registry, null, 2), { encoding: 'utf8', mode: 0o644 });
-};
-
-export const compileCodemirror = async () => {
- console.log('Building Codemirror Components...');
-
- const cmModules = getPackagesUnderScope('@codemirror');
- const lModules = getPackagesUnderScope('@lezer');
- const externalModules = [...cmModules, ...lModules];
- const destBasePath = 'media/vendor/codemirror/js';
- const assets = [];
- const tasks = [];
-
- const progressBar = new cliProgress.SingleBar({
- stopOnComplete: true,
- format: '{bar} {percentage}% | {value}/{total} files done',
- }, cliProgress.Presets.shades_classic);
- const totalSteps = (cmModules.length + lModules.length) * 2;
- progressBar.start(totalSteps, 0);
-
- // Prepare @codemirror modules
- cmModules.forEach((module) => {
- const destFile = `${module.replace('@codemirror/', 'codemirror-')}.js`;
- const destPath = `${destBasePath}/${destFile}`;
- assets.push({ package: module, uri: destPath });
-
- const task = buildModule(module, externalModules, destPath).then(() => {
- progressBar.increment();
- return createMinified(destPath).then(() => {
- progressBar.increment();
- });
- });
- tasks.push(task);
- });
-
- // Prepare @lezer modules which @codemirror depends on
- lModules.forEach((module) => {
- const destFile = `${module.replace('@lezer/', 'lezer-')}.js`;
- const destPath = `${destBasePath}/${destFile}`;
- assets.push({ package: module, uri: destPath });
-
- const task2 = buildModule(module, externalModules, destPath).then(() => {
- progressBar.increment();
- return createMinified(destPath).then(() => {
- progressBar.increment();
- });
- });
- tasks.push(task2);
- });
-
- return Promise.all(tasks).then(() => {
- progressBar.stop();
- return updateAssetRegistry(assets, externalModules);
- });
-};
diff --git a/build/build-modules-js/javascript/build-com_media-js.mjs b/build/build-modules-js/javascript/build-com_media-js.mjs
deleted file mode 100644
index 0e9343101bc..00000000000
--- a/build/build-modules-js/javascript/build-com_media-js.mjs
+++ /dev/null
@@ -1,161 +0,0 @@
-import { writeFile, copyFile } from 'node:fs/promises';
-import { resolve } from 'node:path';
-
-import { rollup, watch } from 'rollup';
-import { nodeResolve } from '@rollup/plugin-node-resolve';
-import replace from '@rollup/plugin-replace';
-import { babel } from '@rollup/plugin-babel';
-import VuePlugin from 'rollup-plugin-vue';
-import commonjs from '@rollup/plugin-commonjs';
-import dotenv from 'dotenv';
-
-import { minifyCode } from './minify.mjs';
-
-dotenv.config({ quiet: true });
-
-const inputJS = 'administrator/components/com_media/resources/scripts/mediamanager.es6.js';
-const isProduction = process.env.NODE_ENV !== 'DEVELOPMENT';
-
-export const mediaManager = async () => {
- console.log('Building Media Manager ES Module...');
-
- const bundle = await rollup({
- input: resolve(inputJS),
- plugins: [
- VuePlugin({
- target: 'browser',
- css: false,
- compileTemplate: true,
- template: {
- isProduction,
- },
- }),
- nodeResolve(),
- commonjs(),
- replace({
- 'process.env.NODE_ENV': JSON.stringify((process.env.NODE_ENV && process.env.NODE_ENV.toLocaleLowerCase()) || 'production'),
- __VUE_OPTIONS_API__: true,
- __VUE_PROD_DEVTOOLS__: !isProduction,
- preventAssignment: true,
- }),
- babel({
- exclude: 'node_modules/core-js/**',
- babelHelpers: 'bundled',
- babelrc: false,
- presets: [
- [
- '@babel/preset-env',
- {
- targets: {
- browsers: [
- '> 1%',
- 'not op_mini all',
- /** https://caniuse.com/es6-module */
- 'chrome >= 61',
- 'safari >= 11',
- 'edge >= 16',
- 'Firefox >= 60',
- ],
- },
- loose: true,
- bugfixes: false,
- ignoreBrowserslistConfig: true,
- },
- ],
- ],
- }),
- ],
- });
-
- bundle
- .write({
- format: 'es',
- sourcemap: !isProduction ? 'inline' : false,
- file: 'media/com_media/js/media-manager.js',
- })
- .then((value) => (isProduction ? minifyCode(value.output[0].code) : value.output[0]))
- .then((content) => {
- if (isProduction) {
- console.log('✅ ES2017 Media Manager ready');
- return writeFile(resolve('media/com_media/js/media-manager.min.js'), content.code, { encoding: 'utf8', mode: 0o644 });
- }
- console.log('✅ ES2017 Media Manager ready');
- return copyFile(resolve('media/com_media/js/media-manager.js'), resolve('media/com_media/js/media-manager.min.js'));
- })
- .catch((error) => {
- console.error(error);
- });
-
- // closes the bundle
- await bundle.close();
-};
-
-export const watchMediaManager = async () => {
- console.log('Watching Media Manager js+vue files...');
- console.log('=========');
- const watcher = watch({
- input: resolve(inputJS),
- plugins: [
- VuePlugin({
- target: 'browser',
- css: false,
- compileTemplate: true,
- template: {
- isProduction: true,
- },
- }),
- nodeResolve(),
- commonjs(),
- replace({
- 'process.env.NODE_ENV': JSON.stringify('development'),
- __VUE_OPTIONS_API__: true,
- __VUE_PROD_DEVTOOLS__: true,
- preventAssignment: true,
- }),
- babel({
- exclude: 'node_modules/core-js/**',
- babelHelpers: 'bundled',
- babelrc: false,
- presets: [
- [
- '@babel/preset-env',
- {
- targets: {
- browsers: [
- '> 1%',
- 'not op_mini all',
- /** https://caniuse.com/es6-module */
- 'chrome 61',
- 'safari 11',
- 'edge 16',
- 'Firefox 60',
- ],
- },
- loose: true,
- bugfixes: false,
- ignoreBrowserslistConfig: true,
- },
- ],
- ],
- }),
- ],
- output: [
- {
- format: 'es',
- sourcemap: 'inline',
- file: 'media/com_media/js/media-manager.js',
- },
- {
- format: 'es',
- sourcemap: 'inline',
- file: 'media/com_media/js/media-manager.min.js',
- },
- ],
- });
-
- watcher.on('event', ({ code, result, error }) => {
- if (result) result.close();
- if (error) console.log(error);
- if (code === 'BUNDLE_END') console.log('Files updated ✅');
- });
-};
diff --git a/build/build-modules-js/javascript/build-com_workflow-js.mjs b/build/build-modules-js/javascript/build-com_workflow-js.mjs
deleted file mode 100644
index cf6c4b8fc53..00000000000
--- a/build/build-modules-js/javascript/build-com_workflow-js.mjs
+++ /dev/null
@@ -1,170 +0,0 @@
-import { writeFile, copyFile } from 'node:fs/promises';
-import { resolve } from 'node:path';
-
-import { rollup, watch } from 'rollup';
-import { nodeResolve } from '@rollup/plugin-node-resolve';
-import replace from '@rollup/plugin-replace';
-import { babel } from '@rollup/plugin-babel';
-import VuePlugin from 'rollup-plugin-vue';
-import commonjs from '@rollup/plugin-commonjs';
-import dotenv from 'dotenv';
-
-import { minifyCode } from './minify.mjs';
-
-dotenv.config();
-
-const inputJS = 'administrator/components/com_workflow/resources/scripts/workflowgraph.es6.js';
-const isProduction = process.env.NODE_ENV !== 'DEVELOPMENT';
-
-export const workflowGraph = async () => {
- // eslint-disable-next-line no-console
- console.log('Building Workflow Graph ES Module...');
-
- const bundle = await rollup({
- input: resolve(inputJS),
- external: ['joomla.dialog'],
- plugins: [
- VuePlugin({
- target: 'browser',
- css: false,
- compileTemplate: true,
- template: {
- isProduction,
- },
- }),
- nodeResolve(),
- commonjs(),
- replace({
- 'process.env.NODE_ENV': JSON.stringify((process.env.NODE_ENV && process.env.NODE_ENV.toLocaleLowerCase()) || 'production'),
- __VUE_OPTIONS_API__: true,
- __VUE_PROD_DEVTOOLS__: !isProduction,
- preventAssignment: true,
- }),
- babel({
- exclude: 'node_modules/core-js/**',
- babelHelpers: 'bundled',
- babelrc: false,
- presets: [
- [
- '@babel/preset-env',
- {
- targets: {
- browsers: [
- '> 1%',
- 'not op_mini all',
- /** https://caniuse.com/es6-module */
- 'chrome >= 61',
- 'safari >= 11',
- 'edge >= 16',
- 'Firefox >= 60',
- ],
- },
- loose: true,
- bugfixes: false,
- ignoreBrowserslistConfig: true,
- },
- ],
- ],
- }),
- ],
- });
-
- bundle
- .write({
- format: 'es',
- sourcemap: !isProduction ? 'inline' : false,
- file: 'media/com_workflow/js/workflow-graph.js',
- })
- .then((value) => (isProduction ? minifyCode(value.output[0].code) : value.output[0]))
- .then((content) => {
- if (isProduction) {
- // eslint-disable-next-line no-console
- console.log('✅ ES2017 Workflow Graph ready');
- return writeFile(resolve('media/com_workflow/js/workflow-graph.min.js'), content.code, { encoding: 'utf8', mode: 0o644 });
- }
- // eslint-disable-next-line no-console
- console.log('✅ ES2017 Workflow Graph ready');
- return copyFile(resolve('media/com_workflow/js/workflow-graph.js'), resolve('media/com_workflow/js/workflow-graph.min.js'));
- })
- .catch((error) => {
- // eslint-disable-next-line no-console
- console.error(error);
- });
-
- // closes the bundle
- await bundle.close();
-};
-
-export const watchWorkflowGraph = async () => {
- // eslint-disable-next-line no-console
- console.log('Watching Workflow Graph js+vue files...');
- // eslint-disable-next-line no-console
- console.log('=========');
- const watcher = watch({
- input: resolve(inputJS),
- plugins: [
- VuePlugin({
- target: 'browser',
- css: false,
- compileTemplate: true,
- template: {
- isProduction: true,
- },
- }),
- nodeResolve(),
- commonjs(),
- replace({
- 'process.env.NODE_ENV': JSON.stringify('development'),
- __VUE_OPTIONS_API__: true,
- __VUE_PROD_DEVTOOLS__: true,
- preventAssignment: true,
- }),
- babel({
- exclude: 'node_modules/core-js/**',
- babelHelpers: 'bundled',
- babelrc: false,
- presets: [
- [
- '@babel/preset-env',
- {
- targets: {
- browsers: [
- '> 1%',
- 'not op_mini all',
- /** https://caniuse.com/es6-module */
- 'chrome 61',
- 'safari 11',
- 'edge 16',
- 'Firefox 60',
- ],
- },
- loose: true,
- bugfixes: false,
- ignoreBrowserslistConfig: true,
- },
- ],
- ],
- }),
- ],
- output: [
- {
- format: 'es',
- sourcemap: 'inline',
- file: 'media/com_workflow/js/workflow-graph.js',
- },
- {
- format: 'es',
- sourcemap: 'inline',
- file: 'media/com_workflow/js/workflow-graph.min.js',
- },
- ],
- });
-
- watcher.on('event', ({ code, result, error }) => {
- if (result) result.close();
- // eslint-disable-next-line no-console
- if (error) console.log(error);
- // eslint-disable-next-line no-console
- if (code === 'BUNDLE_END') console.log('Files updated ✅');
- });
-};
diff --git a/build/build-modules-js/javascript/compile-to-es2017.mjs b/build/build-modules-js/javascript/compile-to-es2017.mjs
deleted file mode 100644
index af1cf740cf7..00000000000
--- a/build/build-modules-js/javascript/compile-to-es2017.mjs
+++ /dev/null
@@ -1,101 +0,0 @@
-import { writeFile } from 'node:fs/promises';
-import { basename, sep, resolve } from 'node:path';
-
-import { rollup } from 'rollup';
-import { nodeResolve } from '@rollup/plugin-node-resolve';
-import { babel } from '@rollup/plugin-babel';
-
-import { minifyCode } from './minify.mjs';
-import { getPackagesUnderScope } from '../init/common/resolve-package.cjs';
-
-// List of external modules that should not be resolved by rollup
-const externalModules = [];
-const collectExternals = () => {
- if (externalModules.length) {
- return;
- }
-
- // Joomla and Vendor modules
- externalModules.push(
- 'cropper-module',
- 'codemirror',
- 'joomla.dialog',
- 'editor-api',
- 'editor-decorator',
- 'sa11y',
- 'sa11y-lang',
- );
-
- // Codemirror modules
- const cmModules = getPackagesUnderScope('@codemirror');
- if (cmModules) {
- externalModules.push(...cmModules);
- }
- const lezerModules = getPackagesUnderScope('@lezer');
- if (lezerModules) {
- externalModules.push(...lezerModules);
- }
-};
-
-/**
- * Compiles es6 files to es5.
- *
- * @param file the full path to the file + filename + extension
- */
-export const handleESMFile = async (file) => {
- const newPath = file.replace(/\.w-c\.es6\.js$/, '').replace(/\.es6\.js$/, '').replace(`${sep}build${sep}media_source${sep}`, `${sep}media${sep}`);
-
- // Make sure externals are collected
- collectExternals();
-
- const bundle = await rollup({
- input: resolve(file),
- plugins: [
- nodeResolve({ preferBuiltins: false }),
- babel({
- exclude: 'node_modules/core-js/**',
- babelHelpers: 'bundled',
- babelrc: false,
- presets: [
- [
- '@babel/preset-env',
- {
- targets: {
- browsers: [
- '> 1%',
- 'not op_mini all',
- /** https://caniuse.com/es6-module */
- 'chrome >= 61',
- 'safari >= 11',
- 'edge >= 16',
- 'Firefox >= 60',
- ],
- },
- bugfixes: true,
- loose: true,
- },
- ],
- ],
- }),
- ],
- external: externalModules,
- });
-
- bundle.write({
- format: file.endsWith('core.es6.js') ? 'iife' : 'es',
- sourcemap: false,
- file: resolve(`${newPath}.js`),
- })
- .then((value) => minifyCode(value.output[0].code))
- .then((content) => {
- console.log(`✅ ES2017 file: ${basename(file).replace('.es6.js', '.js')}: transpiled`);
-
- return writeFile(resolve(`${newPath}.min.js`), content.code, { encoding: 'utf8', mode: 0o644 });
- })
- .catch((error) => {
- console.error(error);
- });
-
- // closes the bundle
- await bundle.close();
-};
diff --git a/build/build-modules-js/javascript/handle-es5.mjs b/build/build-modules-js/javascript/handle-es5.mjs
deleted file mode 100644
index a7eae972d7b..00000000000
--- a/build/build-modules-js/javascript/handle-es5.mjs
+++ /dev/null
@@ -1,20 +0,0 @@
-import { basename, dirname, sep } from 'node:path';
-
-import FsExtra from 'fs-extra';
-import { minifyFile } from './minify.mjs';
-
-export const handleES5File = async (file) => {
- if (file.endsWith('.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'),
- { preserveTimestamps: true },
- );
- console.log(`✅ Legacy js file: ${basename(file)}: copied`);
-
- minifyFile(file.replace(`${sep}build${sep}media_source${sep}`, `${sep}media${sep}`).replace('.es5.js', '.js'));
- }
-};
diff --git a/build/build-modules-js/javascript/js-handle.mjs b/build/build-modules-js/javascript/js-handle.mjs
new file mode 100644
index 00000000000..4a2c9cabba8
--- /dev/null
+++ b/build/build-modules-js/javascript/js-handle.mjs
@@ -0,0 +1,159 @@
+/**
+ * JS handler
+ */
+
+import fsp from 'node:fs/promises';
+import path from "node:path";
+import fs from "node:fs";
+
+import { transform } from 'esbuild';
+import { rollup } from 'rollup';
+import { nodeResolve } from '@rollup/plugin-node-resolve';
+import { babel } from '@rollup/plugin-babel';
+import { getPackagesUnderScope } from '../utils/resolve-package.mjs';
+
+// List of external modules that should not be resolved by rollup
+// @TODO: Make it configurable somehow?
+const externalModules = [];
+const getExternalModules = async () => {
+ if (externalModules.length) {
+ return externalModules;
+ }
+
+ // Joomla and Vendor modules
+ externalModules.push(
+ 'cropper-module',
+ 'codemirror',
+ 'joomla.dialog',
+ 'editor-api',
+ 'editor-decorator',
+ 'sa11y',
+ 'sa11y-lang',
+ );
+
+ // Codemirror modules
+ const cmModules = getPackagesUnderScope('@codemirror');
+ if (cmModules) {
+ externalModules.push(...cmModules);
+ }
+ const lezerModules = getPackagesUnderScope('@lezer');
+ if (lezerModules) {
+ externalModules.push(...lezerModules);
+ }
+
+ return externalModules;
+};
+
+/**
+ * Minify JS content
+ *
+ * @param { String } content
+ * @returns { Promise }
+ */
+export const minifyJSContent = async (content = '') => transform(content, { minify: true })
+ .then((result) => result.code);
+
+/**
+ * Handle JS file without extra processing. Just minification.
+ *
+ * @param { String } srcPath
+ * @param { String } targetPath
+ * @returns { Promise }
+ */
+export const handleJSFile = async (srcPath, targetPath) => {
+ const targetFolder = path.dirname(targetPath);
+
+ if (!fs.existsSync(targetFolder)) {
+ fs.mkdirSync(targetFolder, { mode: 0o755, recursive: true });
+ }
+
+ return fsp.readFile(srcPath, { encoding: 'utf8' }).then((content) => {
+ return minifyJSContent(content).then((jsMin) => {
+ // Copy source
+ const saveCopy = (srcPath !== targetPath) ? fsp.copyFile(srcPath, targetPath) : Promise.resolve();
+
+ // Store minified version
+ const saveMin = fsp.writeFile(
+ targetPath.replace('.js', '.min.js'),
+ jsMin,
+ { encoding: 'utf8', mode: 0o644 }
+ );
+
+ return Promise.all([saveCopy, saveMin]);
+ });
+ }).catch((error) => {
+ throw new Error(`Processing failed for "${srcPath}".`, { cause: error });
+ });
+};
+
+/**
+ * Handle JS file which requires extra processing.
+ *
+ * @param { String } srcPath
+ * @param { String } targetPath
+ * @param { string[] } externalModulesList
+ * @returns { Promise }
+ */
+export const handleMJSFile = async (srcPath, targetPath, externalModulesList = []) => {
+ const externalModules = externalModulesList && externalModulesList.length ? externalModulesList : await getExternalModules();
+ const targetFolder = path.dirname(targetPath);
+
+ if (!fs.existsSync(targetFolder)) {
+ fs.mkdirSync(targetFolder, { mode: 0o755, recursive: true });
+ }
+
+ return rollup({
+ input: srcPath,
+ plugins: [
+ nodeResolve({ preferBuiltins: false }),
+ babel({
+ exclude: 'node_modules/core-js/**',
+ babelHelpers: 'bundled',
+ babelrc: false,
+ presets: [
+ [
+ '@babel/preset-env',
+ {
+ targets: {
+ browsers: [
+ '> 1%',
+ 'not op_mini all',
+ /** https://caniuse.com/es6-module */
+ 'chrome >= 61',
+ 'safari >= 11',
+ 'edge >= 16',
+ 'Firefox >= 60',
+ ],
+ },
+ bugfixes: true,
+ loose: true,
+ },
+ ],
+ ],
+ }),
+ ],
+ external: externalModules,
+ }).then(( bundle) => {
+ // Process and store source file
+ const result = bundle.write({
+ format: targetPath.endsWith('core.js') ? 'iife' : 'es',
+ sourcemap: false,
+ file: targetPath,
+ });
+
+ // Minify the code and store
+ const saveMin = result
+ .then(( value ) => minifyJSContent(value.output[0].code))
+ .then(( jsMin ) => {
+ return fsp.writeFile(
+ targetPath.replace('.js', '.min.js'),
+ jsMin,
+ { encoding: 'utf8', mode: 0o644 }
+ );
+ });
+
+ return saveMin.then(() => bundle.close());
+ }).catch((error) => {
+ throw new Error(`Processing failed for "${srcPath}".`, { cause: error });
+ });
+};
diff --git a/build/build-modules-js/javascript/minify.mjs b/build/build-modules-js/javascript/minify.mjs
deleted file mode 100644
index a01b7b6b0fa..00000000000
--- a/build/build-modules-js/javascript/minify.mjs
+++ /dev/null
@@ -1,25 +0,0 @@
-import { basename } from 'node:path';
-import { readFile, writeFile } from 'node:fs/promises';
-
-import { transform } from 'esbuild';
-
-/**
- * Minify a js file using esbuild
- *
- * @param file
- * @returns {Promise}
- */
-export const minifyFile = async (file) => {
- const fileContent = await readFile(file, { encoding: 'utf8' });
- const content = await transform(fileContent, { minify: true });
- await writeFile(file.replace('.js', '.min.js'), content.code, { encoding: 'utf8', mode: 0o644 });
- console.log(`✅ Legacy js file: ${basename(file)}: minified`);
-};
-
-/**
- * Minify a chunk of js using esbuild
- *
- * @param code
- * @returns {Promise}
- */
-export const minifyCode = async (code) => transform(code, { minify: true });
diff --git a/build/build-modules-js/settings.json b/build/build-modules-js/settings.json
index 1529438ac31..63515056854 100644
--- a/build/build-modules-js/settings.json
+++ b/build/build-modules-js/settings.json
@@ -420,8 +420,8 @@
"@fortawesome/fontawesome-free": {
"name": "fontawesome-free",
"css": {
- "css/fontawesome.css": "css/fontawesome.css",
- "css/fontawesome.min.css": "css/fontawesome.min.css"
+ "css/all.css": "css/fontawesome.css",
+ "css/all.min.css": "css/fontawesome.min.css"
},
"filesExtra": {
"scss": "scss",
@@ -644,7 +644,7 @@
},
"tinymce": {
"name": "tinymce",
- "licenseFilename": "license.txt"
+ "licenseFilename": "license.md"
},
"accessibility": {
"name": "accessibility",
diff --git a/build/build-modules-js/stylesheets/css-handler.mjs b/build/build-modules-js/stylesheets/css-handler.mjs
new file mode 100644
index 00000000000..e5472ac9b32
--- /dev/null
+++ b/build/build-modules-js/stylesheets/css-handler.mjs
@@ -0,0 +1,112 @@
+/**
+ * CSS handler
+ */
+
+import rtlcss from 'rtlcss';
+import path from 'node:path';
+import fsp from 'node:fs/promises';
+import fs from "node:fs";
+
+import { composeVisitors, transform as transformCss } from 'lightningcss';
+import { urlVersioning2 } from './css-versioning.mjs';
+import { createHash } from "node:crypto";
+
+/**
+ * Preprocess Css content
+ *
+ * @param { String } content
+ * @returns { Promise }
+ */
+export const preprocessCSS = async (content = '') => {
+ // Remove @charset "UTF-8" at beginning to preserve the license
+ // Because the license comment needs to start at the beginning of the file to be saved
+ content = content.startsWith('@charset "UTF-8";\n') ? content.replace('@charset "UTF-8";\n', '') : content;
+
+ // Check the header comments and make sure it starts with /*!
+ // This need to force lightningcss to keep the license comments
+ if (content.substring(0, 50).includes('/**')) {
+ content = content.replace('/**', '/*!');
+ }
+
+ // Run url() versioning for the source
+ const hash = createHash('md5');
+ hash.update(content);
+ const hashStr = hash.digest('hex').substring(0, 6);
+
+ const { code: css } = transformCss({
+ code: Buffer.from(content),
+ minify: false,
+ visitor: composeVisitors([ urlVersioning2(hashStr) ]), // Adds a hash to the url() parts of the static css
+ });
+
+ return css.toString();
+};
+
+/**
+ * Minify Css content
+ * @param { String } content
+ * @returns { Promise }
+ */
+export const minifyCSS = async (content = '') => {
+
+ const { code: cssMin } = transformCss({
+ code: Buffer.from(content),
+ minify: true,
+ });
+
+ return cssMin.toString();
+};
+
+/**
+ * Handle CSS content and store it at the destination.
+ * Store source and minified version.
+ *
+ * @param { String } targetPath
+ * @param { String } content
+ * @returns { Promise }
+ */
+export const handleAndStoreCSSContent = async (targetPath, content = '') => {
+ if (targetPath.endsWith('-rtl.css')) {
+ content = rtlcss.process(content);
+ }
+
+ const css = await preprocessCSS(content);
+ const cssMin = await minifyCSS(css);
+ const targetFolder = path.dirname(targetPath);
+
+ if (!fs.existsSync(targetFolder)) {
+ fs.mkdirSync(targetFolder, { mode: 0o755, recursive: true });
+ }
+
+ const save = fsp.writeFile(
+ targetPath,
+ `@charset "UTF-8";\n${css}`, // Force "UTF-8" for all, also it is removed by preprocessCSS
+ { encoding: 'utf8', mode: 0o644 },
+ );
+
+ // Save minified css file
+ const saveMin = fsp.writeFile(
+ targetPath.replace('.css', '.min.css'),
+ `@charset "UTF-8";${cssMin}`,
+ { encoding: 'utf8', mode: 0o644 }
+ );
+
+ return Promise.all([save, saveMin]);
+};
+
+/**
+ * Read source CSS, handle its content and store it at the destination.
+ *
+ * @param { String } srcPath
+ * @param { String } targetPath
+ * @returns { Promise }
+ */
+export const handleCSSFile = async (srcPath, targetPath) => {
+ return fsp.readFile(srcPath, { encoding: 'utf8' }).then((content) => {
+ return handleAndStoreCSSContent(targetPath, content);
+ }).catch((error) => {
+ throw new Error(`Processing failed for "${srcPath}".`, { cause: error });
+ });
+};
+
+
diff --git a/build/build-modules-js/stylesheets/css-versioning.mjs b/build/build-modules-js/stylesheets/css-versioning.mjs
index 19ade2f165a..7c5ad8e444c 100644
--- a/build/build-modules-js/stylesheets/css-versioning.mjs
+++ b/build/build-modules-js/stylesheets/css-versioning.mjs
@@ -1,15 +1,11 @@
import { createHash } from 'node:crypto';
-import { readdir, readFile, writeFile } from 'node:fs/promises';
import { existsSync, readFileSync } from 'node:fs';
-import { dirname, extname, resolve } from 'node:path';
-import { transform, composeVisitors } from 'lightningcss';
-import { Timer } from '../utils/timer.mjs';
+import { dirname, resolve } from 'node:path';
-const RootPath = process.cwd();
const skipExternal = true;
const variable = 'v';
-function version(urlString, fromFile) {
+function version(urlString, fromFile, withHash) {
// Skip external URLs
if (skipExternal && (urlString.startsWith('http') || urlString.startsWith('//'))) {
return `${urlString}`;
@@ -27,6 +23,10 @@ function version(urlString, fromFile) {
return `${urlString}`;
}
+ if (withHash) {
+ return `${urlString}?${variable}=${withHash}`;
+ }
+
if (fromFile && existsSync(resolve(`${dirname(fromFile)}/${urlString}`))) {
const hash = createHash('md5');
hash.update(readFileSync(resolve(`${dirname(fromFile)}/${urlString}`)));
@@ -50,58 +50,15 @@ const urlVersioning = (fromFile) => ({
});
/**
- * Adds a hash to the url() parts of the static css
- *
- * @param file
- * @returns {Promise}
- */
-const fixVersion = async (file) => {
- try {
- let content = await readFile(file, { encoding: 'utf8' });
- // To preserve the licence the comment needs to start at the beginning of the file
- const replaceUTF8String = file.endsWith('.min.css') ? '@charset "UTF-8";' : '@charset "UTF-8";\n';
- content = content.startsWith(replaceUTF8String) ? content.replace(replaceUTF8String, '') : content;
-
- // Preserve a leading license comment (/** ... */)
- const firstLine = content.split(/\r?\n/)[0] || '';
- if (firstLine.includes('/*') && !firstLine.includes('/*!')) {
- const endCommentIdx = content.indexOf('*/');
- if (endCommentIdx !== -1
- && (content.substring(0, endCommentIdx).includes('license')
- || content.substring(0, endCommentIdx).includes('copyright'))
- ) {
- content = firstLine.includes('/**') ? content.replace('/**', '/*!') : content.replace('/*', '/*!');
- }
- }
-
- const { code } = transform({
- code: Buffer.from(content),
- minify: file.endsWith('.min.css'),
- visitor: composeVisitors([urlVersioning(file)]),
- });
- await writeFile(file, `@charset "UTF-8";${file.endsWith('.min.css') ? '' : '\n'}${code}`, {
- encoding: 'utf8',
- mode: 0o644,
- });
- } catch (error) {
- throw new Error(error);
- }
-};
-
-/**
- * Loop the media folder and add version to all url() entries in all the css files
- *
- * @returns {Promise}
+ * @param {withHash: String} - the filepath for the css file
+ * @returns {import('lightningcss').Visitor} - A visitor that replaces the url
*/
-const cssVersioningVendor = async () => {
- const bench = new Timer('Versioning');
-
- const cssFiles = (await readdir(`${RootPath}/media/vendor`, { withFileTypes: true, recursive: true }))
- .filter((file) => (!file.isDirectory() && extname(file.name) === '.css'))
- .map((file) => `${file.parentPath}/${file.name}`);
-
- Promise.all(cssFiles.map((file) => fixVersion(file)))
- .then(() => bench.stop());
-};
+const urlVersioning2 = (withHash) => ({
+ /**
+ * @param {import('lightningcss').Url} url - The url object to transform
+ * @returns {import('lightningcss').Url} - The transformed url object
+ */
+ Url: (url) => ({ ...url, url: version(url.url, false, withHash) }),
+});
-export { urlVersioning, cssVersioningVendor };
+export { urlVersioning, urlVersioning2 };
diff --git a/build/build-modules-js/stylesheets/handle-css.mjs b/build/build-modules-js/stylesheets/handle-css.mjs
deleted file mode 100644
index e4609a8e846..00000000000
--- a/build/build-modules-js/stylesheets/handle-css.mjs
+++ /dev/null
@@ -1,55 +0,0 @@
-import { dirname, sep } from 'node:path';
-
-import pkg from 'fs-extra';
-import { transform as transformCss, composeVisitors } from 'lightningcss';
-import { urlVersioning } from './css-versioning.mjs';
-
-const {
- readFile, writeFile, ensureDir,
-} = pkg;
-
-export const handleCssFile = async (file) => {
- const outputFile = file.replace(`${sep}build${sep}media_source${sep}`, `${sep}media${sep}`);
- try {
- // CSS file, we will process the file and then minify it in place
- // Ensure that the directories exist or create them
- await ensureDir(dirname(outputFile), { recursive: true, mode: 0o755 });
-
- let content = await readFile(file, { encoding: 'utf8' });
-
- // To preserve the licence the comment needs to start at the beginning of the file
- content = content.startsWith('@charset "UTF-8";\n') ? content.replace('@charset "UTF-8";\n', '') : content;
-
- if (file !== outputFile) {
- const { code: css } = transformCss({
- code: Buffer.from(content),
- minify: false,
- visitor: composeVisitors([urlVersioning(file)]), // Adds a hash to the url() parts of the static css
- });
-
- // Save optimized css file
- await writeFile(
- outputFile,
- content.startsWith('@charset "UTF-8";')
- ? css
- : `@charset "UTF-8";
-${css}`,
- { encoding: 'utf8', mode: 0o644 },
- );
- }
-
- // Process the file and minify it in place
- const { code: cssMin } = transformCss({
- code: Buffer.from(content),
- minify: true,
- visitor: composeVisitors([urlVersioning(outputFile)]), // Adds a hash to the url() parts of the static css
- });
-
- // Save minified css file
- await writeFile(outputFile.replace('.css', '.min.css'), `@charset "UTF-8";${cssMin}`, { encoding: 'utf8', mode: 0o644 });
-
- console.log(`✅ CSS file copied/minified: ${file}`);
- } catch (err) {
- console.log(err);
- }
-};
diff --git a/build/build-modules-js/stylesheets/handle-scss.mjs b/build/build-modules-js/stylesheets/handle-scss.mjs
deleted file mode 100644
index 3143d8b78fe..00000000000
--- a/build/build-modules-js/stylesheets/handle-scss.mjs
+++ /dev/null
@@ -1,69 +0,0 @@
-import { writeFile } from 'node:fs/promises';
-import { dirname, sep } from 'node:path';
-
-import rtlcss from 'rtlcss';
-import { ensureDir } from 'fs-extra';
-import { transform as transformCss, Features, composeVisitors } from 'lightningcss';
-import { compileAsync } from 'sass-embedded';
-import { urlVersioning } from './css-versioning.mjs';
-
-const getOutputFile = (file) => file.replace(`${sep}scss${sep}`, `${sep}css${sep}`).replace('.scss', '.css').replace(`${sep}build${sep}media_source${sep}`, `${sep}media${sep}`);
-
-export const handleScssFile = async (file) => {
- let contents;
- const cssFile = getOutputFile(file);
-
- try {
- const { css } = await compileAsync(file);
- contents = css.toString();
- } catch (error) {
- const message = `Error in file: ${file}\n${error.formatted || error.message}`;
- const newErr = new Error(message);
- newErr.stack = error.stack;
- throw newErr;
- }
-
- if (cssFile.endsWith('-rtl.css')) {
- contents = rtlcss.process(contents);
- }
-
- // To preserve the licence the comment needs to start at the beginning of the file
- contents = contents.startsWith('@charset "UTF-8";\n') ? contents.replace('@charset "UTF-8";\n', '') : contents;
-
- // Ensure the folder exists or create it
- await ensureDir(dirname(cssFile), {});
-
- const { code: css } = transformCss({
- code: Buffer.from(contents),
- minify: false,
- exclude: Features.VendorPrefixes,
- visitor: composeVisitors([urlVersioning(file)]), // Adds a hash to the url() parts of the static css
- });
-
- // Save optimized css file
- await writeFile(
- cssFile,
- contents.startsWith('@charset "UTF-8";')
- ? css
- : `@charset "UTF-8";
-${css}`,
- { encoding: 'utf8', mode: 0o644 },
- );
-
- const { code: cssMin } = transformCss({
- code: Buffer.from(contents),
- minify: true,
- exclude: Features.VendorPrefixes,
- visitor: composeVisitors([urlVersioning(cssFile)]), // Adds a hash to the url() parts of the static css
- });
-
- // Ensure the folder exists or create it
- await ensureDir(dirname(cssFile.replace('.css', '.min.css')), {});
- await writeFile(
- cssFile.replace('.css', '.min.css'),
- `@charset "UTF-8";${cssMin}`,
- { encoding: 'utf8', mode: 0o644 },
- );
-
- console.log(`✅ SCSS File compiled: ${cssFile}`);
-};
diff --git a/build/build-modules-js/stylesheets/scss-handler.mjs b/build/build-modules-js/stylesheets/scss-handler.mjs
new file mode 100644
index 00000000000..8681508baba
--- /dev/null
+++ b/build/build-modules-js/stylesheets/scss-handler.mjs
@@ -0,0 +1,25 @@
+/**
+ * SCSS handler
+ */
+import { compileAsync } from 'sass-embedded';
+import { handleAndStoreCSSContent } from './css-handler.mjs';
+
+/**
+ * Read source SCSS, compile it to CSS and store it at the destination.
+ *
+ * @param { String } srcPath
+ * @param { String } targetPath
+ * @param { boolean } silent
+ * @returns { Promise }
+ */
+export const handleSCSSFile = async (srcPath, targetPath, silent = false) => {
+ return compileAsync(srcPath, {
+ quietDeps: true,
+ silenceDeprecations: silent ? ['if-function', 'import', 'global-builtin', 'color-functions'] : []
+ })
+ .then(({ css: content }) => {
+ return handleAndStoreCSSContent(targetPath, content);
+ }).catch((error) => {
+ throw new Error(`Processing failed for "${srcPath}".`, { cause: error });
+ });
+};
diff --git a/build/build-modules-js/utils/compressFile.mjs b/build/build-modules-js/utils/compressFile.mjs
index c03dbe864c9..aacb0d6b297 100644
--- a/build/build-modules-js/utils/compressFile.mjs
+++ b/build/build-modules-js/utils/compressFile.mjs
@@ -19,17 +19,21 @@ const gzipEncode = (data) => gzipPromise(data, gzipOpts);
const brotliPromise = promisify(brotliCompress);
const brotliEncode = (data) => brotliPromise(data, brotliOpts);
-export const compressFile = async (file, enableBrotli) => {
- if (file.endsWith('.min.js') || file.endsWith('.min.css')) {
- try {
- const data = await readFile(file);
- await writeFile(`${file}.gz`, await gzipEncode(data));
- if (enableBrotli) {
- await writeFile(`${file}.br`, await brotliEncode(data));
- }
- console.log(file);
- } catch (err) {
- console.info(`Error on ${file}: ${err.code}`);
- }
- }
+/**
+ * Compress and store the result aside original file.
+ * @param { String } file
+ * @param { boolean } enableBrotli
+ * @return {Promise}
+ */
+export const compressFileAndSave = async (file, enableBrotli = false) => {
+ return readFile(file).then((content) => {
+ const gzipRun = gzipEncode(content).then((data) => {
+ return writeFile(`${file}.gz`, data);
+ });
+ const brotliRun = !enableBrotli ? Promise.resolve() : brotliEncode(content).then(() => {
+ return writeFile(`${file}.br`, data);
+ });
+
+ return Promise.all([gzipRun, brotliRun]);
+ });
};
diff --git a/build/build-modules-js/init/common/resolve-package.cjs b/build/build-modules-js/utils/resolve-package.mjs
similarity index 52%
rename from build/build-modules-js/init/common/resolve-package.cjs
rename to build/build-modules-js/utils/resolve-package.mjs
index 9a2159acd5d..892f40f230c 100644
--- a/build/build-modules-js/init/common/resolve-package.cjs
+++ b/build/build-modules-js/utils/resolve-package.mjs
@@ -1,4 +1,9 @@
-const { existsSync, readdirSync } = require('node:fs');
+/**
+ * Resolve Package Helper
+ */
+import path from 'node:path';
+import { existsSync, readdirSync } from 'node:fs';
+import { createRequire } from 'node:module';
/**
* Find full path for package file.
@@ -7,10 +12,13 @@ const { existsSync, readdirSync } = require('node:fs');
* @param {string} relativePath Relative path to the file to resolve, in format packageName/file-name.js
* @returns {string|boolean}
*/
-module.exports.resolvePackageFile = (relativePath) => {
- for (let i = 0, l = module.paths.length; i < l; i += 1) {
- const path = module.paths[i];
- const fullPath = `${path}/${relativePath}`;
+export const resolvePackageFile = (relativePath) => {
+ // Get list of node.js include paths
+ const paths = createRequire(import.meta.url).resolve.paths('node');
+
+ for (let i = 0, l = paths.length; i < l; i += 1) {
+ const fullPath = path.join(paths[i], relativePath);
+
if (existsSync(fullPath)) {
return fullPath;
}
@@ -26,13 +34,16 @@ module.exports.resolvePackageFile = (relativePath) => {
* @param scope
* @returns {[]}
*/
-module.exports.getPackagesUnderScope = (scope) => {
+export const getPackagesUnderScope = (scope) => {
const cmModules = new Set();
+ // Get list of node.js include paths
+ const paths = createRequire(import.meta.url).resolve.paths('node');
+
// Get the scope roots
const roots = [];
- module.paths.forEach((path) => {
- const fullPath = `${path}/${scope}`;
+ paths.forEach((pathBase) => {
+ const fullPath = path.join(pathBase, scope);
if (existsSync(fullPath)) {
roots.push(fullPath);
}
@@ -41,7 +52,7 @@ module.exports.getPackagesUnderScope = (scope) => {
// List of modules
roots.forEach((rootPath) => {
readdirSync(rootPath).forEach((subModule) => {
- cmModules.add(`${scope}/${subModule}`);
+ cmModules.add(path.join(scope, subModule));
});
});
diff --git a/build/build-modules-js/versioning.mjs b/build/build-modules-js/versioning.mjs
deleted file mode 100644
index 3eb985a6abb..00000000000
--- a/build/build-modules-js/versioning.mjs
+++ /dev/null
@@ -1,128 +0,0 @@
-import {
- lstat, readdir, readFile, writeFile,
-} from 'node:fs/promises';
-import {
- basename, dirname, resolve, sep,
-} from 'node:path';
-
-import { createHashFromFile } from './utils/hashfromfile.mjs';
-import { Timer } from './utils/timer.mjs';
-
-const RootPath = process.cwd();
-const exclusion = [
- // We will skip these:
- '.DS_Store',
- 'index.html',
- 'cache',
- 'vendors',
-];
-const final = {};
-
-/**
- * Update a given joomla.assets.json entry
- *
- * @param asset
- * @param directory
- * @returns {Promise<{type}|*>}
- */
-const updateAsset = async (asset, directory) => {
- const currentDir = `${RootPath}${sep}media${sep}${directory}`;
- if (!asset.type) {
- final[directory].push(asset);
- return;
- }
- let subDir;
- if (asset.type === 'script') {
- subDir = 'js';
- }
- if (asset.type === 'style') {
- subDir = 'css';
- }
- if (!subDir) {
- final[directory].push(asset);
- return;
- }
-
- let path = `${currentDir}${sep}${subDir}${sep}${basename(asset.uri)}`;
- if (`${directory}/${basename(asset.uri)}` !== asset.uri) {
- if (dirname(asset.uri) === 'system/fields') {
- path = `${currentDir}${sep}${subDir}${sep}fields${sep}${basename(asset.uri)}`;
- } else {
- final[directory].push(asset);
- return;
- }
- }
-
- const jAssetFile = await lstat(path);
-
- if (!jAssetFile.isFile()) {
- final[directory].push(asset);
- return;
- }
-
- const hash = await createHashFromFile(path);
-
- asset.version = hash.substring(0, 6);
- final[directory].push(asset);
-};
-
-/**
- * Read the joomla.assets.json and loop the assets
- *
- * @param directory
- * @returns {Promise}
- */
-const fixVersion = async (directory) => {
- let jAssetFile;
- try {
- jAssetFile = await lstat(`${RootPath}${sep}media${sep}${directory}${sep}joomla.asset.json`);
- } catch (err) {
- return;
- }
-
- if (!jAssetFile.isFile()) {
- return;
- }
-
- const jAssetFileContent = await readFile(`${RootPath}${sep}media${sep}${directory}${sep}joomla.asset.json`, { encoding: 'utf8' });
- let jsonData;
- try {
- jsonData = JSON.parse(jAssetFileContent);
- } catch (err) {
- throw new Error(`media\\${directory}\\joomla.asset.json is not a valid JSON file!!!`);
- }
-
- if (!jsonData || !jsonData.assets.length) {
- return;
- }
-
- const processes = [];
- jsonData.assets.map((asset) => processes.push(updateAsset(asset, directory)));
-
- await Promise.all(processes);
-
- jsonData.assets = final[directory];
- await writeFile(`${RootPath}${sep}media${sep}${directory}${sep}joomla.asset.json`, JSON.stringify(jsonData, '', 2), { encoding: 'utf8', mode: 0o644 });
-};
-
-/**
- * Loop the media folder and add version to all .js/.css entries in all
- * the joomla.assets.json files
- *
- * @returns {Promise}
- */
-export const versioning = async () => {
- const bench = new Timer('Versioning');
- const tasks = [];
- let mediaDirectories = await readdir(resolve(RootPath, 'media'));
- mediaDirectories = mediaDirectories.filter((dir) => !exclusion.includes(dir));
-
- mediaDirectories.forEach((directory) => {
- final[directory] = [];
- tasks.push(fixVersion(directory));
- });
-
- await Promise.all(tasks);
-
- bench.stop();
-};
diff --git a/build/build-modules-js/watch.mjs b/build/build-modules-js/watch.mjs
deleted file mode 100644
index 648dc468a82..00000000000
--- a/build/build-modules-js/watch.mjs
+++ /dev/null
@@ -1,44 +0,0 @@
-import {
- join, extname, basename, dirname,
-} from 'node:path';
-import chokidar from 'chokidar';
-
-import { handleESMFile } from './javascript/compile-to-es2017.mjs';
-import { handleES5File } from './javascript/handle-es5.mjs';
-import { handleScssFile } from './stylesheets/handle-scss.mjs';
-import { handleCssFile } from './stylesheets/handle-css.mjs';
-import { debounce } from './utils/debounce.mjs';
-
-const RootPath = process.cwd();
-
-const processFile = (file) => {
- if (extname(file) === '.js' && !dirname(file).startsWith(join(RootPath, 'build/media_source/vendor/bootstrap/js'))) {
- if ((file.endsWith('.w-c.es6.js') || file.endsWith('.es6.js')) && !file.startsWith('_')) {
- debounce(handleESMFile(file), 300);
- }
- if (file.endsWith('.es5..js')) {
- debounce(handleES5File(file), 300);
- }
- }
-
- if (extname(file) === '.scss' && !basename(file).startsWith('_')) {
- debounce(handleScssFile(file), 300);
- }
- if (extname(file) === '.css') {
- debounce(handleCssFile(file), 300);
- }
-};
-
-export const watching = (path) => {
- const watchingPath = path ? join(RootPath, path) : join(RootPath, 'build/media_source');
- const watcher = chokidar.watch(watchingPath, {
- ignored: /(^|[/\\])\../, // ignore dotfiles
- persistent: true,
- });
-
- watcher
- .on('add', (file) => processFile(file))
- .on('change', (file) => processFile(file));
- // @todo Handle this case as well
- // .on('unlink', path => log(`File ${path} has been removed`));
-};
diff --git a/build/build.mjs b/build/build.mjs
index 37185ff1d58..e9c3b322bd7 100644
--- a/build/build.mjs
+++ b/build/build.mjs
@@ -1,220 +1,61 @@
/**
- * Command line helper
- *
- * To get the complete functional media folder please run:
- * npm ci
- *
- * For dedicated tasks, please run:
- * node build.mjs --build-pages will create the error pages (for incomplete repo build PHP+NPM)
- * node build.mjs --copy-assets will clean the media/vendor folder and then will populate the folder from node_modules
- * node build.mjs --compile-js will transpile ES6 files and also uglify the ES6,ES5 files
- * node build.mjs --compile-css will compile all the scss defined files and also create a minified version of the css
- * node build.mjs --compile-bs will compile all the Bootstrap javascript components
- * node build.mjs --com-media will compile the media manager Vue application
- * node build.mjs --watch-com-media will watch and compile the media manager Vue application
- * node build.mjs --gzip will create gzip files for all the minified stylesheets and scripts.
- * node build.mjs --versioning will update all the joomla.assets.json files providing accurate versions for stylesheets and scripts.
+ * Script used to build Joomla Web Assets content
*/
-import { createRequire } from 'node:module';
import { Command } from 'commander';
import semver from 'semver';
-
-// Joomla Build modules
-import { createErrorPages } from './build-modules-js/error-pages.mjs';
-import { stylesheets } from './build-modules-js/compilecss.mjs';
-import { scripts } from './build-modules-js/compilejs.mjs';
-import { bootstrapJs } from './build-modules-js/javascript/build-bootstrap-js.mjs';
-import { localisePackages } from './build-modules-js/init/localise-packages.mjs';
-import { minifyVendor } from './build-modules-js/init/minify-vendor.mjs';
-import { patchPackages } from './build-modules-js/init/patches.mjs';
-import { cleanVendors } from './build-modules-js/init/cleanup-media.mjs';
-import { recreateMediaFolder } from './build-modules-js/init/recreate-media.mjs';
-import { watching } from './build-modules-js/watch.mjs';
-import { mediaManager, watchMediaManager } from './build-modules-js/javascript/build-com_media-js.mjs';
-import { workflowGraph, watchWorkflowGraph } from './build-modules-js/javascript/build-com_workflow-js.mjs';
-import { compressFiles } from './build-modules-js/compress.mjs';
-import { versioning } from './build-modules-js/versioning.mjs';
import { Timer } from './build-modules-js/utils/timer.mjs';
-import { compileCodemirror } from './build-modules-js/javascript/build-codemirror.mjs';
-import { cssVersioningVendor } from './build-modules-js/stylesheets/css-versioning.mjs';
-
-const require = createRequire(import.meta.url);
-
-// The settings
-const options = require('../package.json');
-const settings = require('./build-modules-js/settings.json');
-
-const handleError = (err, terminateCode) => {
- console.error(err);
- process.exitCode = terminateCode;
-};
-
-if (semver.gte(semver.minVersion(options.engines.node), semver.clean(process.version))) {
- handleError(
- `Node version ${semver.clean(process.version)} is not supported, please upgrade to Node version ${semver.clean(options.engines.node)}`,
- 1,
- );
-}
-
-// The command line
-const Program = new Command();
+import buildCommand from './build-modules-js/command/build-command.mjs';
+import watchCommand from './build-modules-js/command/watch-command.mjs';
+import pkgOptions from '../package.json' with { type: 'json' };
+import { builders, blockingBuilders } from './build-modules-js/builders-registry.mjs';
-// Merge Joomla's specific settings to the main package.json object
-if ('settings' in settings) {
- options.settings = settings.settings;
+// Check minimum Node version
+if (semver.gte(semver.minVersion(pkgOptions.engines.node), semver.clean(process.version))) {
+ throw new Error(`Node version ${semver.clean(process.version)} is not supported, please upgrade to Node version ${semver.clean(pkgOptions.engines.node)}`);
}
-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.allowUnknownOption()
- .version(options.version)
- .option('--copy-assets', 'Moving files from node_modules to media folder')
- .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('--compile-codemirror', 'Compiles all the codemirror modules.')
- .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('--com-workflow', 'Compile the Workflow Graph client side App.')
- .option(
- '--watch-com-workflow',
- 'Watch and Compile the Workflow Graph client side App.',
- )
- .option('--gzip', 'Compress all the minified stylesheets and scripts.')
- .option('--prepare', 'Run all the needed tasks to initialise the repo')
- .option(
- '--versioning',
- 'Update all the .js/.css versions on their relative joomla.assets.json',
- )
+// The command line, initialize
+const program = new Command();
+program
+ // Show correct command hint in the Help
+ .name('node build/build.mjs')
+ .version(pkgOptions.version)
.addHelpText(
'after',
`
-Version: ${options.version}
+Version: ${pkgOptions.version}
`,
);
-Program.parse(process.argv);
-
-const cliOptions = Program.opts();
+program
+ .command('builders-list')
+ .description('Show list of builders')
+ .action(() => {
+ console.log(builders.join("\n"));
+ });
+
+program
+ .command('build')
+ .description('Build all or only specified asset')
+ .option('-a,--all', 'build all assets')
+ .option('-n,--name ', 'build specific resource(s)')
+ .option('-t,--task ', 'task(s) to run for specified resource(s)')
+ .option('--sass-silent', 'hide SASS deprecations and warnings')
+ .action((options) => {
+ const bench = new Timer('Build command');
+ buildCommand(program, options, builders, blockingBuilders)
+ .then(() => bench.stop('Build command'));
+ });
+
+program
+ .command('watch')
+ .description('Watch specified asset and rebuild on changes')
+ .option('-n,--name ', 'builder(s) to watch')
+ .action((options) => {
+ watchCommand(program, options, builders);
+ });
+
+program.parse(process.argv)
-// Update the vendor folder
-if (cliOptions.copyAssets) {
- allowedVersion();
- recreateMediaFolder(options)
- .then(() => cleanVendors())
- .then(() => localisePackages(options))
- .then(() => patchPackages(options))
- .then(() => cssVersioningVendor())
- .then(() => minifyVendor())
- .catch((error) => handleError(error, 1));
-}
-
-// Creates the error pages for unsupported PHP version & incomplete environment
-if (cliOptions.buildPages) {
- createErrorPages(options).catch((err) => handleError(err, 1));
-}
-
-// Convert scss to css
-if (cliOptions.compileCss) {
- stylesheets(options, Program.args[0]).catch((err) => handleError(err, 1));
-}
-
-// Compress/transpile the javascript files
-if (cliOptions.compileJs) {
- scripts(options, Program.args[0]).catch((err) => handleError(err, 1));
-}
-
-// Watch & Compile the javascript files in the media_source folder
-if (cliOptions.watch) {
- watching(Program.args[0]);
-}
-
-// Compile the Bootstrap javascript components
-if (cliOptions.compileBs) {
- bootstrapJs();
-}
-
-// Compile codemirror
-if (cliOptions.compileCodemirror) {
- compileCodemirror();
-}
-
-// Gzip js/css files
-if (cliOptions.gzip) {
- compressFiles();
-}
-
-// Compile the media manager
-if (cliOptions.comMedia) {
- // false indicates "no watch"
- mediaManager(false);
-}
-
-// Watch & Compile the media manager
-if (cliOptions.watchComMedia) {
- watchMediaManager(true);
-}
-
-// Compile the Workflow Graph
-if (cliOptions.comWorkflow) {
- // false indicates "no watch"
- workflowGraph(false);
-}
-
-// Watch & Compile the Workflow Graph
-if (cliOptions.watchComWorkflow) {
- watchWorkflowGraph(true);
-}
-
-// Update the .js/.css versions
-if (cliOptions.versioning) {
- versioning().catch((err) => handleError(err, 1));
-}
-
-// Prepare the repo for dev work
-if (cliOptions.prepare) {
- const bench = new Timer('Build');
- allowedVersion();
- recreateMediaFolder(options)
- .then(() => cleanVendors())
- .then(() => localisePackages(options))
- .then(() => patchPackages(options))
- .then(() => minifyVendor())
- .then(() => createErrorPages(options))
- .then(() => stylesheets(options, Program.args[0]))
- .then(() => cssVersioningVendor())
- .then(() => scripts(options, Program.args[0]))
- .then(() => mediaManager())
- .then(() => workflowGraph())
- .then(() => bootstrapJs())
- .then(() => compileCodemirror())
- .then(() => bench.stop('Build'))
- .catch((err) => handleError(err, -1));
-}
diff --git a/build/build.php b/build/build.php
index a942beb18b4..00edf252244 100644
--- a/build/build.php
+++ b/build/build.php
@@ -350,9 +350,6 @@ function capture_or_fail(string $command): string
// Create gzipped version of the static assets
run_and_check('npm run gzip');
-// Create version entries of the static assets in their respective joomla.asset.json
-run_and_check('npm run versioning');
-
// Clean the checkout of extra resources
if (!$debugBuild) {
clean_checkout($fullpath);
@@ -438,14 +435,13 @@ function capture_or_fail(string $command): string
'.gitignore',
'.php-cs-fixer.dist.php',
'acceptance.suite.yml',
- // Media Manager Node Assets
- 'administrator/components/com_media/resources',
'build',
'CODE_OF_CONDUCT.md',
'composer.json',
'composer.lock',
'crowdin.yml',
'cypress.config.dist.mjs',
+ 'media_source',
'package-lock.json',
'package.json',
'phpstan-baseline.neon',
diff --git a/build/media_source/system/scss/joomla-fontawesome.scss b/build/media_source/system/scss/joomla-fontawesome.scss
deleted file mode 100644
index 065b9145179..00000000000
--- a/build/media_source/system/scss/joomla-fontawesome.scss
+++ /dev/null
@@ -1,14 +0,0 @@
-// Override the font path
-$fa-font-path: "../../../media/vendor/fontawesome-free/webfonts" !default;
-$fa-font-display: block !default;
-
-// Font Awesome 6 Free
-@import "../../../../media/vendor/fontawesome-free/scss/fontawesome";
-@import "../../../../media/vendor/fontawesome-free/scss/regular";
-@import "../../../../media/vendor/fontawesome-free/scss/solid";
-
-// Brands must be imported last
-@import "../../../../media/vendor/fontawesome-free/scss/brands";
-
-// B/C for Icomoon
-@import "icomoon";
diff --git a/build/media_source/templates/administrator/atum/scss/vendor/awesomplete/awesomplete.scss b/build/media_source/templates/administrator/atum/scss/vendor/awesomplete/awesomplete.scss
deleted file mode 100644
index 639aa912dcd..00000000000
--- a/build/media_source/templates/administrator/atum/scss/vendor/awesomplete/awesomplete.scss
+++ /dev/null
@@ -1,6 +0,0 @@
-// Awesomplete
-@import "../../../../../../../../media/vendor/awesomplete/css/awesomplete";
-
-.awesomplete {
- display: block;
-}
diff --git a/build/media_source/vendor/jquery/js/jquery-noconflict.es6.js b/build/media_source/vendor/jquery/js/jquery-noconflict.es6.js
deleted file mode 100644
index 2f0120d756c..00000000000
--- a/build/media_source/vendor/jquery/js/jquery-noconflict.es6.js
+++ /dev/null
@@ -1,2 +0,0 @@
-// eslint-disable-next-line no-undef
-window.$ = jQuery.noConflict();
diff --git a/components/com_ajax/ajax.php b/components/com_ajax/ajax.php
index 69bd3838ae3..b54a0ba7201 100644
--- a/components/com_ajax/ajax.php
+++ b/components/com_ajax/ajax.php
@@ -14,6 +14,7 @@
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Log\Log;
+use Joomla\CMS\Plugin\Attribute\AllowUnauthorizedAdministratorAccess;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\Response\JsonResponse;
use Joomla\CMS\String\StringableInterface;
@@ -35,6 +36,30 @@
// Prevent the api url from being indexed
$app->setHeader('X-Robots-Tag', 'noindex, nofollow');
+$unauthorizedAdministratorAccessCheck = ($app->isClient('administrator') && $app->getIdentity()->guest);
+
+/**
+ * Validate the presence of the AllowUnauthorizedAdministratorAccess attribute on the method being called.
+ *
+ * @param $classOrObject
+ * @param $method
+ *
+ * @return void
+ * @throws \RuntimeException
+ */
+
+$verifyUnauthorizedAdministratorAccessCheck = function ($classOrObject, $method): void {
+ $reflection = new ReflectionMethod($classOrObject, $method);
+
+ foreach ($reflection->getAttributes() as $attribute) {
+ if ($attribute->getName() === AllowUnauthorizedAdministratorAccess::class) {
+ return;
+ }
+ }
+
+ throw new RuntimeException(Text::_('JERROR_ALERTNOAUTHOR'));
+};
+
// JInput object
$input = $app->getInput();
@@ -87,13 +112,23 @@
$moduleInstance = $app->bootModule('mod_' . $module, $app->getName());
if ($moduleInstance instanceof \Joomla\CMS\Helper\HelperFactoryInterface && $helper = $moduleInstance->getHelper(substr($class, 3))) {
- $results = method_exists($helper, $method . 'Ajax') ? $helper->{$method . 'Ajax'}() : null;
+ if (method_exists($helper, $method . 'Ajax')) {
+ if ($unauthorizedAdministratorAccessCheck) {
+ $verifyUnauthorizedAdministratorAccessCheck($helper, $method . 'Ajax');
+ }
+
+ $results = $helper->{$method . 'Ajax'}();
+ }
}
if ($results === null && is_file($helperFile)) {
JLoader::register($class, $helperFile);
if (method_exists($class, $method . 'Ajax')) {
+ if ($unauthorizedAdministratorAccessCheck) {
+ $verifyUnauthorizedAdministratorAccessCheck($class, $method . 'Ajax');
+ }
+
// Load language file for module
$basePath = JPATH_BASE;
$lang = Factory::getLanguage();
@@ -134,6 +169,12 @@
PluginHelper::importPlugin($group, null, true, $dispatcher);
+ if ($unauthorizedAdministratorAccessCheck) {
+ foreach ($dispatcher->getListeners($eventName) as $event) {
+ $verifyUnauthorizedAdministratorAccessCheck($event[0], $event[1]);
+ }
+ }
+
$results = $dispatcher->dispatch($eventName, new AjaxEvent($eventName, ['subject' => $app]))->getArgument('result', []);
} catch (Throwable $e) {
$results = $e;
@@ -179,6 +220,10 @@
JLoader::register($class, $helperFile);
if (method_exists($class, $method . 'Ajax')) {
+ if ($unauthorizedAdministratorAccessCheck) {
+ $verifyUnauthorizedAdministratorAccessCheck($class, $method . 'Ajax');
+ }
+
// Load language file for template
$lang = Factory::getLanguage();
$lang->load('tpl_' . $template, $basePath)
diff --git a/components/com_content/tmpl/category/blog_links.php b/components/com_content/tmpl/category/blog_links.php
index f051000bdaa..ce067d1c00c 100644
--- a/components/com_content/tmpl/category/blog_links.php
+++ b/components/com_content/tmpl/category/blog_links.php
@@ -20,7 +20,7 @@
link_items as $item) : ?>
- title; ?>
+ escape($item->title); ?>
diff --git a/components/com_content/tmpl/featured/default_links.php b/components/com_content/tmpl/featured/default_links.php
index 5cd908911bf..1b308d951ac 100644
--- a/components/com_content/tmpl/featured/default_links.php
+++ b/components/com_content/tmpl/featured/default_links.php
@@ -19,7 +19,7 @@
link_items as $item) : ?>
- title; ?>
+ escape($item->title); ?>
diff --git a/includes/incompatible.html b/includes/incompatible.html
index a2e693105fd..113843b4b6b 100644
--- a/includes/incompatible.html
+++ b/includes/incompatible.html
@@ -5,7 +5,7 @@
Joomla: unsupported PHP version
-
+
diff --git a/installation/language/af-ZA/langmetadata.xml b/installation/language/af-ZA/langmetadata.xml
index a6b58c41c8d..35519201078 100644
--- a/installation/language/af-ZA/langmetadata.xml
+++ b/installation/language/af-ZA/langmetadata.xml
@@ -1,8 +1,8 @@
Afrikaans (Suid-Afrika)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Afrikaans Translation Team
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/ar-AA/langmetadata.xml b/installation/language/ar-AA/langmetadata.xml
index d01da03c149..b9c1c47698e 100644
--- a/installation/language/ar-AA/langmetadata.xml
+++ b/installation/language/ar-AA/langmetadata.xml
@@ -1,8 +1,8 @@
Arabic (اللغة العربية)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Joomla! Project (Arabic Translation Team)
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/be-BY/langmetadata.xml b/installation/language/be-BY/langmetadata.xml
index 100c196aa3f..c3474c56d88 100644
--- a/installation/language/be-BY/langmetadata.xml
+++ b/installation/language/be-BY/langmetadata.xml
@@ -1,8 +1,8 @@
Belarusian (be-BY)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Joomla Belarus Community
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/bg-BG/langmetadata.xml b/installation/language/bg-BG/langmetadata.xml
index 59ce448b42e..0123a527774 100644
--- a/installation/language/bg-BG/langmetadata.xml
+++ b/installation/language/bg-BG/langmetadata.xml
@@ -1,8 +1,8 @@
Bulgarian (bg-BG)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Joomla! Bulgaria
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/ca-ES/langmetadata.xml b/installation/language/ca-ES/langmetadata.xml
index c10087d1856..6da6dbdf2e1 100644
--- a/installation/language/ca-ES/langmetadata.xml
+++ b/installation/language/ca-ES/langmetadata.xml
@@ -1,8 +1,8 @@
Catalan (ca-ES)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Catalan [ca-ES] Translation Team
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/cs-CZ/langmetadata.xml b/installation/language/cs-CZ/langmetadata.xml
index 6f51d19d225..f233b9a34ed 100644
--- a/installation/language/cs-CZ/langmetadata.xml
+++ b/installation/language/cs-CZ/langmetadata.xml
@@ -1,8 +1,8 @@
Czech (Čeština)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Czech Translation Team
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/cy-GB/langmetadata.xml b/installation/language/cy-GB/langmetadata.xml
index 95441699941..4e7e7e13781 100644
--- a/installation/language/cy-GB/langmetadata.xml
+++ b/installation/language/cy-GB/langmetadata.xml
@@ -1,8 +1,8 @@
Welsh (United Kingdom)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Joomla! Project - Welsh Translation Team
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/da-DK/langmetadata.xml b/installation/language/da-DK/langmetadata.xml
index 97ac1bb1431..d89a0c77e47 100644
--- a/installation/language/da-DK/langmetadata.xml
+++ b/installation/language/da-DK/langmetadata.xml
@@ -1,8 +1,8 @@
Danish (Danmark)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Danish Translation Team (Transl.: Ronny Buelund)
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/de-AT/joomla.ini b/installation/language/de-AT/joomla.ini
index 7cecdf7f7dd..3cf125503c3 100644
--- a/installation/language/de-AT/joomla.ini
+++ b/installation/language/de-AT/joomla.ini
@@ -165,7 +165,7 @@ INSTL_DEFAULTLANGUAGE_DESC_FRONTEND="Joomla hat folgende Sprachen installiert. B
INSTL_DEFAULTLANGUAGE_FRONTEND="Standard-Sprache: Website"
INSTL_DEFAULTLANGUAGE_FRONTEND_COULDNT_SET_DEFAULT="Joomla war es nicht möglich die Sprache als Standard festzulegen. Englisch wird daher als Standard-Sprache für die WEBSITE (Frontend) verwendet."
INSTL_DEFAULTLANGUAGE_FRONTEND_SET_DEFAULT="Die Sprache mit dem Sprach-Tag „%s“ wurde zur Standard-Sprache für die WEBSITE festgelegt."
-INSTL_DEFAULTLANGUAGE_SET_DEFAULT_LANGUAGE="Standardsprache konfigurieren"
+INSTL_DEFAULTLANGUAGE_SET_DEFAULT_LANGUAGE="Standardsprache festlegen"
INSTL_DEFAULTLANGUAGE_TRY_LATER="Weitere Sprachen können auch noch später in der Administration von Joomla installiert werden."
INSTL_DEFAULTLANGUAGE_NATIVE_LANGUAGE_NAME="Deutsch (Österreich)" ; IMPORTANT NOTE FOR TRANSLATORS: Do not literally translate this line, instead add the localised name of the language. For example Spanish will be Español
diff --git a/installation/language/de-AT/langmetadata.xml b/installation/language/de-AT/langmetadata.xml
index daeb249bebb..5c77b315fe0 100644
--- a/installation/language/de-AT/langmetadata.xml
+++ b/installation/language/de-AT/langmetadata.xml
@@ -1,8 +1,8 @@
German (Austria)
- 6.0.3
- 2026-02
+ 6.1.0
+ 2026-04
J!German
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/de-CH/joomla.ini b/installation/language/de-CH/joomla.ini
index 7f92588ee26..01425cd2c87 100644
--- a/installation/language/de-CH/joomla.ini
+++ b/installation/language/de-CH/joomla.ini
@@ -165,7 +165,7 @@ INSTL_DEFAULTLANGUAGE_DESC_FRONTEND="Joomla hat folgende Sprachen installiert. B
INSTL_DEFAULTLANGUAGE_FRONTEND="Standard-Sprache: Website"
INSTL_DEFAULTLANGUAGE_FRONTEND_COULDNT_SET_DEFAULT="Joomla war es nicht möglich die Sprache als Standard festzulegen. Englisch wird daher als Standard-Sprache für die WEBSITE (Frontend) verwendet."
INSTL_DEFAULTLANGUAGE_FRONTEND_SET_DEFAULT="Die Sprache mit dem Sprach-Tag „%s“ wurde zur Standard-Sprache für die WEBSITE festgelegt."
-INSTL_DEFAULTLANGUAGE_SET_DEFAULT_LANGUAGE="Standardsprache konfigurieren"
+INSTL_DEFAULTLANGUAGE_SET_DEFAULT_LANGUAGE="Standardsprache festlegen"
INSTL_DEFAULTLANGUAGE_TRY_LATER="Weitere Sprachen können auch noch später in der Administration von Joomla installiert werden."
INSTL_DEFAULTLANGUAGE_NATIVE_LANGUAGE_NAME="Deutsch (Schweiz)" ; IMPORTANT NOTE FOR TRANSLATORS: Do not literally translate this line, instead add the localised name of the language. For example Spanish will be Español
diff --git a/installation/language/de-CH/langmetadata.xml b/installation/language/de-CH/langmetadata.xml
index a75e27af96b..22078e82315 100644
--- a/installation/language/de-CH/langmetadata.xml
+++ b/installation/language/de-CH/langmetadata.xml
@@ -1,8 +1,8 @@
German (Switzerland)
- 6.0.3
- 2026-02
+ 6.1.0
+ 2026-04
J!German
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/de-DE/joomla.ini b/installation/language/de-DE/joomla.ini
index dad67771f0d..8e4297eb6fa 100644
--- a/installation/language/de-DE/joomla.ini
+++ b/installation/language/de-DE/joomla.ini
@@ -165,7 +165,7 @@ INSTL_DEFAULTLANGUAGE_DESC_FRONTEND="Joomla hat folgende Sprachen installiert. B
INSTL_DEFAULTLANGUAGE_FRONTEND="Standard-Sprache: Website"
INSTL_DEFAULTLANGUAGE_FRONTEND_COULDNT_SET_DEFAULT="Joomla war es nicht möglich die Sprache als Standard festzulegen. Englisch wird daher als Standard-Sprache für die WEBSITE (Frontend) verwendet."
INSTL_DEFAULTLANGUAGE_FRONTEND_SET_DEFAULT="Die Sprache mit dem Sprach-Tag „%s“ wurde zur Standard-Sprache für die WEBSITE festgelegt."
-INSTL_DEFAULTLANGUAGE_SET_DEFAULT_LANGUAGE="Standardsprache konfigurieren"
+INSTL_DEFAULTLANGUAGE_SET_DEFAULT_LANGUAGE="Standardsprache festlegen"
INSTL_DEFAULTLANGUAGE_TRY_LATER="Weitere Sprachen können auch noch später in der Administration von Joomla installiert werden."
INSTL_DEFAULTLANGUAGE_NATIVE_LANGUAGE_NAME="Deutsch (Deutschland)" ; IMPORTANT NOTE FOR TRANSLATORS: Do not literally translate this line, instead add the localised name of the language. For example Spanish will be Español
diff --git a/installation/language/de-DE/langmetadata.xml b/installation/language/de-DE/langmetadata.xml
index 6ebf7033d9d..40cf7bd3423 100644
--- a/installation/language/de-DE/langmetadata.xml
+++ b/installation/language/de-DE/langmetadata.xml
@@ -1,8 +1,8 @@
German (Germany)
- 6.0.3
- 2026-02
+ 6.1.0
+ 2026-04
J!German
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/de-LI/joomla.ini b/installation/language/de-LI/joomla.ini
index 50660a6fa4b..d167e53f9d5 100644
--- a/installation/language/de-LI/joomla.ini
+++ b/installation/language/de-LI/joomla.ini
@@ -165,7 +165,7 @@ INSTL_DEFAULTLANGUAGE_DESC_FRONTEND="Joomla hat folgende Sprachen installiert. B
INSTL_DEFAULTLANGUAGE_FRONTEND="Standard-Sprache: Website"
INSTL_DEFAULTLANGUAGE_FRONTEND_COULDNT_SET_DEFAULT="Joomla war es nicht möglich die Sprache als Standard festzulegen. Englisch wird daher als Standard-Sprache für die WEBSITE (Frontend) verwendet."
INSTL_DEFAULTLANGUAGE_FRONTEND_SET_DEFAULT="Die Sprache mit dem Sprach-Tag „%s“ wurde zur Standard-Sprache für die WEBSITE festgelegt."
-INSTL_DEFAULTLANGUAGE_SET_DEFAULT_LANGUAGE="Standardsprache konfigurieren"
+INSTL_DEFAULTLANGUAGE_SET_DEFAULT_LANGUAGE="Standardsprache festlegen"
INSTL_DEFAULTLANGUAGE_TRY_LATER="Weitere Sprachen können auch noch später in der Administration von Joomla installiert werden."
INSTL_DEFAULTLANGUAGE_NATIVE_LANGUAGE_NAME="Deutsch (Liechtenstein)" ; IMPORTANT NOTE FOR TRANSLATORS: Do not literally translate this line, instead add the localised name of the language. For example Spanish will be Español
diff --git a/installation/language/de-LI/langmetadata.xml b/installation/language/de-LI/langmetadata.xml
index 8b0c58d0202..c5ec5d31699 100644
--- a/installation/language/de-LI/langmetadata.xml
+++ b/installation/language/de-LI/langmetadata.xml
@@ -1,8 +1,8 @@
German (Liechtenstein)
- 6.0.3
- 2026-02
+ 6.1.0
+ 2026-04
J!German
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/de-LU/joomla.ini b/installation/language/de-LU/joomla.ini
index cf8f191ece6..0633b8bc928 100644
--- a/installation/language/de-LU/joomla.ini
+++ b/installation/language/de-LU/joomla.ini
@@ -165,7 +165,7 @@ INSTL_DEFAULTLANGUAGE_DESC_FRONTEND="Joomla hat folgende Sprachen installiert. B
INSTL_DEFAULTLANGUAGE_FRONTEND="Standard-Sprache: Website"
INSTL_DEFAULTLANGUAGE_FRONTEND_COULDNT_SET_DEFAULT="Joomla war es nicht möglich die Sprache als Standard festzulegen. Englisch wird daher als Standard-Sprache für die WEBSITE (Frontend) verwendet."
INSTL_DEFAULTLANGUAGE_FRONTEND_SET_DEFAULT="Die Sprache mit dem Sprach-Tag „%s“ wurde zur Standard-Sprache für die WEBSITE festgelegt."
-INSTL_DEFAULTLANGUAGE_SET_DEFAULT_LANGUAGE="Standardsprache konfigurieren"
+INSTL_DEFAULTLANGUAGE_SET_DEFAULT_LANGUAGE="Standardsprache festlegen"
INSTL_DEFAULTLANGUAGE_TRY_LATER="Weitere Sprachen können auch noch später in der Administration von Joomla installiert werden."
INSTL_DEFAULTLANGUAGE_NATIVE_LANGUAGE_NAME="Deutsch (Luxemburg)" ; IMPORTANT NOTE FOR TRANSLATORS: Do not literally translate this line, instead add the localised name of the language. For example Spanish will be Español
diff --git a/installation/language/de-LU/langmetadata.xml b/installation/language/de-LU/langmetadata.xml
index c62126f20f9..726e786948d 100644
--- a/installation/language/de-LU/langmetadata.xml
+++ b/installation/language/de-LU/langmetadata.xml
@@ -1,8 +1,8 @@
German (Luxembourg)
- 6.0.3
- 2026-02
+ 6.1.0
+ 2026-04
J!German
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/el-GR/langmetadata.xml b/installation/language/el-GR/langmetadata.xml
index e7a49a1fbee..55b946679e3 100644
--- a/installation/language/el-GR/langmetadata.xml
+++ b/installation/language/el-GR/langmetadata.xml
@@ -1,8 +1,8 @@
Greek (el-GR)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Ομάδα Μετάφρασης: joomla. gr
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/en-AU/langmetadata.xml b/installation/language/en-AU/langmetadata.xml
index 77fbbc9c14e..7a9bfee1ea7 100644
--- a/installation/language/en-AU/langmetadata.xml
+++ b/installation/language/en-AU/langmetadata.xml
@@ -1,8 +1,8 @@
English (Australia)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Joomla! Project
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/en-CA/langmetadata.xml b/installation/language/en-CA/langmetadata.xml
index 5f622def0a9..84ff21e16a1 100644
--- a/installation/language/en-CA/langmetadata.xml
+++ b/installation/language/en-CA/langmetadata.xml
@@ -1,8 +1,8 @@
English (Canada)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Joomla! Project
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/en-NZ/langmetadata.xml b/installation/language/en-NZ/langmetadata.xml
index 587d1dd007f..1ecc8a15fea 100644
--- a/installation/language/en-NZ/langmetadata.xml
+++ b/installation/language/en-NZ/langmetadata.xml
@@ -1,8 +1,8 @@
English (New Zealand)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Joomla! Project
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/en-US/langmetadata.xml b/installation/language/en-US/langmetadata.xml
index fdbafc5f8d7..53f6d71af2b 100644
--- a/installation/language/en-US/langmetadata.xml
+++ b/installation/language/en-US/langmetadata.xml
@@ -1,8 +1,8 @@
English (United States)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Joomla! Project
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/es-ES/langmetadata.xml b/installation/language/es-ES/langmetadata.xml
index faa2a82eb5c..0dedc397ed4 100644
--- a/installation/language/es-ES/langmetadata.xml
+++ b/installation/language/es-ES/langmetadata.xml
@@ -1,8 +1,8 @@
Spanish (es-ES)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Spanish [es-ES] Translation Team
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/et-EE/langmetadata.xml b/installation/language/et-EE/langmetadata.xml
index 6ae88a3f1ea..1db99538dec 100644
--- a/installation/language/et-EE/langmetadata.xml
+++ b/installation/language/et-EE/langmetadata.xml
@@ -1,8 +1,8 @@
Estonian
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Joomla! Project
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/eu-ES/langmetadata.xml b/installation/language/eu-ES/langmetadata.xml
index f1ebf16b33a..0e1505ad370 100644
--- a/installation/language/eu-ES/langmetadata.xml
+++ b/installation/language/eu-ES/langmetadata.xml
@@ -1,8 +1,8 @@
Basque
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Joomla! Basque Translation Team
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/fa-AF/langmetadata.xml b/installation/language/fa-AF/langmetadata.xml
index 28bb3e592be..9c4c77788a5 100644
--- a/installation/language/fa-AF/langmetadata.xml
+++ b/installation/language/fa-AF/langmetadata.xml
@@ -1,8 +1,8 @@
فارسی (دری)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
JoomlaPersian Translation Team
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/fa-IR/langmetadata.xml b/installation/language/fa-IR/langmetadata.xml
index f56eed84abc..0ada3949333 100644
--- a/installation/language/fa-IR/langmetadata.xml
+++ b/installation/language/fa-IR/langmetadata.xml
@@ -1,8 +1,8 @@
Persian (fa-IR)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Persian Translation Team: joomlafarsi.com
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/fi-FI/langmetadata.xml b/installation/language/fi-FI/langmetadata.xml
index 501466fadf9..dbc115ed60a 100644
--- a/installation/language/fi-FI/langmetadata.xml
+++ b/installation/language/fi-FI/langmetadata.xml
@@ -1,8 +1,8 @@
Finnish (Finland)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Finnish translation team: Joomla.fi
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/fr-CA/langmetadata.xml b/installation/language/fr-CA/langmetadata.xml
index 6a028a16d8d..d5a69d863d4 100644
--- a/installation/language/fr-CA/langmetadata.xml
+++ b/installation/language/fr-CA/langmetadata.xml
@@ -1,8 +1,8 @@
French (Canada)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Joomla! Project - Canadian translation team
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/fr-FR/langmetadata.xml b/installation/language/fr-FR/langmetadata.xml
index 3aea144d680..b6ce9ba9107 100644
--- a/installation/language/fr-FR/langmetadata.xml
+++ b/installation/language/fr-FR/langmetadata.xml
@@ -1,8 +1,8 @@
French (fr-FR)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Joomla! Project - French translation team
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/he-IL/langmetadata.xml b/installation/language/he-IL/langmetadata.xml
index 0f261ada8f3..6f633559dd7 100644
--- a/installation/language/he-IL/langmetadata.xml
+++ b/installation/language/he-IL/langmetadata.xml
@@ -1,8 +1,8 @@
Hebrew (Israel)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
פרוייקט ג'ומלה
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/hr-HR/langmetadata.xml b/installation/language/hr-HR/langmetadata.xml
index b7020b650ec..f42506bd273 100644
--- a/installation/language/hr-HR/langmetadata.xml
+++ b/installation/language/hr-HR/langmetadata.xml
@@ -1,8 +1,8 @@
Hrvatski (Hrvatska)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Joomla! Hrvatska team
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/hu-HU/langmetadata.xml b/installation/language/hu-HU/langmetadata.xml
index 0bdcf513c4f..af58bb1db4c 100644
--- a/installation/language/hu-HU/langmetadata.xml
+++ b/installation/language/hu-HU/langmetadata.xml
@@ -1,8 +1,8 @@
Hungarian (Magyar)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Joomla! Magyarország
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/id-ID/langmetadata.xml b/installation/language/id-ID/langmetadata.xml
index 565044ab4a8..15d598cbcf2 100644
--- a/installation/language/id-ID/langmetadata.xml
+++ b/installation/language/id-ID/langmetadata.xml
@@ -1,8 +1,8 @@
Bahasa Indonesia (id-ID)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Joomla! Indonesia
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/it-IT/langmetadata.xml b/installation/language/it-IT/langmetadata.xml
index a6efaeff4ce..94245ac2f3d 100644
--- a/installation/language/it-IT/langmetadata.xml
+++ b/installation/language/it-IT/langmetadata.xml
@@ -1,8 +1,8 @@
Italiano (it-IT)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Joomla! Project (Italian Translation Team)
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/ja-JP/langmetadata.xml b/installation/language/ja-JP/langmetadata.xml
index e3d5328daaa..22d64e8366e 100644
--- a/installation/language/ja-JP/langmetadata.xml
+++ b/installation/language/ja-JP/langmetadata.xml
@@ -1,8 +1,8 @@
Japanese (Japan)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Joomla!じゃぱん
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/ka-GE/langmetadata.xml b/installation/language/ka-GE/langmetadata.xml
index e8b8c125fb6..ec33a2f5515 100644
--- a/installation/language/ka-GE/langmetadata.xml
+++ b/installation/language/ka-GE/langmetadata.xml
@@ -1,8 +1,8 @@
Georgian (Georgia)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Georgian Translation Team
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/kk-KZ/langmetadata.xml b/installation/language/kk-KZ/langmetadata.xml
index 1217d7da5ff..c01ec2d536c 100644
--- a/installation/language/kk-KZ/langmetadata.xml
+++ b/installation/language/kk-KZ/langmetadata.xml
@@ -1,8 +1,8 @@
Kazakh (Kazakhstan)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Sarvarov Akylkerey
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/ko-KR/langmetadata.xml b/installation/language/ko-KR/langmetadata.xml
index 788c44e11bc..337a83ecab5 100644
--- a/installation/language/ko-KR/langmetadata.xml
+++ b/installation/language/ko-KR/langmetadata.xml
@@ -1,8 +1,8 @@
Korean (ko-KR)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Joomla! 프로젝트
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/lt-LT/langmetadata.xml b/installation/language/lt-LT/langmetadata.xml
index fba9121409f..b60e9a233b7 100644
--- a/installation/language/lt-LT/langmetadata.xml
+++ b/installation/language/lt-LT/langmetadata.xml
@@ -1,8 +1,8 @@
Lietuvių (lt-LT)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Oskaras Jankauskas
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/lv-LV/joomla.cli.ini b/installation/language/lv-LV/joomla.cli.ini
index 94beb0d5dd5..7092dd9ee3c 100644
--- a/installation/language/lv-LV/joomla.cli.ini
+++ b/installation/language/lv-LV/joomla.cli.ini
@@ -1,6 +1,38 @@
+INSTL_ADMIN_EMAIL_DESC="Ievadiet lapas Super User e-pasta adresi"
+INSTL_ADMIN_EMAIL_DESC_SHORT="Vietnes superlietotāja konta e-pasta adrese"
+INSTL_ADMIN_PASSWORD_DESC="Ievadiet Super User konta paroli"
+INSTL_ADMIN_PASSWORD_DESC_SHORT="Super User konta parole"
+INSTL_ADMIN_USERNAME_DESC="Ievadiet galvenā administratora lietotāja vārdu"
+INSTL_ADMIN_USERNAME_DESC_SHORT="Super User konta lietotājvārds"
+INSTL_ADMIN_USER_DESC="Ievadiet galvenā administratora vārdu"
+INSTL_ADMIN_USER_DESC_SHORT="Super User konta vārds"
INSTL_DATABASE_COULD_NOT_CONNECT="%s"
+INSTL_DATABASE_ENCRYPTION_CA_LABEL="Ceļš uz CA failu šifrēšanas pārbaudei"
+INSTL_DATABASE_ENCRYPTION_CA_LABEL_SHORT="Ceļš uz CA failu šifrēšanas pārbaudei"
+INSTL_DATABASE_ENCRYPTION_CERT_LABEL="Ceļš uz SSL sertifikātu datubāzes savienojumam. Nepieciešams, lai šifrēšana būtu iestatīta uz 2"
+INSTL_DATABASE_ENCRYPTION_CERT_LABEL_SHORT="Ceļš uz SSL sertifikātu datubāzes savienojumam. Nepieciešams, lai šifrēšana būtu iestatīta uz 2"
INSTL_DATABASE_ENCRYPTION_CIPHER_LABEL="Atbalstītais Šifrēšanas veids (opcija)"
INSTL_DATABASE_ENCRYPTION_CIPHER_LABEL_SHORT="Atbalstītais Šifrēšanas veids (opcija)"
+INSTL_DATABASE_ENCRYPTION_KEY_LABEL="SSL atslēga datubāzes savienojumam. Nepieciešams, lai šifrēšana būtu iestatīta uz 2"
+INSTL_DATABASE_ENCRYPTION_KEY_LABEL_SHORT="SSL atslēga datubāzes savienojumam. Nepieciešams, lai šifrēšana būtu iestatīta uz 2"
+INSTL_DATABASE_ENCRYPTION_MODE_LABEL="Šifrēšana datubāzes savienojumam. Vērtības: 0=Nav, 1=Vienvirziena, 2=Divvirzienu"
+INSTL_DATABASE_ENCRYPTION_MODE_LABEL_SHORT="Šifrēšana datubāzes savienojumam. Vērtības: 0=Nav, 1=Vienvirziena, 2=Divvirzienu"
+INSTL_DATABASE_ENCRYPTION_VERIFY_SERVER_CERT_LABEL="Verificēt SSL sertifikātu datubāzes savienojumam. Vērtības: 0=Nē, 1=Jā. Nepieciešams, lai šifrēšana būtu iestatīta uz 1 vai 2"
+INSTL_DATABASE_ENCRYPTION_VERIFY_SERVER_CERT_LABEL_SHORT="Verificēt SSL sertifikātu datubāzes savienojumam. Vērtības: 0=Nē, 1=Jā. Nepieciešams, lai šifrēšana būtu iestatīta uz 1 vai 2"
+INSTL_DATABASE_HOST_DESC="Datubāzes serveris"
+INSTL_DATABASE_HOST_DESC_SHORT="Datubāzes serveris"
+INSTL_DATABASE_NAME_DESC="Datu bāzes nosaukums"
+INSTL_DATABASE_NAME_DESC_SHORT="Datu bāzes nosaukums"
+INSTL_DATABASE_PASSWORD_DESC="Datubāzes parole"
+INSTL_DATABASE_PASSWORD_DESC_SHORT="Datubāzes parole"
+INSTL_DATABASE_PREFIX_DESC="Datubāzes tabulas prefikss tabulām"
+INSTL_DATABASE_PREFIX_DESC_SHORT="Datubāzes tabulas prefikss tabulām"
+INSTL_DATABASE_TYPE_DESC="Datubāzes veids. Atbalstītās: mysql, mysqli, pgsql"
+INSTL_DATABASE_TYPE_DESC_SHORT="Datubāzes veids. Joomla atbalstītās: mysql (=MySQL (PDO)), mysqli (=MySQLi), pgsql (=PostgreSQL (PDO))"
+INSTL_DATABASE_USER_DESC="Datubāzes lietotāja vārds"
+INSTL_DATABASE_USER_DESC_SHORT="Datubāzes lietotāja vārds"
INSTL_PUBLIC_FOLDER_DESC="Relatīvais vai absolūtais ceļš uz publisko direktoriju"
INSTL_PUBLIC_FOLDER_DESC_SHORT="Relatīvais vai absolūtais ceļš uz publisko direktoriju"
+INSTL_SITE_NAME_DESC="Ievadiet lapas nosaukumu"
+INSTL_SITE_NAME_DESC_SHORT="Lapas nosaukums"
diff --git a/installation/language/lv-LV/langmetadata.xml b/installation/language/lv-LV/langmetadata.xml
index cad9e43d288..a7188392368 100644
--- a/installation/language/lv-LV/langmetadata.xml
+++ b/installation/language/lv-LV/langmetadata.xml
@@ -1,8 +1,8 @@
Latvian (Latvia)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Joomla! Projekts
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/mk-MK/langmetadata.xml b/installation/language/mk-MK/langmetadata.xml
index 57559035291..57261357838 100644
--- a/installation/language/mk-MK/langmetadata.xml
+++ b/installation/language/mk-MK/langmetadata.xml
@@ -1,8 +1,8 @@
Macedonian (mk-MK)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Joomla! Project
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/nl-BE/langmetadata.xml b/installation/language/nl-BE/langmetadata.xml
index c0f0477bc09..1527582c747 100644
--- a/installation/language/nl-BE/langmetadata.xml
+++ b/installation/language/nl-BE/langmetadata.xml
@@ -1,8 +1,8 @@
Dutch (Belgium)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Dutch (BE) translation team
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/nl-NL/langmetadata.xml b/installation/language/nl-NL/langmetadata.xml
index 563682b68f4..1d91f9e2889 100644
--- a/installation/language/nl-NL/langmetadata.xml
+++ b/installation/language/nl-NL/langmetadata.xml
@@ -1,8 +1,8 @@
Dutch (nl-NL)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Dutch Translation Team
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/pt-BR/langmetadata.xml b/installation/language/pt-BR/langmetadata.xml
index c15f7617be8..bf374983b28 100644
--- a/installation/language/pt-BR/langmetadata.xml
+++ b/installation/language/pt-BR/langmetadata.xml
@@ -1,8 +1,8 @@
Português do Brasil (pt-BR)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Projeto Joomla!
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/pt-PT/langmetadata.xml b/installation/language/pt-PT/langmetadata.xml
index 9b7f1a1d21c..a573d0f3d9b 100644
--- a/installation/language/pt-PT/langmetadata.xml
+++ b/installation/language/pt-PT/langmetadata.xml
@@ -1,8 +1,8 @@
Português (Portugal)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Comunidade JoomlaPortugal
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/ro-RO/langmetadata.xml b/installation/language/ro-RO/langmetadata.xml
index 9eb4c6a05f9..2bd7b708035 100644
--- a/installation/language/ro-RO/langmetadata.xml
+++ b/installation/language/ro-RO/langmetadata.xml
@@ -1,8 +1,8 @@
Română (România)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Horia Negura - Quanta
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/sk-SK/langmetadata.xml b/installation/language/sk-SK/langmetadata.xml
index ce54ee10c19..46a78c65a76 100644
--- a/installation/language/sk-SK/langmetadata.xml
+++ b/installation/language/sk-SK/langmetadata.xml
@@ -1,8 +1,8 @@
Slovak (Slovakia)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Slovak translation team : Peter Michnica
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/sl-SI/langmetadata.xml b/installation/language/sl-SI/langmetadata.xml
index 5e7a9db7f26..b28a2042491 100644
--- a/installation/language/sl-SI/langmetadata.xml
+++ b/installation/language/sl-SI/langmetadata.xml
@@ -1,8 +1,8 @@
Slovenščina (Slovenija)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Slovenska prevajalska ekipa
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/sr-YU/langmetadata.xml b/installation/language/sr-YU/langmetadata.xml
index 5d811d6cfc9..5576d4fd38d 100644
--- a/installation/language/sr-YU/langmetadata.xml
+++ b/installation/language/sr-YU/langmetadata.xml
@@ -1,8 +1,8 @@
Srpski (Republika Srbija)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Goran Nešić & Saša Matić
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/sv-SE/langmetadata.xml b/installation/language/sv-SE/langmetadata.xml
index 54eff3fe3cc..56b999f3e41 100644
--- a/installation/language/sv-SE/langmetadata.xml
+++ b/installation/language/sv-SE/langmetadata.xml
@@ -1,8 +1,8 @@
Swedish (Sweden)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Swedish Translation Team - SvenskJoomla
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/ta-IN/langmetadata.xml b/installation/language/ta-IN/langmetadata.xml
index 05aaa62ffeb..6ff9a110ed8 100644
--- a/installation/language/ta-IN/langmetadata.xml
+++ b/installation/language/ta-IN/langmetadata.xml
@@ -1,8 +1,8 @@
Tamil (India)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Ilagnayeru 'MIG' Manickam, Elango Samy Manim
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/th-TH/langmetadata.xml b/installation/language/th-TH/langmetadata.xml
index e27b1df26e8..8f27a64c793 100644
--- a/installation/language/th-TH/langmetadata.xml
+++ b/installation/language/th-TH/langmetadata.xml
@@ -1,8 +1,8 @@
Thai (ภาษาไทย)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Thai Translation Team
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/tr-TR/langmetadata.xml b/installation/language/tr-TR/langmetadata.xml
index f35b0d78469..f588f9474e3 100644
--- a/installation/language/tr-TR/langmetadata.xml
+++ b/installation/language/tr-TR/langmetadata.xml
@@ -1,8 +1,8 @@
Turkish (Turkey)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Joomla! Türkiye
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/uk-UA/langmetadata.xml b/installation/language/uk-UA/langmetadata.xml
index e24bcb6c1ce..57148882e6a 100644
--- a/installation/language/uk-UA/langmetadata.xml
+++ b/installation/language/uk-UA/langmetadata.xml
@@ -1,8 +1,8 @@
Ukrainian (uk-UA)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Denys Nosov
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/ur-PK/langmetadata.xml b/installation/language/ur-PK/langmetadata.xml
index 2fbe55b2227..14d9d2a9c6b 100644
--- a/installation/language/ur-PK/langmetadata.xml
+++ b/installation/language/ur-PK/langmetadata.xml
@@ -1,8 +1,8 @@
Urdu (ur-PK)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Urdu Translation Team
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/vi-VN/langmetadata.xml b/installation/language/vi-VN/langmetadata.xml
index e376d6d6614..9f2d5afb237 100644
--- a/installation/language/vi-VN/langmetadata.xml
+++ b/installation/language/vi-VN/langmetadata.xml
@@ -1,8 +1,8 @@
Vietnamese (Vietnam)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Joomla! Project
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/zh-CN/langmetadata.xml b/installation/language/zh-CN/langmetadata.xml
index 3bf329515b8..b787f3a615d 100644
--- a/installation/language/zh-CN/langmetadata.xml
+++ b/installation/language/zh-CN/langmetadata.xml
@@ -1,8 +1,8 @@
Chinese Simplified (China)
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
Joomla中文网
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/installation/language/zh-TW/langmetadata.xml b/installation/language/zh-TW/langmetadata.xml
index 0cf3e6d93d8..e7effc7a5b1 100644
--- a/installation/language/zh-TW/langmetadata.xml
+++ b/installation/language/zh-TW/langmetadata.xml
@@ -1,8 +1,8 @@
正體中文
- 6.0.4
- 2026-02
+ 6.1.0
+ 2026-03
正體中文 Translation Team
(C) 2005 Open Source Matters, Inc.
GNU General Public License version 2 or later; see LICENSE.txt
diff --git a/language/en-GB/mod_articles.ini b/language/en-GB/mod_articles.ini
index c5c6db00396..64a22c77842 100644
--- a/language/en-GB/mod_articles.ini
+++ b/language/en-GB/mod_articles.ini
@@ -68,7 +68,7 @@ MOD_ARTICLES_FIELD_TITLEONLY_LABEL="Title Only (lists)"
MOD_ARTICLES_FIELD_TITLE_HEADING="Header Level"
MOD_ARTICLES_FIELD_TITLE_HEADING_NONE="None"
MOD_ARTICLES_FIELD_TITLE_LABEL="Article Title"
-MOD_ARTICLES_FIELD_TRIGGER_EVENTS_DESC="Enable this option to trigger three plugin events (afterDisplayTitle, beforeDisplayContent, afterDisplayContent) for each article in the results list."
+MOD_ARTICLES_FIELD_TRIGGER_EVENTS_DESC="Enable this option to trigger four plugin events (onContentPrepare, afterDisplayTitle, beforeDisplayContent, afterDisplayContent) for each article in the results list."
MOD_ARTICLES_FIELD_TRIGGER_EVENTS_LABEL="Trigger Plugin Events"
MOD_ARTICLES_FIELD_UNPUBLISHED_LABEL="Show Unpublished Articles"
MOD_ARTICLES_INFO="Details"
diff --git a/layouts/joomla/content/readmore.php b/layouts/joomla/content/readmore.php
index 53127a969bd..b2db3373e7b 100644
--- a/layouts/joomla/content/readmore.php
+++ b/layouts/joomla/content/readmore.php
@@ -30,7 +30,7 @@
'; ?>
get('show_readmore_title', 0) != 0) : ?>
- title, $params->get('readmore_limit')); ?>
+ title, $params->get('readmore_limit'), false); ?>
get('show_readmore_title', 0) == 0) : ?>
@@ -41,7 +41,7 @@
'; ?>
- title, $params->get('readmore_limit'))); ?>
+ title, $params->get('readmore_limit'), false)); ?>
diff --git a/layouts/joomla/form/field/modal-select.php b/layouts/joomla/form/field/modal-select.php
index 04a11b89ebf..967d9798fe8 100644
--- a/layouts/joomla/form/field/modal-select.php
+++ b/layouts/joomla/form/field/modal-select.php
@@ -56,12 +56,12 @@
$wa->useScript('modal-content-select-field');
}
-$fieldClass = $required ? 'required modal-value' : '';
+$titleClass = $required ? ' required' : '';
?>
>
-
@@ -72,6 +72,6 @@
endif; ?>
-
/>
diff --git a/libraries/src/Form/Rule/ShowOnRule.php b/libraries/src/Form/Rule/ShowOnRule.php
index 22fa68ee036..dadb7236540 100644
--- a/libraries/src/Form/Rule/ShowOnRule.php
+++ b/libraries/src/Form/Rule/ShowOnRule.php
@@ -31,7 +31,7 @@ class ShowOnRule extends FormRule
* @var string
* @since 5.0.0
*/
- protected $regex = '^[A-Za-z0-9-]+((:.+)|(!:.*))$';
+ protected $regex = '^[A-Za-z0-9-]+((:.*)|(!:.*))$';
/**
* Method to test the value.
diff --git a/libraries/src/MVC/Controller/ApiController.php b/libraries/src/MVC/Controller/ApiController.php
index 375c6d3133a..82fc2825143 100644
--- a/libraries/src/MVC/Controller/ApiController.php
+++ b/libraries/src/MVC/Controller/ApiController.php
@@ -210,12 +210,12 @@ public function displayList()
if (\array_key_exists('offset', $paginationInfo)) {
$offset = $paginationInfo['offset'];
- $this->modelState->set($this->context . '.limitstart', $offset);
+ $this->modelState->set($this->context . '.limitstart', (int) $offset);
}
if (\array_key_exists('limit', $paginationInfo)) {
$limit = $paginationInfo['limit'];
- $this->modelState->set($this->context . '.list.limit', $limit);
+ $this->modelState->set($this->context . '.list.limit', (int) $limit);
}
$viewType = $this->app->getDocument()->getType();
@@ -246,8 +246,25 @@ public function displayList()
// Push the model into the view (as default)
$view->setModel($model, true);
+ /**
+ * Check the currently set order values in the modelstate against the valid filters
+ */
+ if (
+ $this->modelState->get('list.ordering')
+ && !$model->isValidFilterColumn($this->modelState->get('list.ordering'))
+ ) {
+ $model->setState('list.ordering', null);
+ }
+
+ if (
+ $this->modelState->get('list.direction')
+ && !\in_array(strtolower($this->modelState->get('list.direction')), ['asc', 'desc'], true)
+ ) {
+ $model->setState('list.direction', 'asc');
+ }
+
if ($offset) {
- $model->setState('list.start', $offset);
+ $model->setState('list.start', (int) $offset);
}
/**
@@ -255,7 +272,7 @@ public function displayList()
* the last page of data. If there isn't a limit start then set
*/
if ($limit) {
- $model->setState('list.limit', $limit);
+ $model->setState('list.limit', (int) $limit);
} else {
$model->setState('list.limit', $this->itemsPerPage);
}
diff --git a/libraries/src/MVC/Model/ListModel.php b/libraries/src/MVC/Model/ListModel.php
index bb2370225f8..ed06176233f 100644
--- a/libraries/src/MVC/Model/ListModel.php
+++ b/libraries/src/MVC/Model/ListModel.php
@@ -213,6 +213,18 @@ public function getActiveFilters()
return $activeFilters;
}
+ /**
+ * Validates a column name against the list of valid columns defined in the model
+ *
+ * @return bool
+ *
+ * @since 5.4.4
+ */
+ public function isValidFilterColumn($columnName): bool
+ {
+ return \in_array($columnName, $this->filter_fields, true);
+ }
+
/**
* Method to get an array of data items.
*
diff --git a/libraries/src/MVC/View/AbstractView.php b/libraries/src/MVC/View/AbstractView.php
index 05d7615c07b..1491b092edd 100644
--- a/libraries/src/MVC/View/AbstractView.php
+++ b/libraries/src/MVC/View/AbstractView.php
@@ -50,7 +50,7 @@ abstract class AbstractView implements ViewInterface, DispatcherAwareInterface,
* @var Document
* @since 3.0
*
- * @deprecated 4.4.0 will be removed in 7.0
+ * @deprecated 4.4.0 will be made private in 7.0
* Use $this->getDocument() instead
*/
public $document;
diff --git a/libraries/src/Plugin/Attribute/AllowUnauthorizedAdministratorAccess.php b/libraries/src/Plugin/Attribute/AllowUnauthorizedAdministratorAccess.php
new file mode 100644
index 00000000000..807d3095d07
--- /dev/null
+++ b/libraries/src/Plugin/Attribute/AllowUnauthorizedAdministratorAccess.php
@@ -0,0 +1,25 @@
+
+ * @license GNU General Public License version 2 or later; see LICENSE.txt
+ */
+
+namespace Joomla\CMS\Plugin\Attribute;
+
+// phpcs:disable PSR1.Files.SideEffects
+\defined('_JEXEC') or die;
+// phpcs:enable PSR1.Files.SideEffects
+
+/**
+ * This attribute allows the plugin listener to handle AJAX requests in the backend of the site,
+ * where normally com_ajax is not available when we are not logged in.
+ *
+ * @since 5.4.4
+ */
+#[\Attribute(\Attribute::TARGET_METHOD)]
+class AllowUnauthorizedAdministratorAccess
+{
+}
diff --git a/media_source/README.md b/media_source/README.md
new file mode 100644
index 00000000000..d55377d2954
--- /dev/null
+++ b/media_source/README.md
@@ -0,0 +1,127 @@
+# CMS Media source
+
+The folder contains source files of CMS client-side resources (Stylesheets, JavaScripts, Images and other assets) needed for extensions to work.
+Each folder is for a specific extension with a few exceptions like `vendor`, `system`.
+
+## Building assets
+
+Before using the assets they must first be built/compiled and placed under `media/` folder.
+
+Following command helps to build, they will call builder associated with each asset:
+- `npm run build -- -a` Build all assets. Will go through all resources and will build each asset.
+- `npm run build -- -n ,` Build only specific asset.
+
+Additionally, each builder may provide their own task, that can be executed separately without running the whole rebuild.
+In default configuration the builder uses following tasks:
+- `clear` remove all associated files from `media/`.
+- `copy` copy static files to `media/`
+- `css` process Stylesheets files. Copy or compile to CSS when needed (example for SCSS etc.).
+- `js` process JavaScript files. Copy or compile to JS when needed (example for `.es6.js` and `.vue` etc.).
+- `gzip` prepare compressed version of css,js files.
+
+To execute specific task use `-t` argument:
+- `npm run build -- -a -t ,` Will apply specified task to all asset builders.
+- `npm run build -- -n , -t ,` Will apply specified task to specified asset builders.
+
+Use watchers while developing an extension allows to automatically refresh the assets while editing.
+- `npm run watch -- -n ` Will start watching files changes for specific asset.
+
+## Adding new assets
+
+To add new resource follow next steps:
+- Create folder under `media_source/` with name of future asset. Example for `com_example` it will be `media_source/com_example/`.
+- Add Stylesheets, JavaScript and other needed files for the asset.
+- Add the resource name in to `build/build-modules-js/builders-registry.mjs` into the list of `builders` so CLI know it exists.
+- (Optionally) When need extra processing add custom builder into the root of the newly created folder `media_source/com_example/builder.mjs`.
+- Source files of complex Application (for example Vue based script) place under `src/` like `media_source/com_example/src/` and use custom builder to build the Applictaion.
+
+Done. And do not forget to run build.
+
+### Note about JavaScript and Stylesheets
+
+#### Javascript
+
+- Modern JavaScript files must have an extension `.es6.js`.
+ This allows ESLint to check the code style, Joomla is using the Airbnb preset https://github.com/airbnb/javascript.
+ It also instructs Rollup to do the transforms for ES2017. This step creates both normal and minified files.
+ Production code WILL NOT have the `.es6` part for ES2017+ files.
+
+- Legacy JavaScript files must have an extension `.es5.js`.
+ This instructs ESLint to skip checking this file.
+ Also, it instructs the tools to create a minified version (production code WILL NOT have the `.es5` part)
+
+
+#### SCSS
+- SCSS files starting with `_` will not become entry points for SCSS.
+ SCSS files will be transformed to CSS, both normal and minified versions.
+
+### Custom builder
+
+By default, each resource uses `DefaultModuleBuilder` class to build its asset.
+However, each resource may have own `builder.mjs` script with custom logic.
+To use custom builder add `builder.mjs` with custom logic in to the root of the resources' folder.
+
+#### Anatomy of custom builder
+
+Each builder receives the base path (path to `media_source/`) and target path (path to `media/`) as input, also cmd options.
+The builder should provide list of tasks which it is able to run and expose public methods for each task to do so.
+
+**ATTENTION**: While coding the custom builder avoid writing in to folders outside the current asset scope. This could lead to unexpected collisions.
+
+Example builder:
+
+```javascript
+export default class ExampleModuleBuilder
+{
+ tasksBuild = ['clear', 'copy', 'css', 'js'];
+ tasksExtras = ['gzip'];
+
+ constructor(name = '', basePath = '', targetPath = '', options = {}) {
+ if (!name) {
+ throw new Error(`Argument "name" is required for ModuleBuilder.`);
+ }
+
+ if (!basePath || !targetPath) {
+ throw new Error(`Arguments "basePath" and "targetPath" is required for "${name}" ModuleBuilder.`);
+ }
+
+ this.name = name;
+ this.basePath = path.join(basePath, name);
+ this.targetPath = path.join(targetPath, name);
+ this.options = options;
+ }
+
+ getAllTasks() {
+ return [ ...this.tasksBuild, ...this.tasksExtras ];
+ }
+
+ getBuildTasks() {
+ return this.tasksBuild;
+ }
+
+ // The methods to execute each task
+ async clear() {}
+ async copy() {}
+ async css() {}
+ async js() {}
+ async gzip() {}
+}
+```
+
+The list of tasks is not strict, and depending on the builder needs.
+However, it is required the builder to implement `getBuildTasks()` so the main script knows which tasks need to run while running the complete build.
+Method `getAllTasks()` is optional, needed only when builder have tasks that can be executed from CLI but which does not participate in the complete build.
+
+To simplify the coding it is possible to extend `DefaultModuleBuilder` class.
+
+```javascript
+import DefaultModuleBuilder from '../../build/build-modules-js/builder/default-module-builder.mjs';
+
+export default class ExampleModuleBuilder extends DefaultModuleBuilder {
+ async js() {
+ await super.js();
+
+ // Run custom code
+ }
+}
+```
diff --git a/build/media_source/cache/index.html b/media_source/cache/index.html
similarity index 100%
rename from build/media_source/cache/index.html
rename to media_source/cache/index.html
diff --git a/build/media_source/com_actionlogs/joomla.asset.json b/media_source/com_actionlogs/joomla.asset.json
similarity index 100%
rename from build/media_source/com_actionlogs/joomla.asset.json
rename to media_source/com_actionlogs/joomla.asset.json
diff --git a/build/media_source/com_actionlogs/js/admin-actionlogs-default.es6.js b/media_source/com_actionlogs/js/admin-actionlogs-default.es6.js
similarity index 100%
rename from build/media_source/com_actionlogs/js/admin-actionlogs-default.es6.js
rename to media_source/com_actionlogs/js/admin-actionlogs-default.es6.js
diff --git a/build/media_source/com_admin/joomla.asset.json b/media_source/com_admin/joomla.asset.json
similarity index 100%
rename from build/media_source/com_admin/joomla.asset.json
rename to media_source/com_admin/joomla.asset.json
diff --git a/build/media_source/com_admin/js/admin-help.es6.js b/media_source/com_admin/js/admin-help.es6.js
similarity index 100%
rename from build/media_source/com_admin/js/admin-help.es6.js
rename to media_source/com_admin/js/admin-help.es6.js
diff --git a/build/media_source/com_associations/css/sidebyside.css b/media_source/com_associations/css/sidebyside.css
similarity index 100%
rename from build/media_source/com_associations/css/sidebyside.css
rename to media_source/com_associations/css/sidebyside.css
diff --git a/build/media_source/com_associations/joomla.asset.json b/media_source/com_associations/joomla.asset.json
similarity index 100%
rename from build/media_source/com_associations/joomla.asset.json
rename to media_source/com_associations/joomla.asset.json
diff --git a/build/media_source/com_associations/js/admin-associations-default.es6.js b/media_source/com_associations/js/admin-associations-default.es6.js
similarity index 100%
rename from build/media_source/com_associations/js/admin-associations-default.es6.js
rename to media_source/com_associations/js/admin-associations-default.es6.js
diff --git a/build/media_source/com_associations/js/admin-associations-modal.es6.js b/media_source/com_associations/js/admin-associations-modal.es6.js
similarity index 100%
rename from build/media_source/com_associations/js/admin-associations-modal.es6.js
rename to media_source/com_associations/js/admin-associations-modal.es6.js
diff --git a/build/media_source/com_associations/js/associations-edit.es6.js b/media_source/com_associations/js/associations-edit.es6.js
similarity index 100%
rename from build/media_source/com_associations/js/associations-edit.es6.js
rename to media_source/com_associations/js/associations-edit.es6.js
diff --git a/build/media_source/com_associations/js/sidebyside.es6.js b/media_source/com_associations/js/sidebyside.es6.js
similarity index 100%
rename from build/media_source/com_associations/js/sidebyside.es6.js
rename to media_source/com_associations/js/sidebyside.es6.js
diff --git a/build/media_source/com_banners/joomla.asset.json b/media_source/com_banners/joomla.asset.json
similarity index 100%
rename from build/media_source/com_banners/joomla.asset.json
rename to media_source/com_banners/joomla.asset.json
diff --git a/build/media_source/com_banners/js/admin-banner-edit.es6.js b/media_source/com_banners/js/admin-banner-edit.es6.js
similarity index 100%
rename from build/media_source/com_banners/js/admin-banner-edit.es6.js
rename to media_source/com_banners/js/admin-banner-edit.es6.js
diff --git a/build/media_source/com_cache/joomla.asset.json b/media_source/com_cache/joomla.asset.json
similarity index 100%
rename from build/media_source/com_cache/joomla.asset.json
rename to media_source/com_cache/joomla.asset.json
diff --git a/build/media_source/com_cache/js/admin-cache-default.es6.js b/media_source/com_cache/js/admin-cache-default.es6.js
similarity index 100%
rename from build/media_source/com_cache/js/admin-cache-default.es6.js
rename to media_source/com_cache/js/admin-cache-default.es6.js
diff --git a/build/media_source/com_categories/css/shared-categories-accordion.css b/media_source/com_categories/css/shared-categories-accordion.css
similarity index 100%
rename from build/media_source/com_categories/css/shared-categories-accordion.css
rename to media_source/com_categories/css/shared-categories-accordion.css
diff --git a/build/media_source/com_categories/joomla.asset.json b/media_source/com_categories/joomla.asset.json
similarity index 100%
rename from build/media_source/com_categories/joomla.asset.json
rename to media_source/com_categories/joomla.asset.json
diff --git a/build/media_source/com_categories/js/shared-categories-accordion.es6.js b/media_source/com_categories/js/shared-categories-accordion.es6.js
similarity index 100%
rename from build/media_source/com_categories/js/shared-categories-accordion.es6.js
rename to media_source/com_categories/js/shared-categories-accordion.es6.js
diff --git a/build/media_source/com_config/joomla.asset.json b/media_source/com_config/joomla.asset.json
similarity index 100%
rename from build/media_source/com_config/joomla.asset.json
rename to media_source/com_config/joomla.asset.json
diff --git a/build/media_source/com_config/js/config-default.es6.js b/media_source/com_config/js/config-default.es6.js
similarity index 100%
rename from build/media_source/com_config/js/config-default.es6.js
rename to media_source/com_config/js/config-default.es6.js
diff --git a/build/media_source/com_config/js/config-filters.es6.js b/media_source/com_config/js/config-filters.es6.js
similarity index 100%
rename from build/media_source/com_config/js/config-filters.es6.js
rename to media_source/com_config/js/config-filters.es6.js
diff --git a/build/media_source/com_config/js/modules-default.es6.js b/media_source/com_config/js/modules-default.es6.js
similarity index 100%
rename from build/media_source/com_config/js/modules-default.es6.js
rename to media_source/com_config/js/modules-default.es6.js
diff --git a/build/media_source/com_config/js/templates-default.es6.js b/media_source/com_config/js/templates-default.es6.js
similarity index 100%
rename from build/media_source/com_config/js/templates-default.es6.js
rename to media_source/com_config/js/templates-default.es6.js
diff --git a/build/media_source/com_contact/joomla.asset.json b/media_source/com_contact/joomla.asset.json
similarity index 100%
rename from build/media_source/com_contact/joomla.asset.json
rename to media_source/com_contact/joomla.asset.json
diff --git a/build/media_source/com_contact/js/admin-contacts-modal.es6.js b/media_source/com_contact/js/admin-contacts-modal.es6.js
similarity index 100%
rename from build/media_source/com_contact/js/admin-contacts-modal.es6.js
rename to media_source/com_contact/js/admin-contacts-modal.es6.js
diff --git a/build/media_source/com_contact/js/contacts-list.es6.js b/media_source/com_contact/js/contacts-list.es6.js
similarity index 100%
rename from build/media_source/com_contact/js/contacts-list.es6.js
rename to media_source/com_contact/js/contacts-list.es6.js
diff --git a/build/media_source/com_content/joomla.asset.json b/media_source/com_content/joomla.asset.json
similarity index 100%
rename from build/media_source/com_content/joomla.asset.json
rename to media_source/com_content/joomla.asset.json
diff --git a/build/media_source/com_content/js/admin-article-pagebreak.es6.js b/media_source/com_content/js/admin-article-pagebreak.es6.js
similarity index 100%
rename from build/media_source/com_content/js/admin-article-pagebreak.es6.js
rename to media_source/com_content/js/admin-article-pagebreak.es6.js
diff --git a/build/media_source/com_content/js/admin-article-readmore.es6.js b/media_source/com_content/js/admin-article-readmore.es6.js
similarity index 100%
rename from build/media_source/com_content/js/admin-article-readmore.es6.js
rename to media_source/com_content/js/admin-article-readmore.es6.js
diff --git a/build/media_source/com_content/js/admin-articles-default-batch-footer.es6.js b/media_source/com_content/js/admin-articles-default-batch-footer.es6.js
similarity index 100%
rename from build/media_source/com_content/js/admin-articles-default-batch-footer.es6.js
rename to media_source/com_content/js/admin-articles-default-batch-footer.es6.js
diff --git a/build/media_source/com_content/js/admin-articles-default-stage-footer.es6.js b/media_source/com_content/js/admin-articles-default-stage-footer.es6.js
similarity index 100%
rename from build/media_source/com_content/js/admin-articles-default-stage-footer.es6.js
rename to media_source/com_content/js/admin-articles-default-stage-footer.es6.js
diff --git a/build/media_source/com_content/js/admin-articles-modal.es6.js b/media_source/com_content/js/admin-articles-modal.es6.js
similarity index 100%
rename from build/media_source/com_content/js/admin-articles-modal.es6.js
rename to media_source/com_content/js/admin-articles-modal.es6.js
diff --git a/build/media_source/com_content/js/articles-list.es6.js b/media_source/com_content/js/articles-list.es6.js
similarity index 100%
rename from build/media_source/com_content/js/articles-list.es6.js
rename to media_source/com_content/js/articles-list.es6.js
diff --git a/build/media_source/com_content/js/articles-status.es6.js b/media_source/com_content/js/articles-status.es6.js
similarity index 100%
rename from build/media_source/com_content/js/articles-status.es6.js
rename to media_source/com_content/js/articles-status.es6.js
diff --git a/build/media_source/com_content/js/form-edit.es6.js b/media_source/com_content/js/form-edit.es6.js
similarity index 100%
rename from build/media_source/com_content/js/form-edit.es6.js
rename to media_source/com_content/js/form-edit.es6.js
diff --git a/build/media_source/com_contenthistory/joomla.asset.json b/media_source/com_contenthistory/joomla.asset.json
similarity index 100%
rename from build/media_source/com_contenthistory/joomla.asset.json
rename to media_source/com_contenthistory/joomla.asset.json
diff --git a/build/media_source/com_contenthistory/js/admin-compare-compare.es6.js b/media_source/com_contenthistory/js/admin-compare-compare.es6.js
similarity index 100%
rename from build/media_source/com_contenthistory/js/admin-compare-compare.es6.js
rename to media_source/com_contenthistory/js/admin-compare-compare.es6.js
diff --git a/build/media_source/com_contenthistory/js/admin-history-modal.es6.js b/media_source/com_contenthistory/js/admin-history-modal.es6.js
similarity index 100%
rename from build/media_source/com_contenthistory/js/admin-history-modal.es6.js
rename to media_source/com_contenthistory/js/admin-history-modal.es6.js
diff --git a/build/media_source/com_cpanel/joomla.asset.json b/media_source/com_cpanel/joomla.asset.json
similarity index 100%
rename from build/media_source/com_cpanel/joomla.asset.json
rename to media_source/com_cpanel/joomla.asset.json
diff --git a/build/media_source/com_cpanel/js/admin-cpanel-default.es6.js b/media_source/com_cpanel/js/admin-cpanel-default.es6.js
similarity index 100%
rename from build/media_source/com_cpanel/js/admin-cpanel-default.es6.js
rename to media_source/com_cpanel/js/admin-cpanel-default.es6.js
diff --git a/build/media_source/com_cpanel/js/admin-system-loader.es6.js b/media_source/com_cpanel/js/admin-system-loader.es6.js
similarity index 100%
rename from build/media_source/com_cpanel/js/admin-system-loader.es6.js
rename to media_source/com_cpanel/js/admin-system-loader.es6.js
diff --git a/build/media_source/com_fields/joomla.asset.json b/media_source/com_fields/joomla.asset.json
similarity index 100%
rename from build/media_source/com_fields/joomla.asset.json
rename to media_source/com_fields/joomla.asset.json
diff --git a/build/media_source/com_fields/js/admin-field-changecontext.es6.js b/media_source/com_fields/js/admin-field-changecontext.es6.js
similarity index 100%
rename from build/media_source/com_fields/js/admin-field-changecontext.es6.js
rename to media_source/com_fields/js/admin-field-changecontext.es6.js
diff --git a/build/media_source/com_fields/js/admin-field-edit.es6.js b/media_source/com_fields/js/admin-field-edit.es6.js
similarity index 100%
rename from build/media_source/com_fields/js/admin-field-edit.es6.js
rename to media_source/com_fields/js/admin-field-edit.es6.js
diff --git a/build/media_source/com_fields/js/admin-field-typehaschanged.es6.js b/media_source/com_fields/js/admin-field-typehaschanged.es6.js
similarity index 100%
rename from build/media_source/com_fields/js/admin-field-typehaschanged.es6.js
rename to media_source/com_fields/js/admin-field-typehaschanged.es6.js
diff --git a/build/media_source/com_fields/js/admin-fields-default-batch.es6.js b/media_source/com_fields/js/admin-fields-default-batch.es6.js
similarity index 100%
rename from build/media_source/com_fields/js/admin-fields-default-batch.es6.js
rename to media_source/com_fields/js/admin-fields-default-batch.es6.js
diff --git a/build/media_source/com_fields/js/admin-fields-modal.es6.js b/media_source/com_fields/js/admin-fields-modal.es6.js
similarity index 100%
rename from build/media_source/com_fields/js/admin-fields-modal.es6.js
rename to media_source/com_fields/js/admin-fields-modal.es6.js
diff --git a/build/media_source/com_finder/css/dates.css b/media_source/com_finder/css/dates.css
similarity index 100%
rename from build/media_source/com_finder/css/dates.css
rename to media_source/com_finder/css/dates.css
diff --git a/build/media_source/com_finder/css/finder.css b/media_source/com_finder/css/finder.css
similarity index 100%
rename from build/media_source/com_finder/css/finder.css
rename to media_source/com_finder/css/finder.css
diff --git a/build/media_source/com_finder/css/indexer.css b/media_source/com_finder/css/indexer.css
similarity index 100%
rename from build/media_source/com_finder/css/indexer.css
rename to media_source/com_finder/css/indexer.css
diff --git a/build/media_source/com_finder/joomla.asset.json b/media_source/com_finder/joomla.asset.json
similarity index 100%
rename from build/media_source/com_finder/joomla.asset.json
rename to media_source/com_finder/joomla.asset.json
diff --git a/build/media_source/com_finder/js/debug.es6.js b/media_source/com_finder/js/debug.es6.js
similarity index 100%
rename from build/media_source/com_finder/js/debug.es6.js
rename to media_source/com_finder/js/debug.es6.js
diff --git a/build/media_source/com_finder/js/filters.es6.js b/media_source/com_finder/js/filters.es6.js
similarity index 100%
rename from build/media_source/com_finder/js/filters.es6.js
rename to media_source/com_finder/js/filters.es6.js
diff --git a/build/media_source/com_finder/js/finder-edit.es6.js b/media_source/com_finder/js/finder-edit.es6.js
similarity index 100%
rename from build/media_source/com_finder/js/finder-edit.es6.js
rename to media_source/com_finder/js/finder-edit.es6.js
diff --git a/build/media_source/com_finder/js/finder.es6.js b/media_source/com_finder/js/finder.es6.js
similarity index 100%
rename from build/media_source/com_finder/js/finder.es6.js
rename to media_source/com_finder/js/finder.es6.js
diff --git a/build/media_source/com_finder/js/indexer.es6.js b/media_source/com_finder/js/indexer.es6.js
similarity index 100%
rename from build/media_source/com_finder/js/indexer.es6.js
rename to media_source/com_finder/js/indexer.es6.js
diff --git a/build/media_source/com_finder/js/maps.es6.js b/media_source/com_finder/js/maps.es6.js
similarity index 100%
rename from build/media_source/com_finder/js/maps.es6.js
rename to media_source/com_finder/js/maps.es6.js
diff --git a/build/media_source/com_guidedtours/images/6_0/cassiopeiacolors.jpg b/media_source/com_guidedtours/images/6_0/cassiopeiacolors.jpg
similarity index 100%
rename from build/media_source/com_guidedtours/images/6_0/cassiopeiacolors.jpg
rename to media_source/com_guidedtours/images/6_0/cassiopeiacolors.jpg
diff --git a/build/media_source/com_guidedtours/images/6_1/captcha.jpg b/media_source/com_guidedtours/images/6_1/captcha.jpg
similarity index 100%
rename from build/media_source/com_guidedtours/images/6_1/captcha.jpg
rename to media_source/com_guidedtours/images/6_1/captcha.jpg
diff --git a/build/media_source/com_guidedtours/images/6_1/media.jpg b/media_source/com_guidedtours/images/6_1/media.jpg
similarity index 100%
rename from build/media_source/com_guidedtours/images/6_1/media.jpg
rename to media_source/com_guidedtours/images/6_1/media.jpg
diff --git a/build/media_source/com_guidedtours/images/6_1/workflows.jpg b/media_source/com_guidedtours/images/6_1/workflows.jpg
similarity index 100%
rename from build/media_source/com_guidedtours/images/6_1/workflows.jpg
rename to media_source/com_guidedtours/images/6_1/workflows.jpg
diff --git a/build/media_source/com_guidedtours/joomla.asset.json b/media_source/com_guidedtours/joomla.asset.json
similarity index 100%
rename from build/media_source/com_guidedtours/joomla.asset.json
rename to media_source/com_guidedtours/joomla.asset.json
diff --git a/build/media_source/com_guidedtours/js/tour-edit.es6.js b/media_source/com_guidedtours/js/tour-edit.es6.js
similarity index 100%
rename from build/media_source/com_guidedtours/js/tour-edit.es6.js
rename to media_source/com_guidedtours/js/tour-edit.es6.js
diff --git a/build/media_source/com_installer/css/installer.css b/media_source/com_installer/css/installer.css
similarity index 100%
rename from build/media_source/com_installer/css/installer.css
rename to media_source/com_installer/css/installer.css
diff --git a/build/media_source/com_installer/joomla.asset.json b/media_source/com_installer/joomla.asset.json
similarity index 100%
rename from build/media_source/com_installer/joomla.asset.json
rename to media_source/com_installer/joomla.asset.json
diff --git a/build/media_source/com_installer/js/changelog.es6.js b/media_source/com_installer/js/changelog.es6.js
similarity index 100%
rename from build/media_source/com_installer/js/changelog.es6.js
rename to media_source/com_installer/js/changelog.es6.js
diff --git a/build/media_source/com_installer/js/installer.es6.js b/media_source/com_installer/js/installer.es6.js
similarity index 100%
rename from build/media_source/com_installer/js/installer.es6.js
rename to media_source/com_installer/js/installer.es6.js
diff --git a/build/media_source/com_joomlaupdate/joomla.asset.json b/media_source/com_joomlaupdate/joomla.asset.json
similarity index 100%
rename from build/media_source/com_joomlaupdate/joomla.asset.json
rename to media_source/com_joomlaupdate/joomla.asset.json
diff --git a/build/media_source/com_joomlaupdate/js/admin-update-default.es6.js b/media_source/com_joomlaupdate/js/admin-update-default.es6.js
similarity index 100%
rename from build/media_source/com_joomlaupdate/js/admin-update-default.es6.js
rename to media_source/com_joomlaupdate/js/admin-update-default.es6.js
diff --git a/build/media_source/com_joomlaupdate/js/default.es6.js b/media_source/com_joomlaupdate/js/default.es6.js
similarity index 100%
rename from build/media_source/com_joomlaupdate/js/default.es6.js
rename to media_source/com_joomlaupdate/js/default.es6.js
diff --git a/build/media_source/com_languages/css/overrider.css b/media_source/com_languages/css/overrider.css
similarity index 100%
rename from build/media_source/com_languages/css/overrider.css
rename to media_source/com_languages/css/overrider.css
diff --git a/build/media_source/com_languages/joomla.asset.json b/media_source/com_languages/joomla.asset.json
similarity index 100%
rename from build/media_source/com_languages/joomla.asset.json
rename to media_source/com_languages/joomla.asset.json
diff --git a/build/media_source/com_languages/js/admin-language-edit-change-flag.es6.js b/media_source/com_languages/js/admin-language-edit-change-flag.es6.js
similarity index 100%
rename from build/media_source/com_languages/js/admin-language-edit-change-flag.es6.js
rename to media_source/com_languages/js/admin-language-edit-change-flag.es6.js
diff --git a/build/media_source/com_languages/js/admin-override-edit-refresh-searchstring.es6.js b/media_source/com_languages/js/admin-override-edit-refresh-searchstring.es6.js
similarity index 100%
rename from build/media_source/com_languages/js/admin-override-edit-refresh-searchstring.es6.js
rename to media_source/com_languages/js/admin-override-edit-refresh-searchstring.es6.js
diff --git a/build/media_source/com_languages/js/overrider.es6.js b/media_source/com_languages/js/overrider.es6.js
similarity index 100%
rename from build/media_source/com_languages/js/overrider.es6.js
rename to media_source/com_languages/js/overrider.es6.js
diff --git a/build/media_source/com_mails/joomla.asset.json b/media_source/com_mails/joomla.asset.json
similarity index 100%
rename from build/media_source/com_mails/joomla.asset.json
rename to media_source/com_mails/joomla.asset.json
diff --git a/build/media_source/com_mails/js/admin-email-template-edit.es6.js b/media_source/com_mails/js/admin-email-template-edit.es6.js
similarity index 100%
rename from build/media_source/com_mails/js/admin-email-template-edit.es6.js
rename to media_source/com_mails/js/admin-email-template-edit.es6.js
diff --git a/media_source/com_media/builder.mjs b/media_source/com_media/builder.mjs
new file mode 100644
index 00000000000..df33d4db9ad
--- /dev/null
+++ b/media_source/com_media/builder.mjs
@@ -0,0 +1,98 @@
+/**
+ * Assets Builder
+ */
+import path from 'node:path';
+import fsp from 'node:fs/promises';
+import { rollup } from 'rollup';
+import VuePlugin from 'rollup-plugin-vue';
+import { nodeResolve } from '@rollup/plugin-node-resolve';
+import commonjs from '@rollup/plugin-commonjs';
+import replace from '@rollup/plugin-replace';
+import { babel } from '@rollup/plugin-babel';
+import DefaultModuleBuilder from '../../build/build-modules-js/builder/default-module-builder.mjs';
+import { minifyJSContent } from '../../build/build-modules-js/javascript/js-handle.mjs';
+
+export const buildMediaManager = async (basePath, targetPath) => {
+ const srcFile = path.join(basePath, 'src', 'mediamanager.es6.js');
+ const targetFile = path.join(targetPath, 'js', 'media-manager.js');
+ const targetFileMin = path.join(targetPath, 'js', 'media-manager.min.js');
+ const isProduction = process.env.NODE_ENV !== 'DEVELOPMENT';
+
+ return rollup({
+ input: srcFile,
+ plugins: [
+ VuePlugin({
+ target: 'browser',
+ css: false,
+ compileTemplate: true,
+ template: {
+ isProduction,
+ },
+ }),
+ nodeResolve(),
+ commonjs(),
+ replace({
+ 'process.env.NODE_ENV': JSON.stringify((process.env.NODE_ENV && process.env.NODE_ENV.toLocaleLowerCase()) || 'production'),
+ __VUE_OPTIONS_API__: true,
+ __VUE_PROD_DEVTOOLS__: !isProduction,
+ preventAssignment: true,
+ }),
+ babel({
+ exclude: 'node_modules/core-js/**',
+ babelHelpers: 'bundled',
+ babelrc: false,
+ presets: [
+ [
+ '@babel/preset-env',
+ {
+ targets: {
+ browsers: [
+ '> 1%',
+ 'not op_mini all',
+ /** https://caniuse.com/es6-module */
+ 'chrome >= 61',
+ 'safari >= 11',
+ 'edge >= 16',
+ 'Firefox >= 60',
+ ],
+ },
+ loose: true,
+ bugfixes: false,
+ ignoreBrowserslistConfig: true,
+ },
+ ],
+ ],
+ }),
+ ],
+ }).then((build) => {
+ return build.write({
+ format: 'es',
+ sourcemap: !isProduction ? 'inline' : false,
+ file: targetFile,
+ })
+ .then((value) => (isProduction ? minifyJSContent(value.output[0].code) : value.output[0]))
+ .then((content) => {
+ if (isProduction) {
+ return fsp.writeFile(targetFileMin, content, { encoding: 'utf8', mode: 0o644 });
+ }
+
+ // Copy media-manager.js => media-manager.min.js
+ return fsp.copyFile(targetFile, targetFileMin);
+ }).then(() => {
+ return build.close();
+ })
+ });
+};
+
+export default class MediaModuleBuilder extends DefaultModuleBuilder
+{
+ /**
+ * Process JavaScript files and Modules
+ * @returns { Promise }
+ */
+ async js() {
+ await super.js();
+
+ return buildMediaManager(this.basePath, this.targetPath);
+ }
+};
diff --git a/build/media_source/com_media/joomla.asset.json b/media_source/com_media/joomla.asset.json
similarity index 100%
rename from build/media_source/com_media/joomla.asset.json
rename to media_source/com_media/joomla.asset.json
diff --git a/build/media_source/com_media/js/edit-images.es6.js b/media_source/com_media/js/edit-images.es6.js
similarity index 100%
rename from build/media_source/com_media/js/edit-images.es6.js
rename to media_source/com_media/js/edit-images.es6.js
diff --git a/build/media_source/com_media/scss/_variables.scss b/media_source/com_media/scss/_variables.scss
similarity index 100%
rename from build/media_source/com_media/scss/_variables.scss
rename to media_source/com_media/scss/_variables.scss
diff --git a/build/media_source/com_media/scss/components/_animations.scss b/media_source/com_media/scss/components/_animations.scss
similarity index 100%
rename from build/media_source/com_media/scss/components/_animations.scss
rename to media_source/com_media/scss/components/_animations.scss
diff --git a/build/media_source/com_media/scss/components/_layout.scss b/media_source/com_media/scss/components/_layout.scss
similarity index 100%
rename from build/media_source/com_media/scss/components/_layout.scss
rename to media_source/com_media/scss/components/_layout.scss
diff --git a/build/media_source/com_media/scss/components/_media-breadcrumb.scss b/media_source/com_media/scss/components/_media-breadcrumb.scss
similarity index 100%
rename from build/media_source/com_media/scss/components/_media-breadcrumb.scss
rename to media_source/com_media/scss/components/_media-breadcrumb.scss
diff --git a/build/media_source/com_media/scss/components/_media-browser.scss b/media_source/com_media/scss/components/_media-browser.scss
similarity index 100%
rename from build/media_source/com_media/scss/components/_media-browser.scss
rename to media_source/com_media/scss/components/_media-browser.scss
diff --git a/build/media_source/com_media/scss/components/_media-edit.scss b/media_source/com_media/scss/components/_media-edit.scss
similarity index 100%
rename from build/media_source/com_media/scss/components/_media-edit.scss
rename to media_source/com_media/scss/components/_media-edit.scss
diff --git a/build/media_source/com_media/scss/components/_media-infobar.scss b/media_source/com_media/scss/components/_media-infobar.scss
similarity index 100%
rename from build/media_source/com_media/scss/components/_media-infobar.scss
rename to media_source/com_media/scss/components/_media-infobar.scss
diff --git a/build/media_source/com_media/scss/components/_media-modal.scss b/media_source/com_media/scss/components/_media-modal.scss
similarity index 100%
rename from build/media_source/com_media/scss/components/_media-modal.scss
rename to media_source/com_media/scss/components/_media-modal.scss
diff --git a/build/media_source/com_media/scss/components/_media-toolbar.scss b/media_source/com_media/scss/components/_media-toolbar.scss
similarity index 100%
rename from build/media_source/com_media/scss/components/_media-toolbar.scss
rename to media_source/com_media/scss/components/_media-toolbar.scss
diff --git a/build/media_source/com_media/scss/components/_media-tree.scss b/media_source/com_media/scss/components/_media-tree.scss
similarity index 100%
rename from build/media_source/com_media/scss/components/_media-tree.scss
rename to media_source/com_media/scss/components/_media-tree.scss
diff --git a/build/media_source/com_media/scss/media-manager.scss b/media_source/com_media/scss/media-manager.scss
similarity index 100%
rename from build/media_source/com_media/scss/media-manager.scss
rename to media_source/com_media/scss/media-manager.scss
diff --git a/administrator/components/com_media/resources/scripts/app/Api.es6.js b/media_source/com_media/src/app/Api.es6.js
similarity index 99%
rename from administrator/components/com_media/resources/scripts/app/Api.es6.js
rename to media_source/com_media/src/app/Api.es6.js
index cc536ba3738..e25498c21ee 100644
--- a/administrator/components/com_media/resources/scripts/app/Api.es6.js
+++ b/media_source/com_media/src/app/Api.es6.js
@@ -115,6 +115,7 @@ class Api {
this.canCreate = options.canCreate || false;
this.canEdit = options.canEdit || false;
this.canDelete = options.canDelete || false;
+ this.hasMediaActionPlugins = options.hasMediaActionPlugins !== false;
}
/**
diff --git a/administrator/components/com_media/resources/scripts/app/Event.es6.js b/media_source/com_media/src/app/Event.es6.js
similarity index 100%
rename from administrator/components/com_media/resources/scripts/app/Event.es6.js
rename to media_source/com_media/src/app/Event.es6.js
diff --git a/administrator/components/com_media/resources/scripts/app/Notifications.es6.js b/media_source/com_media/src/app/Notifications.es6.js
similarity index 100%
rename from administrator/components/com_media/resources/scripts/app/Notifications.es6.js
rename to media_source/com_media/src/app/Notifications.es6.js
diff --git a/administrator/components/com_media/resources/scripts/app/path.js b/media_source/com_media/src/app/path.js
similarity index 100%
rename from administrator/components/com_media/resources/scripts/app/path.js
rename to media_source/com_media/src/app/path.js
diff --git a/administrator/components/com_media/resources/scripts/components/app.vue b/media_source/com_media/src/components/app.vue
similarity index 100%
rename from administrator/components/com_media/resources/scripts/components/app.vue
rename to media_source/com_media/src/components/app.vue
diff --git a/administrator/components/com_media/resources/scripts/components/breadcrumb/breadcrumb.vue b/media_source/com_media/src/components/breadcrumb/breadcrumb.vue
similarity index 100%
rename from administrator/components/com_media/resources/scripts/components/breadcrumb/breadcrumb.vue
rename to media_source/com_media/src/components/breadcrumb/breadcrumb.vue
diff --git a/administrator/components/com_media/resources/scripts/components/browser/actionItems/actionItemsContainer.vue b/media_source/com_media/src/components/browser/actionItems/actionItemsContainer.vue
similarity index 98%
rename from administrator/components/com_media/resources/scripts/components/browser/actionItems/actionItemsContainer.vue
rename to media_source/com_media/src/components/browser/actionItems/actionItemsContainer.vue
index 1f46514e6ce..3ba4940af74 100644
--- a/administrator/components/com_media/resources/scripts/components/browser/actionItems/actionItemsContainer.vue
+++ b/media_source/com_media/src/components/browser/actionItems/actionItemsContainer.vue
@@ -189,7 +189,7 @@ export default {
},
canOpenEditView() {
// @TODO pass the array of allowed to edit files from PHP
- return ['jpg', 'jpeg', 'png'].includes(this.item.extension.toLowerCase());
+ return api.hasMediaActionPlugins && ['jpg', 'jpeg', 'png'].includes(this.item.extension.toLowerCase());
},
},
watch: {
diff --git a/administrator/components/com_media/resources/scripts/components/browser/actionItems/delete.vue b/media_source/com_media/src/components/browser/actionItems/delete.vue
similarity index 100%
rename from administrator/components/com_media/resources/scripts/components/browser/actionItems/delete.vue
rename to media_source/com_media/src/components/browser/actionItems/delete.vue
diff --git a/administrator/components/com_media/resources/scripts/components/browser/actionItems/download.vue b/media_source/com_media/src/components/browser/actionItems/download.vue
similarity index 100%
rename from administrator/components/com_media/resources/scripts/components/browser/actionItems/download.vue
rename to media_source/com_media/src/components/browser/actionItems/download.vue
diff --git a/administrator/components/com_media/resources/scripts/components/browser/actionItems/edit.vue b/media_source/com_media/src/components/browser/actionItems/edit.vue
similarity index 100%
rename from administrator/components/com_media/resources/scripts/components/browser/actionItems/edit.vue
rename to media_source/com_media/src/components/browser/actionItems/edit.vue
diff --git a/administrator/components/com_media/resources/scripts/components/browser/actionItems/preview.vue b/media_source/com_media/src/components/browser/actionItems/preview.vue
similarity index 100%
rename from administrator/components/com_media/resources/scripts/components/browser/actionItems/preview.vue
rename to media_source/com_media/src/components/browser/actionItems/preview.vue
diff --git a/administrator/components/com_media/resources/scripts/components/browser/actionItems/rename.vue b/media_source/com_media/src/components/browser/actionItems/rename.vue
similarity index 100%
rename from administrator/components/com_media/resources/scripts/components/browser/actionItems/rename.vue
rename to media_source/com_media/src/components/browser/actionItems/rename.vue
diff --git a/administrator/components/com_media/resources/scripts/components/browser/actionItems/share.vue b/media_source/com_media/src/components/browser/actionItems/share.vue
similarity index 100%
rename from administrator/components/com_media/resources/scripts/components/browser/actionItems/share.vue
rename to media_source/com_media/src/components/browser/actionItems/share.vue
diff --git a/administrator/components/com_media/resources/scripts/components/browser/actionItems/toggle.vue b/media_source/com_media/src/components/browser/actionItems/toggle.vue
similarity index 100%
rename from administrator/components/com_media/resources/scripts/components/browser/actionItems/toggle.vue
rename to media_source/com_media/src/components/browser/actionItems/toggle.vue
diff --git a/administrator/components/com_media/resources/scripts/components/browser/browser.vue b/media_source/com_media/src/components/browser/browser.vue
similarity index 100%
rename from administrator/components/com_media/resources/scripts/components/browser/browser.vue
rename to media_source/com_media/src/components/browser/browser.vue
diff --git a/administrator/components/com_media/resources/scripts/components/browser/items/audio.vue b/media_source/com_media/src/components/browser/items/audio.vue
similarity index 100%
rename from administrator/components/com_media/resources/scripts/components/browser/items/audio.vue
rename to media_source/com_media/src/components/browser/items/audio.vue
diff --git a/administrator/components/com_media/resources/scripts/components/browser/items/directory.vue b/media_source/com_media/src/components/browser/items/directory.vue
similarity index 100%
rename from administrator/components/com_media/resources/scripts/components/browser/items/directory.vue
rename to media_source/com_media/src/components/browser/items/directory.vue
diff --git a/administrator/components/com_media/resources/scripts/components/browser/items/document.vue b/media_source/com_media/src/components/browser/items/document.vue
similarity index 100%
rename from administrator/components/com_media/resources/scripts/components/browser/items/document.vue
rename to media_source/com_media/src/components/browser/items/document.vue
diff --git a/administrator/components/com_media/resources/scripts/components/browser/items/file.vue b/media_source/com_media/src/components/browser/items/file.vue
similarity index 100%
rename from administrator/components/com_media/resources/scripts/components/browser/items/file.vue
rename to media_source/com_media/src/components/browser/items/file.vue
diff --git a/administrator/components/com_media/resources/scripts/components/browser/items/image.vue b/media_source/com_media/src/components/browser/items/image.vue
similarity index 100%
rename from administrator/components/com_media/resources/scripts/components/browser/items/image.vue
rename to media_source/com_media/src/components/browser/items/image.vue
diff --git a/administrator/components/com_media/resources/scripts/components/browser/items/item.es6.js b/media_source/com_media/src/components/browser/items/item.es6.js
similarity index 100%
rename from administrator/components/com_media/resources/scripts/components/browser/items/item.es6.js
rename to media_source/com_media/src/components/browser/items/item.es6.js
diff --git a/administrator/components/com_media/resources/scripts/components/browser/items/video.vue b/media_source/com_media/src/components/browser/items/video.vue
similarity index 100%
rename from administrator/components/com_media/resources/scripts/components/browser/items/video.vue
rename to media_source/com_media/src/components/browser/items/video.vue
diff --git a/administrator/components/com_media/resources/scripts/components/browser/table/row.vue b/media_source/com_media/src/components/browser/table/row.vue
similarity index 100%
rename from administrator/components/com_media/resources/scripts/components/browser/table/row.vue
rename to media_source/com_media/src/components/browser/table/row.vue
diff --git a/administrator/components/com_media/resources/scripts/components/browser/table/table.vue b/media_source/com_media/src/components/browser/table/table.vue
similarity index 100%
rename from administrator/components/com_media/resources/scripts/components/browser/table/table.vue
rename to media_source/com_media/src/components/browser/table/table.vue
diff --git a/administrator/components/com_media/resources/scripts/components/browser/utils/utils.es6.js b/media_source/com_media/src/components/browser/utils/utils.es6.js
similarity index 100%
rename from administrator/components/com_media/resources/scripts/components/browser/utils/utils.es6.js
rename to media_source/com_media/src/components/browser/utils/utils.es6.js
diff --git a/administrator/components/com_media/resources/scripts/components/infobar/infobar.vue b/media_source/com_media/src/components/infobar/infobar.vue
similarity index 100%
rename from administrator/components/com_media/resources/scripts/components/infobar/infobar.vue
rename to media_source/com_media/src/components/infobar/infobar.vue
diff --git a/administrator/components/com_media/resources/scripts/components/modals/confirm-delete-modal.vue b/media_source/com_media/src/components/modals/confirm-delete-modal.vue
similarity index 100%
rename from administrator/components/com_media/resources/scripts/components/modals/confirm-delete-modal.vue
rename to media_source/com_media/src/components/modals/confirm-delete-modal.vue
diff --git a/administrator/components/com_media/resources/scripts/components/modals/create-folder-modal.vue b/media_source/com_media/src/components/modals/create-folder-modal.vue
similarity index 100%
rename from administrator/components/com_media/resources/scripts/components/modals/create-folder-modal.vue
rename to media_source/com_media/src/components/modals/create-folder-modal.vue
diff --git a/administrator/components/com_media/resources/scripts/components/modals/modal.vue b/media_source/com_media/src/components/modals/modal.vue
similarity index 100%
rename from administrator/components/com_media/resources/scripts/components/modals/modal.vue
rename to media_source/com_media/src/components/modals/modal.vue
diff --git a/administrator/components/com_media/resources/scripts/components/modals/preview-modal.vue b/media_source/com_media/src/components/modals/preview-modal.vue
similarity index 100%
rename from administrator/components/com_media/resources/scripts/components/modals/preview-modal.vue
rename to media_source/com_media/src/components/modals/preview-modal.vue
diff --git a/administrator/components/com_media/resources/scripts/components/modals/rename-modal.vue b/media_source/com_media/src/components/modals/rename-modal.vue
similarity index 100%
rename from administrator/components/com_media/resources/scripts/components/modals/rename-modal.vue
rename to media_source/com_media/src/components/modals/rename-modal.vue
diff --git a/administrator/components/com_media/resources/scripts/components/modals/share-modal.vue b/media_source/com_media/src/components/modals/share-modal.vue
similarity index 100%
rename from administrator/components/com_media/resources/scripts/components/modals/share-modal.vue
rename to media_source/com_media/src/components/modals/share-modal.vue
diff --git a/administrator/components/com_media/resources/scripts/components/toolbar/toolbar.vue b/media_source/com_media/src/components/toolbar/toolbar.vue
similarity index 100%
rename from administrator/components/com_media/resources/scripts/components/toolbar/toolbar.vue
rename to media_source/com_media/src/components/toolbar/toolbar.vue
diff --git a/administrator/components/com_media/resources/scripts/components/tree/disk.vue b/media_source/com_media/src/components/tree/disk.vue
similarity index 100%
rename from administrator/components/com_media/resources/scripts/components/tree/disk.vue
rename to media_source/com_media/src/components/tree/disk.vue
diff --git a/administrator/components/com_media/resources/scripts/components/tree/drive.vue b/media_source/com_media/src/components/tree/drive.vue
similarity index 100%
rename from administrator/components/com_media/resources/scripts/components/tree/drive.vue
rename to media_source/com_media/src/components/tree/drive.vue
diff --git a/administrator/components/com_media/resources/scripts/components/tree/tree.vue b/media_source/com_media/src/components/tree/tree.vue
similarity index 100%
rename from administrator/components/com_media/resources/scripts/components/tree/tree.vue
rename to media_source/com_media/src/components/tree/tree.vue
diff --git a/administrator/components/com_media/resources/scripts/components/upload/upload.vue b/media_source/com_media/src/components/upload/upload.vue
similarity index 100%
rename from administrator/components/com_media/resources/scripts/components/upload/upload.vue
rename to media_source/com_media/src/components/upload/upload.vue
diff --git a/administrator/components/com_media/resources/scripts/mediamanager.es6.js b/media_source/com_media/src/mediamanager.es6.js
similarity index 100%
rename from administrator/components/com_media/resources/scripts/mediamanager.es6.js
rename to media_source/com_media/src/mediamanager.es6.js
diff --git a/administrator/components/com_media/resources/scripts/mixins/navigable.es6.js b/media_source/com_media/src/mixins/navigable.es6.js
similarity index 100%
rename from administrator/components/com_media/resources/scripts/mixins/navigable.es6.js
rename to media_source/com_media/src/mixins/navigable.es6.js
diff --git a/administrator/components/com_media/resources/scripts/plugins/translate.es6.js b/media_source/com_media/src/plugins/translate.es6.js
similarity index 100%
rename from administrator/components/com_media/resources/scripts/plugins/translate.es6.js
rename to media_source/com_media/src/plugins/translate.es6.js
diff --git a/administrator/components/com_media/resources/scripts/store/actions.es6.js b/media_source/com_media/src/store/actions.es6.js
similarity index 100%
rename from administrator/components/com_media/resources/scripts/store/actions.es6.js
rename to media_source/com_media/src/store/actions.es6.js
diff --git a/administrator/components/com_media/resources/scripts/store/getters.es6.js b/media_source/com_media/src/store/getters.es6.js
similarity index 100%
rename from administrator/components/com_media/resources/scripts/store/getters.es6.js
rename to media_source/com_media/src/store/getters.es6.js
diff --git a/administrator/components/com_media/resources/scripts/store/mutation-types.es6.js b/media_source/com_media/src/store/mutation-types.es6.js
similarity index 100%
rename from administrator/components/com_media/resources/scripts/store/mutation-types.es6.js
rename to media_source/com_media/src/store/mutation-types.es6.js
diff --git a/administrator/components/com_media/resources/scripts/store/mutations.es6.js b/media_source/com_media/src/store/mutations.es6.js
similarity index 100%
rename from administrator/components/com_media/resources/scripts/store/mutations.es6.js
rename to media_source/com_media/src/store/mutations.es6.js
diff --git a/administrator/components/com_media/resources/scripts/store/plugins/persisted-state.es6.js b/media_source/com_media/src/store/plugins/persisted-state.es6.js
similarity index 100%
rename from administrator/components/com_media/resources/scripts/store/plugins/persisted-state.es6.js
rename to media_source/com_media/src/store/plugins/persisted-state.es6.js
diff --git a/administrator/components/com_media/resources/scripts/store/state.es6.js b/media_source/com_media/src/store/state.es6.js
similarity index 100%
rename from administrator/components/com_media/resources/scripts/store/state.es6.js
rename to media_source/com_media/src/store/state.es6.js
diff --git a/administrator/components/com_media/resources/scripts/store/store.es6.js b/media_source/com_media/src/store/store.es6.js
similarity index 100%
rename from administrator/components/com_media/resources/scripts/store/store.es6.js
rename to media_source/com_media/src/store/store.es6.js
diff --git a/build/media_source/com_menus/css/admin-item-edit_container.css b/media_source/com_menus/css/admin-item-edit_container.css
similarity index 100%
rename from build/media_source/com_menus/css/admin-item-edit_container.css
rename to media_source/com_menus/css/admin-item-edit_container.css
diff --git a/build/media_source/com_menus/joomla.asset.json b/media_source/com_menus/joomla.asset.json
similarity index 100%
rename from build/media_source/com_menus/joomla.asset.json
rename to media_source/com_menus/joomla.asset.json
diff --git a/build/media_source/com_menus/js/admin-item-edit.es6.js b/media_source/com_menus/js/admin-item-edit.es6.js
similarity index 100%
rename from build/media_source/com_menus/js/admin-item-edit.es6.js
rename to media_source/com_menus/js/admin-item-edit.es6.js
diff --git a/build/media_source/com_menus/js/admin-item-edit_container.es6.js b/media_source/com_menus/js/admin-item-edit_container.es6.js
similarity index 100%
rename from build/media_source/com_menus/js/admin-item-edit_container.es6.js
rename to media_source/com_menus/js/admin-item-edit_container.es6.js
diff --git a/build/media_source/com_menus/js/admin-item-edit_modules.es6.js b/media_source/com_menus/js/admin-item-edit_modules.es6.js
similarity index 100%
rename from build/media_source/com_menus/js/admin-item-edit_modules.es6.js
rename to media_source/com_menus/js/admin-item-edit_modules.es6.js
diff --git a/build/media_source/com_menus/js/admin-item-modal.es6.js b/media_source/com_menus/js/admin-item-modal.es6.js
similarity index 100%
rename from build/media_source/com_menus/js/admin-item-modal.es6.js
rename to media_source/com_menus/js/admin-item-modal.es6.js
diff --git a/build/media_source/com_menus/js/admin-items-modal.es6.js b/media_source/com_menus/js/admin-items-modal.es6.js
similarity index 100%
rename from build/media_source/com_menus/js/admin-items-modal.es6.js
rename to media_source/com_menus/js/admin-items-modal.es6.js
diff --git a/build/media_source/com_menus/js/admin-menus-default.es6.js b/media_source/com_menus/js/admin-menus-default.es6.js
similarity index 100%
rename from build/media_source/com_menus/js/admin-menus-default.es6.js
rename to media_source/com_menus/js/admin-menus-default.es6.js
diff --git a/build/media_source/com_menus/js/default-batch-body.es6.js b/media_source/com_menus/js/default-batch-body.es6.js
similarity index 100%
rename from build/media_source/com_menus/js/default-batch-body.es6.js
rename to media_source/com_menus/js/default-batch-body.es6.js
diff --git a/build/media_source/com_modules/joomla.asset.json b/media_source/com_modules/joomla.asset.json
similarity index 100%
rename from build/media_source/com_modules/joomla.asset.json
rename to media_source/com_modules/joomla.asset.json
diff --git a/build/media_source/com_modules/js/admin-module-edit_assignment.es6.js b/media_source/com_modules/js/admin-module-edit_assignment.es6.js
similarity index 100%
rename from build/media_source/com_modules/js/admin-module-edit_assignment.es6.js
rename to media_source/com_modules/js/admin-module-edit_assignment.es6.js
diff --git a/build/media_source/com_modules/js/admin-module-search.es6.js b/media_source/com_modules/js/admin-module-search.es6.js
similarity index 100%
rename from build/media_source/com_modules/js/admin-module-search.es6.js
rename to media_source/com_modules/js/admin-module-search.es6.js
diff --git a/build/media_source/com_modules/js/admin-modules-modal.es6.js b/media_source/com_modules/js/admin-modules-modal.es6.js
similarity index 100%
rename from build/media_source/com_modules/js/admin-modules-modal.es6.js
rename to media_source/com_modules/js/admin-modules-modal.es6.js
diff --git a/build/media_source/com_modules/js/admin-select-modal.es6.js b/media_source/com_modules/js/admin-select-modal.es6.js
similarity index 100%
rename from build/media_source/com_modules/js/admin-select-modal.es6.js
rename to media_source/com_modules/js/admin-select-modal.es6.js
diff --git a/build/media_source/com_scheduler/css/admin-view-task.css b/media_source/com_scheduler/css/admin-view-task.css
similarity index 100%
rename from build/media_source/com_scheduler/css/admin-view-task.css
rename to media_source/com_scheduler/css/admin-view-task.css
diff --git a/build/media_source/com_scheduler/css/admin-view-tasks.css b/media_source/com_scheduler/css/admin-view-tasks.css
similarity index 100%
rename from build/media_source/com_scheduler/css/admin-view-tasks.css
rename to media_source/com_scheduler/css/admin-view-tasks.css
diff --git a/build/media_source/com_scheduler/joomla.asset.json b/media_source/com_scheduler/joomla.asset.json
similarity index 100%
rename from build/media_source/com_scheduler/joomla.asset.json
rename to media_source/com_scheduler/joomla.asset.json
diff --git a/build/media_source/com_scheduler/js/admin-view-run-test-task.es6.js b/media_source/com_scheduler/js/admin-view-run-test-task.es6.js
similarity index 100%
rename from build/media_source/com_scheduler/js/admin-view-run-test-task.es6.js
rename to media_source/com_scheduler/js/admin-view-run-test-task.es6.js
diff --git a/build/media_source/com_scheduler/js/admin-view-select-task-search.es6.js b/media_source/com_scheduler/js/admin-view-select-task-search.es6.js
similarity index 100%
rename from build/media_source/com_scheduler/js/admin-view-select-task-search.es6.js
rename to media_source/com_scheduler/js/admin-view-select-task-search.es6.js
diff --git a/build/media_source/com_scheduler/js/scheduler-config.es6.js b/media_source/com_scheduler/js/scheduler-config.es6.js
similarity index 100%
rename from build/media_source/com_scheduler/js/scheduler-config.es6.js
rename to media_source/com_scheduler/js/scheduler-config.es6.js
diff --git a/build/media_source/com_tags/joomla.asset.json b/media_source/com_tags/joomla.asset.json
similarity index 100%
rename from build/media_source/com_tags/joomla.asset.json
rename to media_source/com_tags/joomla.asset.json
diff --git a/build/media_source/com_tags/js/tag-default.es6.js b/media_source/com_tags/js/tag-default.es6.js
similarity index 100%
rename from build/media_source/com_tags/js/tag-default.es6.js
rename to media_source/com_tags/js/tag-default.es6.js
diff --git a/build/media_source/com_tags/js/tag-list.es6.js b/media_source/com_tags/js/tag-list.es6.js
similarity index 100%
rename from build/media_source/com_tags/js/tag-list.es6.js
rename to media_source/com_tags/js/tag-list.es6.js
diff --git a/build/media_source/com_tags/js/tags-default.es6.js b/media_source/com_tags/js/tags-default.es6.js
similarity index 100%
rename from build/media_source/com_tags/js/tags-default.es6.js
rename to media_source/com_tags/js/tags-default.es6.js
diff --git a/build/media_source/com_templates/css/admin-templates-default.css b/media_source/com_templates/css/admin-templates-default.css
similarity index 100%
rename from build/media_source/com_templates/css/admin-templates-default.css
rename to media_source/com_templates/css/admin-templates-default.css
diff --git a/build/media_source/com_templates/joomla.asset.json b/media_source/com_templates/joomla.asset.json
similarity index 100%
rename from build/media_source/com_templates/joomla.asset.json
rename to media_source/com_templates/joomla.asset.json
diff --git a/build/media_source/com_templates/js/admin-template-toggle-assignment.es6.js b/media_source/com_templates/js/admin-template-toggle-assignment.es6.js
similarity index 100%
rename from build/media_source/com_templates/js/admin-template-toggle-assignment.es6.js
rename to media_source/com_templates/js/admin-template-toggle-assignment.es6.js
diff --git a/build/media_source/com_templates/js/admin-template-toggle-switch.es6.js b/media_source/com_templates/js/admin-template-toggle-switch.es6.js
similarity index 100%
rename from build/media_source/com_templates/js/admin-template-toggle-switch.es6.js
rename to media_source/com_templates/js/admin-template-toggle-switch.es6.js
diff --git a/build/media_source/com_templates/js/admin-templates-default.es6.js b/media_source/com_templates/js/admin-templates-default.es6.js
similarity index 100%
rename from build/media_source/com_templates/js/admin-templates-default.es6.js
rename to media_source/com_templates/js/admin-templates-default.es6.js
diff --git a/build/media_source/com_users/images/emergency.svg b/media_source/com_users/images/emergency.svg
similarity index 100%
rename from build/media_source/com_users/images/emergency.svg
rename to media_source/com_users/images/emergency.svg
diff --git a/build/media_source/com_users/joomla.asset.json b/media_source/com_users/joomla.asset.json
similarity index 100%
rename from build/media_source/com_users/joomla.asset.json
rename to media_source/com_users/joomla.asset.json
diff --git a/build/media_source/com_users/js/activate-user-send-email.es6.js b/media_source/com_users/js/activate-user-send-email.es6.js
similarity index 100%
rename from build/media_source/com_users/js/activate-user-send-email.es6.js
rename to media_source/com_users/js/activate-user-send-email.es6.js
diff --git a/build/media_source/com_users/js/admin-users-groups.es6.js b/media_source/com_users/js/admin-users-groups.es6.js
similarity index 100%
rename from build/media_source/com_users/js/admin-users-groups.es6.js
rename to media_source/com_users/js/admin-users-groups.es6.js
diff --git a/build/media_source/com_users/js/two-factor-focus.es6.js b/media_source/com_users/js/two-factor-focus.es6.js
similarity index 100%
rename from build/media_source/com_users/js/two-factor-focus.es6.js
rename to media_source/com_users/js/two-factor-focus.es6.js
diff --git a/build/media_source/com_users/js/two-factor-list.es6.js b/media_source/com_users/js/two-factor-list.es6.js
similarity index 100%
rename from build/media_source/com_users/js/two-factor-list.es6.js
rename to media_source/com_users/js/two-factor-list.es6.js
diff --git a/media_source/com_workflow/builder.mjs b/media_source/com_workflow/builder.mjs
new file mode 100644
index 00000000000..8e96cacde5c
--- /dev/null
+++ b/media_source/com_workflow/builder.mjs
@@ -0,0 +1,99 @@
+/**
+ * Assets Builder
+ */
+import path from 'node:path';
+import fsp from 'node:fs/promises';
+import { rollup } from 'rollup';
+import VuePlugin from 'rollup-plugin-vue';
+import { nodeResolve } from '@rollup/plugin-node-resolve';
+import commonjs from '@rollup/plugin-commonjs';
+import replace from '@rollup/plugin-replace';
+import { babel } from '@rollup/plugin-babel';
+import DefaultModuleBuilder from '../../build/build-modules-js/builder/default-module-builder.mjs';
+import { minifyJSContent } from '../../build/build-modules-js/javascript/js-handle.mjs';
+
+export const buildWorkflowModule = async (basePath, targetPath) => {
+ const srcFile = path.join(basePath, 'src', 'workflowgraph.es6.js');
+ const targetFile = path.join(targetPath, 'js', 'workflow-graph.js');
+ const targetFileMin = path.join(targetPath, 'js', 'workflow-graph.min.js');
+ const isProduction = process.env.NODE_ENV !== 'DEVELOPMENT';
+
+ return rollup({
+ input: srcFile,
+ external: ['joomla.dialog'],
+ plugins: [
+ VuePlugin({
+ target: 'browser',
+ css: false,
+ compileTemplate: true,
+ template: {
+ isProduction,
+ },
+ }),
+ nodeResolve(),
+ commonjs(),
+ replace({
+ 'process.env.NODE_ENV': JSON.stringify((process.env.NODE_ENV && process.env.NODE_ENV.toLocaleLowerCase()) || 'production'),
+ __VUE_OPTIONS_API__: true,
+ __VUE_PROD_DEVTOOLS__: !isProduction,
+ preventAssignment: true,
+ }),
+ babel({
+ exclude: 'node_modules/core-js/**',
+ babelHelpers: 'bundled',
+ babelrc: false,
+ presets: [
+ [
+ '@babel/preset-env',
+ {
+ targets: {
+ browsers: [
+ '> 1%',
+ 'not op_mini all',
+ /** https://caniuse.com/es6-module */
+ 'chrome >= 61',
+ 'safari >= 11',
+ 'edge >= 16',
+ 'Firefox >= 60',
+ ],
+ },
+ loose: true,
+ bugfixes: false,
+ ignoreBrowserslistConfig: true,
+ },
+ ],
+ ],
+ }),
+ ],
+ }).then((build) => {
+ return build.write({
+ format: 'es',
+ sourcemap: !isProduction ? 'inline' : false,
+ file: targetFile,
+ })
+ .then((value) => (isProduction ? minifyJSContent(value.output[0].code) : value.output[0]))
+ .then((content) => {
+ if (isProduction) {
+ return fsp.writeFile(targetFileMin, content, { encoding: 'utf8', mode: 0o644 });
+ }
+
+ // Copy media-manager.js => media-manager.min.js
+ return fsp.copyFile(targetFile, targetFileMin);
+ }).then(() => {
+ return build.close();
+ })
+ });
+};
+
+export default class WorkflowModuleBuilder extends DefaultModuleBuilder
+{
+ /**
+ * Process JavaScript files and Modules
+ * @returns { Promise }
+ */
+ async js() {
+ await super.js();
+
+ return buildWorkflowModule(this.basePath, this.targetPath);
+ }
+};
diff --git a/build/media_source/com_workflow/joomla.asset.json b/media_source/com_workflow/joomla.asset.json
similarity index 100%
rename from build/media_source/com_workflow/joomla.asset.json
rename to media_source/com_workflow/joomla.asset.json
diff --git a/build/media_source/com_workflow/js/admin-items-workflow-buttons.es6.js b/media_source/com_workflow/js/admin-items-workflow-buttons.es6.js
similarity index 100%
rename from build/media_source/com_workflow/js/admin-items-workflow-buttons.es6.js
rename to media_source/com_workflow/js/admin-items-workflow-buttons.es6.js
diff --git a/build/media_source/com_workflow/js/workflow-graph-client.es6.js b/media_source/com_workflow/js/workflow-graph-client.es6.js
similarity index 100%
rename from build/media_source/com_workflow/js/workflow-graph-client.es6.js
rename to media_source/com_workflow/js/workflow-graph-client.es6.js
diff --git a/build/media_source/com_workflow/scss/workflow-graph-client.scss b/media_source/com_workflow/scss/workflow-graph-client.scss
similarity index 100%
rename from build/media_source/com_workflow/scss/workflow-graph-client.scss
rename to media_source/com_workflow/scss/workflow-graph-client.scss
diff --git a/build/media_source/com_workflow/scss/workflow-graph.scss b/media_source/com_workflow/scss/workflow-graph.scss
similarity index 100%
rename from build/media_source/com_workflow/scss/workflow-graph.scss
rename to media_source/com_workflow/scss/workflow-graph.scss
diff --git a/administrator/components/com_workflow/resources/scripts/app/Event.es6.js b/media_source/com_workflow/src/app/Event.es6.js
similarity index 100%
rename from administrator/components/com_workflow/resources/scripts/app/Event.es6.js
rename to media_source/com_workflow/src/app/Event.es6.js
diff --git a/administrator/components/com_workflow/resources/scripts/app/WorkflowGraphApi.es6.js b/media_source/com_workflow/src/app/WorkflowGraphApi.es6.js
similarity index 100%
rename from administrator/components/com_workflow/resources/scripts/app/WorkflowGraphApi.es6.js
rename to media_source/com_workflow/src/app/WorkflowGraphApi.es6.js
diff --git a/administrator/components/com_workflow/resources/scripts/components/App.vue b/media_source/com_workflow/src/components/App.vue
similarity index 100%
rename from administrator/components/com_workflow/resources/scripts/components/App.vue
rename to media_source/com_workflow/src/components/App.vue
diff --git a/administrator/components/com_workflow/resources/scripts/components/Titlebar.vue b/media_source/com_workflow/src/components/Titlebar.vue
similarity index 100%
rename from administrator/components/com_workflow/resources/scripts/components/Titlebar.vue
rename to media_source/com_workflow/src/components/Titlebar.vue
diff --git a/administrator/components/com_workflow/resources/scripts/components/canvas/ControlsPanel.vue b/media_source/com_workflow/src/components/canvas/ControlsPanel.vue
similarity index 100%
rename from administrator/components/com_workflow/resources/scripts/components/canvas/ControlsPanel.vue
rename to media_source/com_workflow/src/components/canvas/ControlsPanel.vue
diff --git a/administrator/components/com_workflow/resources/scripts/components/canvas/CustomControls.vue b/media_source/com_workflow/src/components/canvas/CustomControls.vue
similarity index 100%
rename from administrator/components/com_workflow/resources/scripts/components/canvas/CustomControls.vue
rename to media_source/com_workflow/src/components/canvas/CustomControls.vue
diff --git a/administrator/components/com_workflow/resources/scripts/components/canvas/WorkflowCanvas.vue b/media_source/com_workflow/src/components/canvas/WorkflowCanvas.vue
similarity index 100%
rename from administrator/components/com_workflow/resources/scripts/components/canvas/WorkflowCanvas.vue
rename to media_source/com_workflow/src/components/canvas/WorkflowCanvas.vue
diff --git a/administrator/components/com_workflow/resources/scripts/components/edges/CustomEdge.vue b/media_source/com_workflow/src/components/edges/CustomEdge.vue
similarity index 100%
rename from administrator/components/com_workflow/resources/scripts/components/edges/CustomEdge.vue
rename to media_source/com_workflow/src/components/edges/CustomEdge.vue
diff --git a/administrator/components/com_workflow/resources/scripts/components/nodes/StageNode.vue b/media_source/com_workflow/src/components/nodes/StageNode.vue
similarity index 100%
rename from administrator/components/com_workflow/resources/scripts/components/nodes/StageNode.vue
rename to media_source/com_workflow/src/components/nodes/StageNode.vue
diff --git a/administrator/components/com_workflow/resources/scripts/plugins/Notifications.es6.js b/media_source/com_workflow/src/plugins/Notifications.es6.js
similarity index 100%
rename from administrator/components/com_workflow/resources/scripts/plugins/Notifications.es6.js
rename to media_source/com_workflow/src/plugins/Notifications.es6.js
diff --git a/administrator/components/com_workflow/resources/scripts/plugins/translate.es6.js b/media_source/com_workflow/src/plugins/translate.es6.js
similarity index 100%
rename from administrator/components/com_workflow/resources/scripts/plugins/translate.es6.js
rename to media_source/com_workflow/src/plugins/translate.es6.js
diff --git a/administrator/components/com_workflow/resources/scripts/store/actions.es6.js b/media_source/com_workflow/src/store/actions.es6.js
similarity index 100%
rename from administrator/components/com_workflow/resources/scripts/store/actions.es6.js
rename to media_source/com_workflow/src/store/actions.es6.js
diff --git a/administrator/components/com_workflow/resources/scripts/store/getters.es6.js b/media_source/com_workflow/src/store/getters.es6.js
similarity index 100%
rename from administrator/components/com_workflow/resources/scripts/store/getters.es6.js
rename to media_source/com_workflow/src/store/getters.es6.js
diff --git a/administrator/components/com_workflow/resources/scripts/store/mutations.es6.js b/media_source/com_workflow/src/store/mutations.es6.js
similarity index 100%
rename from administrator/components/com_workflow/resources/scripts/store/mutations.es6.js
rename to media_source/com_workflow/src/store/mutations.es6.js
diff --git a/administrator/components/com_workflow/resources/scripts/store/plugins/persisted-state.es6.js b/media_source/com_workflow/src/store/plugins/persisted-state.es6.js
similarity index 100%
rename from administrator/components/com_workflow/resources/scripts/store/plugins/persisted-state.es6.js
rename to media_source/com_workflow/src/store/plugins/persisted-state.es6.js
diff --git a/administrator/components/com_workflow/resources/scripts/store/state.es6.js b/media_source/com_workflow/src/store/state.es6.js
similarity index 100%
rename from administrator/components/com_workflow/resources/scripts/store/state.es6.js
rename to media_source/com_workflow/src/store/state.es6.js
diff --git a/administrator/components/com_workflow/resources/scripts/store/store.es6.js b/media_source/com_workflow/src/store/store.es6.js
similarity index 100%
rename from administrator/components/com_workflow/resources/scripts/store/store.es6.js
rename to media_source/com_workflow/src/store/store.es6.js
diff --git a/administrator/components/com_workflow/resources/scripts/utils/accessibility-fixer.es6.js b/media_source/com_workflow/src/utils/accessibility-fixer.es6.js
similarity index 100%
rename from administrator/components/com_workflow/resources/scripts/utils/accessibility-fixer.es6.js
rename to media_source/com_workflow/src/utils/accessibility-fixer.es6.js
diff --git a/administrator/components/com_workflow/resources/scripts/utils/edges.es6.js b/media_source/com_workflow/src/utils/edges.es6.js
similarity index 100%
rename from administrator/components/com_workflow/resources/scripts/utils/edges.es6.js
rename to media_source/com_workflow/src/utils/edges.es6.js
diff --git a/administrator/components/com_workflow/resources/scripts/utils/focus-utils.es6.js b/media_source/com_workflow/src/utils/focus-utils.es6.js
similarity index 100%
rename from administrator/components/com_workflow/resources/scripts/utils/focus-utils.es6.js
rename to media_source/com_workflow/src/utils/focus-utils.es6.js
diff --git a/administrator/components/com_workflow/resources/scripts/utils/keyboard-manager.es6.js b/media_source/com_workflow/src/utils/keyboard-manager.es6.js
similarity index 100%
rename from administrator/components/com_workflow/resources/scripts/utils/keyboard-manager.es6.js
rename to media_source/com_workflow/src/utils/keyboard-manager.es6.js
diff --git a/administrator/components/com_workflow/resources/scripts/utils/positioning.es6.js b/media_source/com_workflow/src/utils/positioning.es6.js
similarity index 100%
rename from administrator/components/com_workflow/resources/scripts/utils/positioning.es6.js
rename to media_source/com_workflow/src/utils/positioning.es6.js
diff --git a/administrator/components/com_workflow/resources/scripts/utils/utils.es6.js b/media_source/com_workflow/src/utils/utils.es6.js
similarity index 100%
rename from administrator/components/com_workflow/resources/scripts/utils/utils.es6.js
rename to media_source/com_workflow/src/utils/utils.es6.js
diff --git a/administrator/components/com_workflow/resources/scripts/workflowgraph.es6.js b/media_source/com_workflow/src/workflowgraph.es6.js
similarity index 100%
rename from administrator/components/com_workflow/resources/scripts/workflowgraph.es6.js
rename to media_source/com_workflow/src/workflowgraph.es6.js
diff --git a/build/media_source/com_wrapper/js/iframe-height.es6.js b/media_source/com_wrapper/js/iframe-height.es6.js
similarity index 100%
rename from build/media_source/com_wrapper/js/iframe-height.es6.js
rename to media_source/com_wrapper/js/iframe-height.es6.js
diff --git a/media_source/error-pages/builder.mjs b/media_source/error-pages/builder.mjs
new file mode 100644
index 00000000000..017f5a3cc45
--- /dev/null
+++ b/media_source/error-pages/builder.mjs
@@ -0,0 +1,177 @@
+/**
+ * Assets Builder
+ */
+import fs from 'node:fs';
+import fsp from 'node:fs/promises';
+import path from 'node:path';
+import Ini from 'ini';
+import buildSettings from '../../build/build-modules-js/settings.json' with { type: 'json' };
+import DefaultModuleBuilder from '../../build/build-modules-js/builder/default-module-builder.mjs';
+import { minifyCSS } from '../../build/build-modules-js/stylesheets/css-handler.mjs';
+import { minifyJSContent } from '../../build/build-modules-js/javascript/js-handle.mjs';
+
+const processIni = async (file, state) => {
+ const languageStrings = Ini.parse(fs.readFileSync(file, { encoding: 'utf8' }));
+
+ // Build the variables into json for the unsupported page
+ if (languageStrings.BUILD_MIN_PHP_ERROR_LANGUAGE) {
+ const name = path.dirname(file).replace(/.+\//, '').replace(/.+\\/, '');
+ state.unsupportedObj = {
+ ...state.unsupportedObj,
+ [name]: {
+ language: Ini.unsafe(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 = path.dirname(file).replace(/.+\//, '').replace(/.+\\/, '');
+ state.incompleteObj = {
+ ...state.incompleteObj,
+ [name]: {
+ language: Ini.unsafe(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 = path.dirname(file).replace(/.+\//, '').replace(/.+\\/, '');
+ state.fatalObj = {
+ ...state.fatalObj,
+ [name]: {
+ language: Ini.unsafe(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 = path.dirname(file).replace(/.+\//, '').replace(/.+\\/, '');
+ state.noxmlObj = {
+ ...state.noxmlObj,
+ [name]: {
+ language: Ini.unsafe(languageStrings.BUILD_NOXML_LANGUAGE),
+ header: languageStrings.BUILD_NOXML_HEADER,
+ text1: languageStrings.BUILD_NOXML_TEXT,
+ 'help-url-text': languageStrings.BUILD_NOXML_URL_TEXT,
+ },
+ };
+ }
+};
+
+const processPage = async (name, pageInfo, state, template, css, js) => {
+ const sortedJson = Object.fromEntries(Object.entries(state[`${name}Obj`]).sort());
+ const jsonContent = `window.errorLocale=${JSON.stringify(sortedJson)};`;
+ const rootPath = process.cwd();
+
+ template = template.replace('{{jsonContents}}', jsonContent);
+ template = template.replace('{{Title}}', pageInfo.title);
+ template = template.replace('{{Header}}', pageInfo.header);
+ template = template.replace('{{Description}}', pageInfo.text);
+ template = template.replace('{{Link}}', pageInfo.link);
+ template = template.replace('{{LinkText}}', pageInfo.linkText);
+
+ if (css) {
+ template = template.replace('{{cssContents}}', css);
+ }
+
+ if (js) {
+ template = template.replace('{{jsContents}}', js);
+ }
+
+ const promises = [];
+ pageInfo.destFile.forEach((file) => {
+ const fullPath = path.join(rootPath, file);
+ const folder = path.dirname(fullPath);
+
+ if (!fs.existsSync(folder)) {
+ fs.mkdirSync(folder, { recursive: true, mode: 0o755});
+ }
+
+ promises.push(fsp.writeFile(fullPath, template, { encoding: 'utf8', mode: 0o644 }));
+ });
+
+ return Promise.all(promises);
+};
+
+/**
+ * Will produce as many .html files as defined in settings.json
+ * Expects three files:
+ * build/warning_page/template.css
+ * build/warning_page/template.html
+ * build/warning_page/template.js
+ *
+ * And also specific strings in the languages in the installation folder!
+ * Also, the base strings are held in build/build-modules-js/settings.json
+ */
+const createErrorPages = async (options, basePath) => {
+ const srcPath = path.join(basePath, 'warning_page');
+ const langsPath = 'installation/language';
+ const state = {
+ incompleteObj: {},
+ unsupportedObj: {},
+ fatalObj: {},
+ noxmlObj: {},
+ };
+
+ // Lookup and parse language files
+ const iniFilesProcess = [];
+ fs.readdirSync(langsPath, { recursive: true, withFileTypes: true}).forEach((file) => {
+ if (file.isDirectory() || file.name.endsWith('langmetadata.xml')) {
+ return;
+ }
+ const iniFile = path.join(file.parentPath, file.name);
+
+ iniFilesProcess.push(processIni(iniFile, state).catch((error) => {
+ throw new Error(`Parsing INI file failed for "${iniFile}".`, { cause: error });
+ }));
+ });
+
+ await Promise.all(iniFilesProcess);
+
+ // Load template files
+ const initTemplate = fs.readFileSync(path.join(srcPath, 'template.html'), { encoding: 'utf8' });
+ let cssContent = fs.readFileSync(path.join(srcPath, 'template.css'), { encoding: 'utf8' });
+ let jsContent = fs.readFileSync(path.join(srcPath, 'template.js'), { encoding: 'utf8' });
+
+ cssContent = await minifyCSS(cssContent);
+ jsContent = await minifyJSContent(jsContent);
+
+ // Lookup and build the pages
+ const processPages = [];
+ Object.keys(options.settings.errorPages).forEach((name) => {
+ const pageInfo = options.settings.errorPages[name];
+
+ processPages.push(processPage(name, pageInfo, state, initTemplate, cssContent, jsContent).catch((error) => {
+ throw new Error(`Failed to build page "${name}".`, { cause: error });
+ }))
+ });
+
+ return Promise.all(processPages);
+};
+
+
+export default class ErrorPagesModuleBuilder extends DefaultModuleBuilder
+{
+ tasksBuild = ['build'];
+ tasksExtras = [];
+
+ /**
+ * Create the pages
+ * @returns { Promise }
+ */
+ async build() {
+ return createErrorPages(buildSettings, this.basePath);
+ }
+};
diff --git a/build/warning_page/template.css b/media_source/error-pages/warning_page/template.css
similarity index 78%
rename from build/warning_page/template.css
rename to media_source/error-pages/warning_page/template.css
index d3561b3ad8e..d90f23fe73c 100644
--- a/build/warning_page/template.css
+++ b/media_source/error-pages/warning_page/template.css
@@ -1,15 +1,10 @@
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;
+ background: #ee2a00 radial-gradient(ellipse at center, rgba(241, 241, 241, 1) 0, rgb(238, 42, 0) 100%) no-repeat fixed;
}
body {
- margin: 0;
padding: 0;
+ margin: 0;
font: 14px / 18px sans-serif;
color: #555;
background-color: transparent;
@@ -35,35 +30,35 @@ p a {
}
.container {
+ position: relative;
display: flex;
flex-direction: column;
- justify-content: center;
align-items: center;
- position: relative;
- margin: 0 auto;
+ justify-content: center;
width: 100%;
height: 100vh;
+ margin: 0 auto;
overflow: hidden;
}
.alert-main {
- display: block;
position: relative;
- background: #fff;
- border: 1px solid rgba(0,0,0,0.1);
- border-radius: 5px;
+ display: block;
padding: 20px 60px;
margin: 0 20px;
- box-shadow: 0 0 10px rgba(0,0,0,0.05);
+ background: #fff;
+ border: 1px solid rgba(0,0,0,.1);
+ border-radius: 5px;
+ box-shadow: 0 0 10px rgba(0,0,0,.05);
}
svg {
position: absolute;
- bottom: -120px;
right: -70px;
+ bottom: -120px;
+ z-index: -1;
width: 400px;
transform: rotate(10deg);
- z-index: -1;
}
h1, p {
@@ -91,27 +86,27 @@ p, label {
p a {
font-weight: bold;
- color: #1C3D5C;
+ color: #1c3d5c;
}
.link-help {
padding: .4rem .85rem;
font-size: 1rem;
font-weight: normal;
- border-radius: .25rem;
text-decoration: none;
background-color: #f5f5f5;
- border: 1px solid rgba(0,0,0,0.1);
+ border: 1px solid rgba(0,0,0,.1);
+ border-radius: .25rem;
}
.link-help:hover {
- background-color: #eee;
text-decoration: none;
+ background-color: #eee;
}
.footer {
margin: 8px 20px;
- text-align: left;
font-size: 11px;
+ text-align: left;
}
.footer ul {
@@ -125,20 +120,20 @@ p a {
}
.footer li, .footer a {
- color: #1C3D5C;
+ color: #1c3d5c;
}
.footer a:hover {
- color: #59B0FF;
+ color: #59b0ff;
}
.links {
display: block;
- text-align: center;
margin-top: 4rem;
- margin-left: auto;
margin-right: auto;
+ margin-left: auto;
font-size: 1rem;
+ text-align: center;
}
.links li {
display: inline-block;
diff --git a/build/warning_page/template.html b/media_source/error-pages/warning_page/template.html
similarity index 100%
rename from build/warning_page/template.html
rename to media_source/error-pages/warning_page/template.html
diff --git a/build/warning_page/template.js b/media_source/error-pages/warning_page/template.js
similarity index 100%
rename from build/warning_page/template.js
rename to media_source/error-pages/warning_page/template.js
diff --git a/build/media_source/index.html b/media_source/index.html
similarity index 100%
rename from build/media_source/index.html
rename to media_source/index.html
diff --git a/media_source/installation/template/builder.mjs b/media_source/installation/template/builder.mjs
new file mode 100644
index 00000000000..2e5ef6c46cd
--- /dev/null
+++ b/media_source/installation/template/builder.mjs
@@ -0,0 +1,51 @@
+/**
+ * Assets Builder
+ */
+import path from 'node:path';
+import fsp from "node:fs/promises";
+import fs from "node:fs";
+
+import DefaultModuleBuilder from '../../../build/build-modules-js/builder/default-module-builder.mjs';
+
+
+export default class InstallationTmplModuleBuilder extends DefaultModuleBuilder
+{
+ /**
+ * Class constructor.
+ *
+ * @param { string } name The folder (builder) name. Relative to media/.
+ * @param { string } basePath Base path to the media source, without builder name.
+ * @param { string } targetPath Path to the media target, without builder name.
+ * @param { object } options Options object, from cmd or etc.
+ */
+ constructor(name = '', basePath = '', targetPath = '', options = {}) {
+ super(name, basePath, targetPath, options);
+
+ // Update target, because it is outside /media folder
+ this.targetPath = path.join(path.dirname(targetPath), name);
+ }
+
+ /**
+ * Remove files on target location
+ * @returns { Promise }
+ */
+ async clear() {
+ if (!fs.existsSync(this.targetPath)) {
+ return;
+ }
+ const promises = [];
+
+ // Do not remove all, since the target contain PHP files also
+ ['css', 'js', 'images', 'scss'].forEach((dir) => {
+ const fullPath = path.join(this.targetPath, dir);
+
+ if (!fs.existsSync(fullPath)) {
+ return;
+ }
+
+ promises.push(fsp.rm(fullPath, { recursive: true }));
+ });
+
+ return Promise.all(promises);
+ }
+};
diff --git a/installation/template/images/Joomla-brandmark-monochrome-white-RGB.svg b/media_source/installation/template/images/Joomla-brandmark-monochrome-white-RGB.svg
similarity index 100%
rename from installation/template/images/Joomla-brandmark-monochrome-white-RGB.svg
rename to media_source/installation/template/images/Joomla-brandmark-monochrome-white-RGB.svg
diff --git a/installation/template/images/Joomla-logo-monochrome-horizontal-white.svg b/media_source/installation/template/images/Joomla-logo-monochrome-horizontal-white.svg
similarity index 100%
rename from installation/template/images/Joomla-logo-monochrome-horizontal-white.svg
rename to media_source/installation/template/images/Joomla-logo-monochrome-horizontal-white.svg
diff --git a/installation/template/images/joomla-pattern.svg b/media_source/installation/template/images/joomla-pattern.svg
similarity index 100%
rename from installation/template/images/joomla-pattern.svg
rename to media_source/installation/template/images/joomla-pattern.svg
diff --git a/installation/template/images/joomla.png b/media_source/installation/template/images/joomla.png
similarity index 100%
rename from installation/template/images/joomla.png
rename to media_source/installation/template/images/joomla.png
diff --git a/installation/template/images/logo-blue.svg b/media_source/installation/template/images/logo-blue.svg
similarity index 100%
rename from installation/template/images/logo-blue.svg
rename to media_source/installation/template/images/logo-blue.svg
diff --git a/installation/template/images/logo-joomla-blue.svg b/media_source/installation/template/images/logo-joomla-blue.svg
similarity index 100%
rename from installation/template/images/logo-joomla-blue.svg
rename to media_source/installation/template/images/logo-joomla-blue.svg
diff --git a/installation/template/images/logo.svg b/media_source/installation/template/images/logo.svg
similarity index 100%
rename from installation/template/images/logo.svg
rename to media_source/installation/template/images/logo.svg
diff --git a/installation/template/images/select-bg-dark.svg b/media_source/installation/template/images/select-bg-dark.svg
similarity index 100%
rename from installation/template/images/select-bg-dark.svg
rename to media_source/installation/template/images/select-bg-dark.svg
diff --git a/build/media_source/templates/administrator/atum/images/select-bg-rtl-dark.svg b/media_source/installation/template/images/select-bg-rtl-dark.svg
similarity index 100%
rename from build/media_source/templates/administrator/atum/images/select-bg-rtl-dark.svg
rename to media_source/installation/template/images/select-bg-rtl-dark.svg
diff --git a/build/media_source/system/images/select-bg-rtl.svg b/media_source/installation/template/images/select-bg-rtl.svg
similarity index 100%
rename from build/media_source/system/images/select-bg-rtl.svg
rename to media_source/installation/template/images/select-bg-rtl.svg
diff --git a/build/media_source/system/images/select-bg.svg b/media_source/installation/template/images/select-bg.svg
similarity index 100%
rename from build/media_source/system/images/select-bg.svg
rename to media_source/installation/template/images/select-bg.svg
diff --git a/installation/template/js/remove.js b/media_source/installation/template/js/remove.js
similarity index 100%
rename from installation/template/js/remove.js
rename to media_source/installation/template/js/remove.js
diff --git a/installation/template/js/setup.js b/media_source/installation/template/js/setup.js
similarity index 100%
rename from installation/template/js/setup.js
rename to media_source/installation/template/js/setup.js
diff --git a/installation/template/js/template.js b/media_source/installation/template/js/template.js
similarity index 97%
rename from installation/template/js/template.js
rename to media_source/installation/template/js/template.js
index a8caefc4b29..5361e7b8938 100644
--- a/installation/template/js/template.js
+++ b/media_source/installation/template/js/template.js
@@ -264,9 +264,9 @@
}
if (page && page.getAttribute('data-page-name')) {
- var script = document.querySelector('script[src*="template.js"]');
+ var script = document.querySelector('script[src*="/template.js"], script[src*="/template.min.js"]');
el = document.createElement('script');
- el.src = script.src.replace("template.js", page.getAttribute('data-page-name') + '.js');
+ el.src = script.src.replace('/template.', '/' + page.getAttribute('data-page-name') + '.');
document.head.appendChild(el);
}
diff --git a/build/media_source/templates/administrator/atum/scss/template-rtl.scss b/media_source/installation/template/scss/template-rtl.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/template-rtl.scss
rename to media_source/installation/template/scss/template-rtl.scss
diff --git a/installation/template/scss/template.scss b/media_source/installation/template/scss/template.scss
similarity index 84%
rename from installation/template/scss/template.scss
rename to media_source/installation/template/scss/template.scss
index 78a53eca8c7..a42198955f3 100644
--- a/installation/template/scss/template.scss
+++ b/media_source/installation/template/scss/template.scss
@@ -3,44 +3,44 @@ $fa-css-prefix: fa;
$fa-font-path: "../../../media/vendor/fontawesome-free/webfonts";
// Font Awesome
-@import "../../../media/templates/administrator/atum/scss/vendor/fontawesome-free/fontawesome";
+@import "../../../../media_source/templates/administrator/atum/scss/vendor/fontawesome-free/fontawesome";
// "Font Awesome 6 Free"
-@import "../../../media/vendor/fontawesome-free/scss/fontawesome";
-@import "../../../media/vendor/fontawesome-free/scss/regular";
-@import "../../../media/vendor/fontawesome-free/scss/solid";
-@import "../../../media/vendor/fontawesome-free/scss/brands"; // order of loading is important.
+@import "../../../../media/vendor/fontawesome-free/scss/fontawesome";
+@import "../../../../media/vendor/fontawesome-free/scss/regular";
+@import "../../../../media/vendor/fontawesome-free/scss/solid";
+@import "../../../../media/vendor/fontawesome-free/scss/brands"; // order of loading is important.
// B/C with Font Awesome 5
-@import "../../../media/vendor/fontawesome-free/scss/shims";
+@import "../../../../media/vendor/fontawesome-free/scss/shims";
// B/C for Icomoon
-@import "../../../build/media_source/system/scss/icomoon";
+@import "../../../../media_source/system/scss/icomoon";
// Bootstrap
-@import "../../../media/vendor/bootstrap/scss/functions";
+@import "../../../../media/vendor/bootstrap/scss/functions";
// Variables from the Atum template
-@import "../../../build/media_source/templates/administrator/atum/scss/variables";
-@import "../../../build/media_source/templates/administrator/atum/scss/variables-dark";
+@import "../../../../media_source/templates/administrator/atum/scss/variables";
+@import "../../../../media_source/templates/administrator/atum/scss/variables-dark";
$table-bg: transparent;
-@import "../../../media/vendor/bootstrap/scss/variables";
-@import "../../../media/vendor/bootstrap/scss/variables-dark";
-@import "../../../media/vendor/bootstrap/scss/maps";
-@import "../../../media/vendor/bootstrap/scss/mixins";
-@import "../../../media/vendor/bootstrap/scss/utilities";
-@import "../../../media/vendor/bootstrap/scss/bootstrap";
+@import "../../../../media/vendor/bootstrap/scss/variables";
+@import "../../../../media/vendor/bootstrap/scss/variables-dark";
+@import "../../../../media/vendor/bootstrap/scss/maps";
+@import "../../../../media/vendor/bootstrap/scss/mixins";
+@import "../../../../media/vendor/bootstrap/scss/utilities";
+@import "../../../../media/vendor/bootstrap/scss/bootstrap";
// Backend Template stuff
-@import "../../../media/templates/administrator/atum/scss/blocks/global";
-@import "../../../media/templates/administrator/atum/scss/blocks/header";
-@import "../../../media/templates/administrator/atum/scss/vendor/bootstrap/custom-forms";
-@import "../../../media/templates/administrator/atum/scss/vendor/joomla-custom-elements/joomla-alert";
+@import "../../../../media_source/templates/administrator/atum/scss/blocks/global";
+@import "../../../../media_source/templates/administrator/atum/scss/blocks/header";
+@import "../../../../media_source/templates/administrator/atum/scss/vendor/bootstrap/custom-forms";
+@import "../../../../media_source/templates/administrator/atum/scss/vendor/joomla-custom-elements/joomla-alert";
// Safari fix
-@import "../../../media/templates/administrator/atum/scss/vendor/bootstrap/reboot";
+@import "../../../../media_source/templates/administrator/atum/scss/vendor/bootstrap/reboot";
// Custom Atum colors
:root {
diff --git a/build/media_source/layouts/css/chromes/outline.css b/media_source/layouts/css/chromes/outline.css
similarity index 100%
rename from build/media_source/layouts/css/chromes/outline.css
rename to media_source/layouts/css/chromes/outline.css
diff --git a/build/media_source/layouts/js/joomla/form/field/category-change.es6.js b/media_source/layouts/js/joomla/form/field/category-change.es6.js
similarity index 100%
rename from build/media_source/layouts/js/joomla/form/field/category-change.es6.js
rename to media_source/layouts/js/joomla/form/field/category-change.es6.js
diff --git a/build/media_source/layouts/js/joomla/html/batch/batch-copymove.es6.js b/media_source/layouts/js/joomla/html/batch/batch-copymove.es6.js
similarity index 100%
rename from build/media_source/layouts/js/joomla/html/batch/batch-copymove.es6.js
rename to media_source/layouts/js/joomla/html/batch/batch-copymove.es6.js
diff --git a/build/media_source/layouts/js/joomla/html/batch/batch-tag-addremove.es6.js b/media_source/layouts/js/joomla/html/batch/batch-tag-addremove.es6.js
similarity index 100%
rename from build/media_source/layouts/js/joomla/html/batch/batch-tag-addremove.es6.js
rename to media_source/layouts/js/joomla/html/batch/batch-tag-addremove.es6.js
diff --git a/build/media_source/legacy/js/toolbar.es5.js b/media_source/legacy/js/toolbar.es5.js
similarity index 100%
rename from build/media_source/legacy/js/toolbar.es5.js
rename to media_source/legacy/js/toolbar.es5.js
diff --git a/build/media_source/mailto/images/close-x.png b/media_source/mailto/images/close-x.png
similarity index 100%
rename from build/media_source/mailto/images/close-x.png
rename to media_source/mailto/images/close-x.png
diff --git a/build/media_source/mod_articles/css/mod-articles.css b/media_source/mod_articles/css/mod-articles.css
similarity index 100%
rename from build/media_source/mod_articles/css/mod-articles.css
rename to media_source/mod_articles/css/mod-articles.css
diff --git a/build/media_source/mod_articles_news/css/template-vert.css b/media_source/mod_articles_news/css/template-vert.css
similarity index 100%
rename from build/media_source/mod_articles_news/css/template-vert.css
rename to media_source/mod_articles_news/css/template-vert.css
diff --git a/build/media_source/mod_articles_news/css/template.css b/media_source/mod_articles_news/css/template.css
similarity index 100%
rename from build/media_source/mod_articles_news/css/template.css
rename to media_source/mod_articles_news/css/template.css
diff --git a/build/media_source/mod_languages/css/template.css b/media_source/mod_languages/css/template.css
similarity index 100%
rename from build/media_source/mod_languages/css/template.css
rename to media_source/mod_languages/css/template.css
diff --git a/build/media_source/mod_languages/images/af.gif b/media_source/mod_languages/images/af.gif
similarity index 100%
rename from build/media_source/mod_languages/images/af.gif
rename to media_source/mod_languages/images/af.gif
diff --git a/build/media_source/mod_languages/images/af_za.gif b/media_source/mod_languages/images/af_za.gif
similarity index 100%
rename from build/media_source/mod_languages/images/af_za.gif
rename to media_source/mod_languages/images/af_za.gif
diff --git a/build/media_source/mod_languages/images/al.gif b/media_source/mod_languages/images/al.gif
similarity index 100%
rename from build/media_source/mod_languages/images/al.gif
rename to media_source/mod_languages/images/al.gif
diff --git a/build/media_source/mod_languages/images/ar.gif b/media_source/mod_languages/images/ar.gif
similarity index 100%
rename from build/media_source/mod_languages/images/ar.gif
rename to media_source/mod_languages/images/ar.gif
diff --git a/build/media_source/mod_languages/images/ar_aa.gif b/media_source/mod_languages/images/ar_aa.gif
similarity index 100%
rename from build/media_source/mod_languages/images/ar_aa.gif
rename to media_source/mod_languages/images/ar_aa.gif
diff --git a/build/media_source/mod_languages/images/at.gif b/media_source/mod_languages/images/at.gif
similarity index 100%
rename from build/media_source/mod_languages/images/at.gif
rename to media_source/mod_languages/images/at.gif
diff --git a/build/media_source/mod_languages/images/az.gif b/media_source/mod_languages/images/az.gif
similarity index 100%
rename from build/media_source/mod_languages/images/az.gif
rename to media_source/mod_languages/images/az.gif
diff --git a/build/media_source/mod_languages/images/az_az.gif b/media_source/mod_languages/images/az_az.gif
similarity index 100%
rename from build/media_source/mod_languages/images/az_az.gif
rename to media_source/mod_languages/images/az_az.gif
diff --git a/build/media_source/mod_languages/images/be.gif b/media_source/mod_languages/images/be.gif
similarity index 100%
rename from build/media_source/mod_languages/images/be.gif
rename to media_source/mod_languages/images/be.gif
diff --git a/build/media_source/mod_languages/images/be_by.gif b/media_source/mod_languages/images/be_by.gif
similarity index 100%
rename from build/media_source/mod_languages/images/be_by.gif
rename to media_source/mod_languages/images/be_by.gif
diff --git a/build/media_source/mod_languages/images/belg.gif b/media_source/mod_languages/images/belg.gif
similarity index 100%
rename from build/media_source/mod_languages/images/belg.gif
rename to media_source/mod_languages/images/belg.gif
diff --git a/build/media_source/mod_languages/images/bg.gif b/media_source/mod_languages/images/bg.gif
similarity index 100%
rename from build/media_source/mod_languages/images/bg.gif
rename to media_source/mod_languages/images/bg.gif
diff --git a/build/media_source/mod_languages/images/bg_bg.gif b/media_source/mod_languages/images/bg_bg.gif
similarity index 100%
rename from build/media_source/mod_languages/images/bg_bg.gif
rename to media_source/mod_languages/images/bg_bg.gif
diff --git a/build/media_source/mod_languages/images/bn.gif b/media_source/mod_languages/images/bn.gif
similarity index 100%
rename from build/media_source/mod_languages/images/bn.gif
rename to media_source/mod_languages/images/bn.gif
diff --git a/build/media_source/mod_languages/images/bn_bd.gif b/media_source/mod_languages/images/bn_bd.gif
similarity index 100%
rename from build/media_source/mod_languages/images/bn_bd.gif
rename to media_source/mod_languages/images/bn_bd.gif
diff --git a/build/media_source/mod_languages/images/br.gif b/media_source/mod_languages/images/br.gif
similarity index 100%
rename from build/media_source/mod_languages/images/br.gif
rename to media_source/mod_languages/images/br.gif
diff --git a/build/media_source/mod_languages/images/br_fr.gif b/media_source/mod_languages/images/br_fr.gif
similarity index 100%
rename from build/media_source/mod_languages/images/br_fr.gif
rename to media_source/mod_languages/images/br_fr.gif
diff --git a/build/media_source/mod_languages/images/bs.gif b/media_source/mod_languages/images/bs.gif
similarity index 100%
rename from build/media_source/mod_languages/images/bs.gif
rename to media_source/mod_languages/images/bs.gif
diff --git a/build/media_source/mod_languages/images/bs_ba.gif b/media_source/mod_languages/images/bs_ba.gif
similarity index 100%
rename from build/media_source/mod_languages/images/bs_ba.gif
rename to media_source/mod_languages/images/bs_ba.gif
diff --git a/build/media_source/mod_languages/images/ca.gif b/media_source/mod_languages/images/ca.gif
similarity index 100%
rename from build/media_source/mod_languages/images/ca.gif
rename to media_source/mod_languages/images/ca.gif
diff --git a/build/media_source/mod_languages/images/ca_es.gif b/media_source/mod_languages/images/ca_es.gif
similarity index 100%
rename from build/media_source/mod_languages/images/ca_es.gif
rename to media_source/mod_languages/images/ca_es.gif
diff --git a/build/media_source/mod_languages/images/cbk_iq.gif b/media_source/mod_languages/images/cbk_iq.gif
similarity index 100%
rename from build/media_source/mod_languages/images/cbk_iq.gif
rename to media_source/mod_languages/images/cbk_iq.gif
diff --git a/build/media_source/mod_languages/images/ch.gif b/media_source/mod_languages/images/ch.gif
similarity index 100%
rename from build/media_source/mod_languages/images/ch.gif
rename to media_source/mod_languages/images/ch.gif
diff --git a/build/media_source/mod_languages/images/cs.gif b/media_source/mod_languages/images/cs.gif
similarity index 100%
rename from build/media_source/mod_languages/images/cs.gif
rename to media_source/mod_languages/images/cs.gif
diff --git a/build/media_source/mod_languages/images/cs_cz.gif b/media_source/mod_languages/images/cs_cz.gif
similarity index 100%
rename from build/media_source/mod_languages/images/cs_cz.gif
rename to media_source/mod_languages/images/cs_cz.gif
diff --git a/build/media_source/mod_languages/images/cy.gif b/media_source/mod_languages/images/cy.gif
similarity index 100%
rename from build/media_source/mod_languages/images/cy.gif
rename to media_source/mod_languages/images/cy.gif
diff --git a/build/media_source/mod_languages/images/cy_gb.gif b/media_source/mod_languages/images/cy_gb.gif
similarity index 100%
rename from build/media_source/mod_languages/images/cy_gb.gif
rename to media_source/mod_languages/images/cy_gb.gif
diff --git a/build/media_source/mod_languages/images/cz.gif b/media_source/mod_languages/images/cz.gif
similarity index 100%
rename from build/media_source/mod_languages/images/cz.gif
rename to media_source/mod_languages/images/cz.gif
diff --git a/build/media_source/mod_languages/images/cz_cz.gif b/media_source/mod_languages/images/cz_cz.gif
similarity index 100%
rename from build/media_source/mod_languages/images/cz_cz.gif
rename to media_source/mod_languages/images/cz_cz.gif
diff --git a/build/media_source/mod_languages/images/da.gif b/media_source/mod_languages/images/da.gif
similarity index 100%
rename from build/media_source/mod_languages/images/da.gif
rename to media_source/mod_languages/images/da.gif
diff --git a/build/media_source/mod_languages/images/da_dk.gif b/media_source/mod_languages/images/da_dk.gif
similarity index 100%
rename from build/media_source/mod_languages/images/da_dk.gif
rename to media_source/mod_languages/images/da_dk.gif
diff --git a/build/media_source/mod_languages/images/de.gif b/media_source/mod_languages/images/de.gif
similarity index 100%
rename from build/media_source/mod_languages/images/de.gif
rename to media_source/mod_languages/images/de.gif
diff --git a/build/media_source/mod_languages/images/de_at.gif b/media_source/mod_languages/images/de_at.gif
similarity index 100%
rename from build/media_source/mod_languages/images/de_at.gif
rename to media_source/mod_languages/images/de_at.gif
diff --git a/build/media_source/mod_languages/images/de_ch.gif b/media_source/mod_languages/images/de_ch.gif
similarity index 100%
rename from build/media_source/mod_languages/images/de_ch.gif
rename to media_source/mod_languages/images/de_ch.gif
diff --git a/build/media_source/mod_languages/images/de_de.gif b/media_source/mod_languages/images/de_de.gif
similarity index 100%
rename from build/media_source/mod_languages/images/de_de.gif
rename to media_source/mod_languages/images/de_de.gif
diff --git a/build/media_source/mod_languages/images/de_li.gif b/media_source/mod_languages/images/de_li.gif
similarity index 100%
rename from build/media_source/mod_languages/images/de_li.gif
rename to media_source/mod_languages/images/de_li.gif
diff --git a/build/media_source/mod_languages/images/de_lu.gif b/media_source/mod_languages/images/de_lu.gif
similarity index 100%
rename from build/media_source/mod_languages/images/de_lu.gif
rename to media_source/mod_languages/images/de_lu.gif
diff --git a/build/media_source/mod_languages/images/dk.gif b/media_source/mod_languages/images/dk.gif
similarity index 100%
rename from build/media_source/mod_languages/images/dk.gif
rename to media_source/mod_languages/images/dk.gif
diff --git a/build/media_source/mod_languages/images/dz_bt.gif b/media_source/mod_languages/images/dz_bt.gif
similarity index 100%
rename from build/media_source/mod_languages/images/dz_bt.gif
rename to media_source/mod_languages/images/dz_bt.gif
diff --git a/build/media_source/mod_languages/images/el.gif b/media_source/mod_languages/images/el.gif
similarity index 100%
rename from build/media_source/mod_languages/images/el.gif
rename to media_source/mod_languages/images/el.gif
diff --git a/build/media_source/mod_languages/images/el_gr.gif b/media_source/mod_languages/images/el_gr.gif
similarity index 100%
rename from build/media_source/mod_languages/images/el_gr.gif
rename to media_source/mod_languages/images/el_gr.gif
diff --git a/build/media_source/mod_languages/images/en.gif b/media_source/mod_languages/images/en.gif
similarity index 100%
rename from build/media_source/mod_languages/images/en.gif
rename to media_source/mod_languages/images/en.gif
diff --git a/build/media_source/mod_languages/images/en_au.gif b/media_source/mod_languages/images/en_au.gif
similarity index 100%
rename from build/media_source/mod_languages/images/en_au.gif
rename to media_source/mod_languages/images/en_au.gif
diff --git a/build/media_source/mod_languages/images/en_ca.gif b/media_source/mod_languages/images/en_ca.gif
similarity index 100%
rename from build/media_source/mod_languages/images/en_ca.gif
rename to media_source/mod_languages/images/en_ca.gif
diff --git a/build/media_source/mod_languages/images/en_gb.gif b/media_source/mod_languages/images/en_gb.gif
similarity index 100%
rename from build/media_source/mod_languages/images/en_gb.gif
rename to media_source/mod_languages/images/en_gb.gif
diff --git a/build/media_source/mod_languages/images/en_nz.gif b/media_source/mod_languages/images/en_nz.gif
similarity index 100%
rename from build/media_source/mod_languages/images/en_nz.gif
rename to media_source/mod_languages/images/en_nz.gif
diff --git a/build/media_source/mod_languages/images/en_us.gif b/media_source/mod_languages/images/en_us.gif
similarity index 100%
rename from build/media_source/mod_languages/images/en_us.gif
rename to media_source/mod_languages/images/en_us.gif
diff --git a/build/media_source/mod_languages/images/eo.gif b/media_source/mod_languages/images/eo.gif
similarity index 100%
rename from build/media_source/mod_languages/images/eo.gif
rename to media_source/mod_languages/images/eo.gif
diff --git a/build/media_source/mod_languages/images/eo_xx.gif b/media_source/mod_languages/images/eo_xx.gif
similarity index 100%
rename from build/media_source/mod_languages/images/eo_xx.gif
rename to media_source/mod_languages/images/eo_xx.gif
diff --git a/build/media_source/mod_languages/images/es.gif b/media_source/mod_languages/images/es.gif
similarity index 100%
rename from build/media_source/mod_languages/images/es.gif
rename to media_source/mod_languages/images/es.gif
diff --git a/build/media_source/mod_languages/images/es_co.gif b/media_source/mod_languages/images/es_co.gif
similarity index 100%
rename from build/media_source/mod_languages/images/es_co.gif
rename to media_source/mod_languages/images/es_co.gif
diff --git a/build/media_source/mod_languages/images/es_es.gif b/media_source/mod_languages/images/es_es.gif
similarity index 100%
rename from build/media_source/mod_languages/images/es_es.gif
rename to media_source/mod_languages/images/es_es.gif
diff --git a/build/media_source/mod_languages/images/et.gif b/media_source/mod_languages/images/et.gif
similarity index 100%
rename from build/media_source/mod_languages/images/et.gif
rename to media_source/mod_languages/images/et.gif
diff --git a/build/media_source/mod_languages/images/et_ee.gif b/media_source/mod_languages/images/et_ee.gif
similarity index 100%
rename from build/media_source/mod_languages/images/et_ee.gif
rename to media_source/mod_languages/images/et_ee.gif
diff --git a/build/media_source/mod_languages/images/eu_es.gif b/media_source/mod_languages/images/eu_es.gif
similarity index 100%
rename from build/media_source/mod_languages/images/eu_es.gif
rename to media_source/mod_languages/images/eu_es.gif
diff --git a/build/media_source/mod_languages/images/fa.gif b/media_source/mod_languages/images/fa.gif
similarity index 100%
rename from build/media_source/mod_languages/images/fa.gif
rename to media_source/mod_languages/images/fa.gif
diff --git a/build/media_source/mod_languages/images/fa_ir.gif b/media_source/mod_languages/images/fa_ir.gif
similarity index 100%
rename from build/media_source/mod_languages/images/fa_ir.gif
rename to media_source/mod_languages/images/fa_ir.gif
diff --git a/build/media_source/mod_languages/images/fi.gif b/media_source/mod_languages/images/fi.gif
similarity index 100%
rename from build/media_source/mod_languages/images/fi.gif
rename to media_source/mod_languages/images/fi.gif
diff --git a/build/media_source/mod_languages/images/fi_fi.gif b/media_source/mod_languages/images/fi_fi.gif
similarity index 100%
rename from build/media_source/mod_languages/images/fi_fi.gif
rename to media_source/mod_languages/images/fi_fi.gif
diff --git a/build/media_source/mod_languages/images/fr.gif b/media_source/mod_languages/images/fr.gif
similarity index 100%
rename from build/media_source/mod_languages/images/fr.gif
rename to media_source/mod_languages/images/fr.gif
diff --git a/build/media_source/mod_languages/images/fr_ca.gif b/media_source/mod_languages/images/fr_ca.gif
similarity index 100%
rename from build/media_source/mod_languages/images/fr_ca.gif
rename to media_source/mod_languages/images/fr_ca.gif
diff --git a/build/media_source/mod_languages/images/fr_fr.gif b/media_source/mod_languages/images/fr_fr.gif
similarity index 100%
rename from build/media_source/mod_languages/images/fr_fr.gif
rename to media_source/mod_languages/images/fr_fr.gif
diff --git a/build/media_source/mod_languages/images/ga_ie.gif b/media_source/mod_languages/images/ga_ie.gif
similarity index 100%
rename from build/media_source/mod_languages/images/ga_ie.gif
rename to media_source/mod_languages/images/ga_ie.gif
diff --git a/build/media_source/mod_languages/images/gd.gif b/media_source/mod_languages/images/gd.gif
similarity index 100%
rename from build/media_source/mod_languages/images/gd.gif
rename to media_source/mod_languages/images/gd.gif
diff --git a/build/media_source/mod_languages/images/gd_gb.gif b/media_source/mod_languages/images/gd_gb.gif
similarity index 100%
rename from build/media_source/mod_languages/images/gd_gb.gif
rename to media_source/mod_languages/images/gd_gb.gif
diff --git a/build/media_source/mod_languages/images/gl.gif b/media_source/mod_languages/images/gl.gif
similarity index 100%
rename from build/media_source/mod_languages/images/gl.gif
rename to media_source/mod_languages/images/gl.gif
diff --git a/build/media_source/mod_languages/images/gl_es.gif b/media_source/mod_languages/images/gl_es.gif
similarity index 100%
rename from build/media_source/mod_languages/images/gl_es.gif
rename to media_source/mod_languages/images/gl_es.gif
diff --git a/build/media_source/mod_languages/images/he.gif b/media_source/mod_languages/images/he.gif
similarity index 100%
rename from build/media_source/mod_languages/images/he.gif
rename to media_source/mod_languages/images/he.gif
diff --git a/build/media_source/mod_languages/images/he_il.gif b/media_source/mod_languages/images/he_il.gif
similarity index 100%
rename from build/media_source/mod_languages/images/he_il.gif
rename to media_source/mod_languages/images/he_il.gif
diff --git a/build/media_source/mod_languages/images/hi.gif b/media_source/mod_languages/images/hi.gif
similarity index 100%
rename from build/media_source/mod_languages/images/hi.gif
rename to media_source/mod_languages/images/hi.gif
diff --git a/build/media_source/mod_languages/images/hi_in.gif b/media_source/mod_languages/images/hi_in.gif
similarity index 100%
rename from build/media_source/mod_languages/images/hi_in.gif
rename to media_source/mod_languages/images/hi_in.gif
diff --git a/build/media_source/mod_languages/images/hk.gif b/media_source/mod_languages/images/hk.gif
similarity index 100%
rename from build/media_source/mod_languages/images/hk.gif
rename to media_source/mod_languages/images/hk.gif
diff --git a/build/media_source/mod_languages/images/hk_hk.gif b/media_source/mod_languages/images/hk_hk.gif
similarity index 100%
rename from build/media_source/mod_languages/images/hk_hk.gif
rename to media_source/mod_languages/images/hk_hk.gif
diff --git a/build/media_source/mod_languages/images/hr.gif b/media_source/mod_languages/images/hr.gif
similarity index 100%
rename from build/media_source/mod_languages/images/hr.gif
rename to media_source/mod_languages/images/hr.gif
diff --git a/build/media_source/mod_languages/images/hr_hr.gif b/media_source/mod_languages/images/hr_hr.gif
similarity index 100%
rename from build/media_source/mod_languages/images/hr_hr.gif
rename to media_source/mod_languages/images/hr_hr.gif
diff --git a/build/media_source/mod_languages/images/hu.gif b/media_source/mod_languages/images/hu.gif
similarity index 100%
rename from build/media_source/mod_languages/images/hu.gif
rename to media_source/mod_languages/images/hu.gif
diff --git a/build/media_source/mod_languages/images/hu_hu.gif b/media_source/mod_languages/images/hu_hu.gif
similarity index 100%
rename from build/media_source/mod_languages/images/hu_hu.gif
rename to media_source/mod_languages/images/hu_hu.gif
diff --git a/build/media_source/mod_languages/images/hy.gif b/media_source/mod_languages/images/hy.gif
similarity index 100%
rename from build/media_source/mod_languages/images/hy.gif
rename to media_source/mod_languages/images/hy.gif
diff --git a/build/media_source/mod_languages/images/hy_am.gif b/media_source/mod_languages/images/hy_am.gif
similarity index 100%
rename from build/media_source/mod_languages/images/hy_am.gif
rename to media_source/mod_languages/images/hy_am.gif
diff --git a/build/media_source/mod_languages/images/icon-16-language.png b/media_source/mod_languages/images/icon-16-language.png
similarity index 100%
rename from build/media_source/mod_languages/images/icon-16-language.png
rename to media_source/mod_languages/images/icon-16-language.png
diff --git a/build/media_source/mod_languages/images/id.gif b/media_source/mod_languages/images/id.gif
similarity index 100%
rename from build/media_source/mod_languages/images/id.gif
rename to media_source/mod_languages/images/id.gif
diff --git a/build/media_source/mod_languages/images/id_id.gif b/media_source/mod_languages/images/id_id.gif
similarity index 100%
rename from build/media_source/mod_languages/images/id_id.gif
rename to media_source/mod_languages/images/id_id.gif
diff --git a/build/media_source/mod_languages/images/is.gif b/media_source/mod_languages/images/is.gif
similarity index 100%
rename from build/media_source/mod_languages/images/is.gif
rename to media_source/mod_languages/images/is.gif
diff --git a/build/media_source/mod_languages/images/is_is.gif b/media_source/mod_languages/images/is_is.gif
similarity index 100%
rename from build/media_source/mod_languages/images/is_is.gif
rename to media_source/mod_languages/images/is_is.gif
diff --git a/build/media_source/mod_languages/images/it.gif b/media_source/mod_languages/images/it.gif
similarity index 100%
rename from build/media_source/mod_languages/images/it.gif
rename to media_source/mod_languages/images/it.gif
diff --git a/build/media_source/mod_languages/images/it_it.gif b/media_source/mod_languages/images/it_it.gif
similarity index 100%
rename from build/media_source/mod_languages/images/it_it.gif
rename to media_source/mod_languages/images/it_it.gif
diff --git a/build/media_source/mod_languages/images/ja.gif b/media_source/mod_languages/images/ja.gif
similarity index 100%
rename from build/media_source/mod_languages/images/ja.gif
rename to media_source/mod_languages/images/ja.gif
diff --git a/build/media_source/mod_languages/images/ja_jp.gif b/media_source/mod_languages/images/ja_jp.gif
similarity index 100%
rename from build/media_source/mod_languages/images/ja_jp.gif
rename to media_source/mod_languages/images/ja_jp.gif
diff --git a/build/media_source/mod_languages/images/ka.gif b/media_source/mod_languages/images/ka.gif
similarity index 100%
rename from build/media_source/mod_languages/images/ka.gif
rename to media_source/mod_languages/images/ka.gif
diff --git a/build/media_source/mod_languages/images/ka_ge.gif b/media_source/mod_languages/images/ka_ge.gif
similarity index 100%
rename from build/media_source/mod_languages/images/ka_ge.gif
rename to media_source/mod_languages/images/ka_ge.gif
diff --git a/build/media_source/mod_languages/images/kk_kz.gif b/media_source/mod_languages/images/kk_kz.gif
similarity index 100%
rename from build/media_source/mod_languages/images/kk_kz.gif
rename to media_source/mod_languages/images/kk_kz.gif
diff --git a/build/media_source/mod_languages/images/km.gif b/media_source/mod_languages/images/km.gif
similarity index 100%
rename from build/media_source/mod_languages/images/km.gif
rename to media_source/mod_languages/images/km.gif
diff --git a/build/media_source/mod_languages/images/km_kh.gif b/media_source/mod_languages/images/km_kh.gif
similarity index 100%
rename from build/media_source/mod_languages/images/km_kh.gif
rename to media_source/mod_languages/images/km_kh.gif
diff --git a/build/media_source/mod_languages/images/ko.gif b/media_source/mod_languages/images/ko.gif
similarity index 100%
rename from build/media_source/mod_languages/images/ko.gif
rename to media_source/mod_languages/images/ko.gif
diff --git a/build/media_source/mod_languages/images/ko_kr.gif b/media_source/mod_languages/images/ko_kr.gif
similarity index 100%
rename from build/media_source/mod_languages/images/ko_kr.gif
rename to media_source/mod_languages/images/ko_kr.gif
diff --git a/build/media_source/mod_languages/images/ku.gif b/media_source/mod_languages/images/ku.gif
similarity index 100%
rename from build/media_source/mod_languages/images/ku.gif
rename to media_source/mod_languages/images/ku.gif
diff --git a/build/media_source/mod_languages/images/lo.gif b/media_source/mod_languages/images/lo.gif
similarity index 100%
rename from build/media_source/mod_languages/images/lo.gif
rename to media_source/mod_languages/images/lo.gif
diff --git a/build/media_source/mod_languages/images/lo_la.gif b/media_source/mod_languages/images/lo_la.gif
similarity index 100%
rename from build/media_source/mod_languages/images/lo_la.gif
rename to media_source/mod_languages/images/lo_la.gif
diff --git a/build/media_source/mod_languages/images/lt.gif b/media_source/mod_languages/images/lt.gif
similarity index 100%
rename from build/media_source/mod_languages/images/lt.gif
rename to media_source/mod_languages/images/lt.gif
diff --git a/build/media_source/mod_languages/images/lt_lt.gif b/media_source/mod_languages/images/lt_lt.gif
similarity index 100%
rename from build/media_source/mod_languages/images/lt_lt.gif
rename to media_source/mod_languages/images/lt_lt.gif
diff --git a/build/media_source/mod_languages/images/lv.gif b/media_source/mod_languages/images/lv.gif
similarity index 100%
rename from build/media_source/mod_languages/images/lv.gif
rename to media_source/mod_languages/images/lv.gif
diff --git a/build/media_source/mod_languages/images/lv_lv.gif b/media_source/mod_languages/images/lv_lv.gif
similarity index 100%
rename from build/media_source/mod_languages/images/lv_lv.gif
rename to media_source/mod_languages/images/lv_lv.gif
diff --git a/build/media_source/mod_languages/images/mk.gif b/media_source/mod_languages/images/mk.gif
similarity index 100%
rename from build/media_source/mod_languages/images/mk.gif
rename to media_source/mod_languages/images/mk.gif
diff --git a/build/media_source/mod_languages/images/mk_mk.gif b/media_source/mod_languages/images/mk_mk.gif
similarity index 100%
rename from build/media_source/mod_languages/images/mk_mk.gif
rename to media_source/mod_languages/images/mk_mk.gif
diff --git a/build/media_source/mod_languages/images/mn.gif b/media_source/mod_languages/images/mn.gif
similarity index 100%
rename from build/media_source/mod_languages/images/mn.gif
rename to media_source/mod_languages/images/mn.gif
diff --git a/build/media_source/mod_languages/images/mn_mn.gif b/media_source/mod_languages/images/mn_mn.gif
similarity index 100%
rename from build/media_source/mod_languages/images/mn_mn.gif
rename to media_source/mod_languages/images/mn_mn.gif
diff --git a/build/media_source/mod_languages/images/ms_my.gif b/media_source/mod_languages/images/ms_my.gif
similarity index 100%
rename from build/media_source/mod_languages/images/ms_my.gif
rename to media_source/mod_languages/images/ms_my.gif
diff --git a/build/media_source/mod_languages/images/nb_no.gif b/media_source/mod_languages/images/nb_no.gif
similarity index 100%
rename from build/media_source/mod_languages/images/nb_no.gif
rename to media_source/mod_languages/images/nb_no.gif
diff --git a/build/media_source/mod_languages/images/nl.gif b/media_source/mod_languages/images/nl.gif
similarity index 100%
rename from build/media_source/mod_languages/images/nl.gif
rename to media_source/mod_languages/images/nl.gif
diff --git a/build/media_source/mod_languages/images/nl_be.gif b/media_source/mod_languages/images/nl_be.gif
similarity index 100%
rename from build/media_source/mod_languages/images/nl_be.gif
rename to media_source/mod_languages/images/nl_be.gif
diff --git a/build/media_source/mod_languages/images/nl_nl.gif b/media_source/mod_languages/images/nl_nl.gif
similarity index 100%
rename from build/media_source/mod_languages/images/nl_nl.gif
rename to media_source/mod_languages/images/nl_nl.gif
diff --git a/build/media_source/mod_languages/images/nn_no.gif b/media_source/mod_languages/images/nn_no.gif
similarity index 100%
rename from build/media_source/mod_languages/images/nn_no.gif
rename to media_source/mod_languages/images/nn_no.gif
diff --git a/build/media_source/mod_languages/images/no.gif b/media_source/mod_languages/images/no.gif
similarity index 100%
rename from build/media_source/mod_languages/images/no.gif
rename to media_source/mod_languages/images/no.gif
diff --git a/build/media_source/mod_languages/images/pl.gif b/media_source/mod_languages/images/pl.gif
similarity index 100%
rename from build/media_source/mod_languages/images/pl.gif
rename to media_source/mod_languages/images/pl.gif
diff --git a/build/media_source/mod_languages/images/pl_pl.gif b/media_source/mod_languages/images/pl_pl.gif
similarity index 100%
rename from build/media_source/mod_languages/images/pl_pl.gif
rename to media_source/mod_languages/images/pl_pl.gif
diff --git a/build/media_source/mod_languages/images/prs_af.gif b/media_source/mod_languages/images/prs_af.gif
similarity index 100%
rename from build/media_source/mod_languages/images/prs_af.gif
rename to media_source/mod_languages/images/prs_af.gif
diff --git a/build/media_source/mod_languages/images/ps.gif b/media_source/mod_languages/images/ps.gif
similarity index 100%
rename from build/media_source/mod_languages/images/ps.gif
rename to media_source/mod_languages/images/ps.gif
diff --git a/build/media_source/mod_languages/images/ps_af.gif b/media_source/mod_languages/images/ps_af.gif
similarity index 100%
rename from build/media_source/mod_languages/images/ps_af.gif
rename to media_source/mod_languages/images/ps_af.gif
diff --git a/build/media_source/mod_languages/images/pt.gif b/media_source/mod_languages/images/pt.gif
similarity index 100%
rename from build/media_source/mod_languages/images/pt.gif
rename to media_source/mod_languages/images/pt.gif
diff --git a/build/media_source/mod_languages/images/pt_br.gif b/media_source/mod_languages/images/pt_br.gif
similarity index 100%
rename from build/media_source/mod_languages/images/pt_br.gif
rename to media_source/mod_languages/images/pt_br.gif
diff --git a/build/media_source/mod_languages/images/pt_pt.gif b/media_source/mod_languages/images/pt_pt.gif
similarity index 100%
rename from build/media_source/mod_languages/images/pt_pt.gif
rename to media_source/mod_languages/images/pt_pt.gif
diff --git a/build/media_source/mod_languages/images/ro.gif b/media_source/mod_languages/images/ro.gif
similarity index 100%
rename from build/media_source/mod_languages/images/ro.gif
rename to media_source/mod_languages/images/ro.gif
diff --git a/build/media_source/mod_languages/images/ro_ro.gif b/media_source/mod_languages/images/ro_ro.gif
similarity index 100%
rename from build/media_source/mod_languages/images/ro_ro.gif
rename to media_source/mod_languages/images/ro_ro.gif
diff --git a/build/media_source/mod_languages/images/ru.gif b/media_source/mod_languages/images/ru.gif
similarity index 100%
rename from build/media_source/mod_languages/images/ru.gif
rename to media_source/mod_languages/images/ru.gif
diff --git a/build/media_source/mod_languages/images/ru_ru.gif b/media_source/mod_languages/images/ru_ru.gif
similarity index 100%
rename from build/media_source/mod_languages/images/ru_ru.gif
rename to media_source/mod_languages/images/ru_ru.gif
diff --git a/build/media_source/mod_languages/images/si.gif b/media_source/mod_languages/images/si.gif
similarity index 100%
rename from build/media_source/mod_languages/images/si.gif
rename to media_source/mod_languages/images/si.gif
diff --git a/build/media_source/mod_languages/images/si_lk.gif b/media_source/mod_languages/images/si_lk.gif
similarity index 100%
rename from build/media_source/mod_languages/images/si_lk.gif
rename to media_source/mod_languages/images/si_lk.gif
diff --git a/build/media_source/mod_languages/images/sk.gif b/media_source/mod_languages/images/sk.gif
similarity index 100%
rename from build/media_source/mod_languages/images/sk.gif
rename to media_source/mod_languages/images/sk.gif
diff --git a/build/media_source/mod_languages/images/sk_sk.gif b/media_source/mod_languages/images/sk_sk.gif
similarity index 100%
rename from build/media_source/mod_languages/images/sk_sk.gif
rename to media_source/mod_languages/images/sk_sk.gif
diff --git a/build/media_source/mod_languages/images/sl.gif b/media_source/mod_languages/images/sl.gif
similarity index 100%
rename from build/media_source/mod_languages/images/sl.gif
rename to media_source/mod_languages/images/sl.gif
diff --git a/build/media_source/mod_languages/images/sl_si.gif b/media_source/mod_languages/images/sl_si.gif
similarity index 100%
rename from build/media_source/mod_languages/images/sl_si.gif
rename to media_source/mod_languages/images/sl_si.gif
diff --git a/build/media_source/mod_languages/images/sq_al.gif b/media_source/mod_languages/images/sq_al.gif
similarity index 100%
rename from build/media_source/mod_languages/images/sq_al.gif
rename to media_source/mod_languages/images/sq_al.gif
diff --git a/build/media_source/mod_languages/images/sr.gif b/media_source/mod_languages/images/sr.gif
similarity index 100%
rename from build/media_source/mod_languages/images/sr.gif
rename to media_source/mod_languages/images/sr.gif
diff --git a/build/media_source/mod_languages/images/sr_rs.gif b/media_source/mod_languages/images/sr_rs.gif
similarity index 100%
rename from build/media_source/mod_languages/images/sr_rs.gif
rename to media_source/mod_languages/images/sr_rs.gif
diff --git a/build/media_source/mod_languages/images/sr_yu.gif b/media_source/mod_languages/images/sr_yu.gif
similarity index 100%
rename from build/media_source/mod_languages/images/sr_yu.gif
rename to media_source/mod_languages/images/sr_yu.gif
diff --git a/build/media_source/mod_languages/images/srp_me.gif b/media_source/mod_languages/images/srp_me.gif
similarity index 100%
rename from build/media_source/mod_languages/images/srp_me.gif
rename to media_source/mod_languages/images/srp_me.gif
diff --git a/build/media_source/mod_languages/images/sv.gif b/media_source/mod_languages/images/sv.gif
similarity index 100%
rename from build/media_source/mod_languages/images/sv.gif
rename to media_source/mod_languages/images/sv.gif
diff --git a/build/media_source/mod_languages/images/sv_se.gif b/media_source/mod_languages/images/sv_se.gif
similarity index 100%
rename from build/media_source/mod_languages/images/sv_se.gif
rename to media_source/mod_languages/images/sv_se.gif
diff --git a/build/media_source/mod_languages/images/sw.gif b/media_source/mod_languages/images/sw.gif
similarity index 100%
rename from build/media_source/mod_languages/images/sw.gif
rename to media_source/mod_languages/images/sw.gif
diff --git a/build/media_source/mod_languages/images/sw_ke.gif b/media_source/mod_languages/images/sw_ke.gif
similarity index 100%
rename from build/media_source/mod_languages/images/sw_ke.gif
rename to media_source/mod_languages/images/sw_ke.gif
diff --git a/build/media_source/mod_languages/images/sy.gif b/media_source/mod_languages/images/sy.gif
similarity index 100%
rename from build/media_source/mod_languages/images/sy.gif
rename to media_source/mod_languages/images/sy.gif
diff --git a/build/media_source/mod_languages/images/sy_iq.gif b/media_source/mod_languages/images/sy_iq.gif
similarity index 100%
rename from build/media_source/mod_languages/images/sy_iq.gif
rename to media_source/mod_languages/images/sy_iq.gif
diff --git a/build/media_source/mod_languages/images/ta.gif b/media_source/mod_languages/images/ta.gif
similarity index 100%
rename from build/media_source/mod_languages/images/ta.gif
rename to media_source/mod_languages/images/ta.gif
diff --git a/build/media_source/mod_languages/images/ta_in.gif b/media_source/mod_languages/images/ta_in.gif
similarity index 100%
rename from build/media_source/mod_languages/images/ta_in.gif
rename to media_source/mod_languages/images/ta_in.gif
diff --git a/build/media_source/mod_languages/images/th.gif b/media_source/mod_languages/images/th.gif
similarity index 100%
rename from build/media_source/mod_languages/images/th.gif
rename to media_source/mod_languages/images/th.gif
diff --git a/build/media_source/mod_languages/images/th_th.gif b/media_source/mod_languages/images/th_th.gif
similarity index 100%
rename from build/media_source/mod_languages/images/th_th.gif
rename to media_source/mod_languages/images/th_th.gif
diff --git a/build/media_source/mod_languages/images/tk_tm.gif b/media_source/mod_languages/images/tk_tm.gif
similarity index 100%
rename from build/media_source/mod_languages/images/tk_tm.gif
rename to media_source/mod_languages/images/tk_tm.gif
diff --git a/build/media_source/mod_languages/images/tr.gif b/media_source/mod_languages/images/tr.gif
similarity index 100%
rename from build/media_source/mod_languages/images/tr.gif
rename to media_source/mod_languages/images/tr.gif
diff --git a/build/media_source/mod_languages/images/tr_tr.gif b/media_source/mod_languages/images/tr_tr.gif
similarity index 100%
rename from build/media_source/mod_languages/images/tr_tr.gif
rename to media_source/mod_languages/images/tr_tr.gif
diff --git a/build/media_source/mod_languages/images/tw.gif b/media_source/mod_languages/images/tw.gif
similarity index 100%
rename from build/media_source/mod_languages/images/tw.gif
rename to media_source/mod_languages/images/tw.gif
diff --git a/build/media_source/mod_languages/images/ug_cn.gif b/media_source/mod_languages/images/ug_cn.gif
similarity index 100%
rename from build/media_source/mod_languages/images/ug_cn.gif
rename to media_source/mod_languages/images/ug_cn.gif
diff --git a/build/media_source/mod_languages/images/uk.gif b/media_source/mod_languages/images/uk.gif
similarity index 100%
rename from build/media_source/mod_languages/images/uk.gif
rename to media_source/mod_languages/images/uk.gif
diff --git a/build/media_source/mod_languages/images/uk_ua.gif b/media_source/mod_languages/images/uk_ua.gif
similarity index 100%
rename from build/media_source/mod_languages/images/uk_ua.gif
rename to media_source/mod_languages/images/uk_ua.gif
diff --git a/build/media_source/mod_languages/images/ur.gif b/media_source/mod_languages/images/ur.gif
similarity index 100%
rename from build/media_source/mod_languages/images/ur.gif
rename to media_source/mod_languages/images/ur.gif
diff --git a/build/media_source/mod_languages/images/ur_pk.gif b/media_source/mod_languages/images/ur_pk.gif
similarity index 100%
rename from build/media_source/mod_languages/images/ur_pk.gif
rename to media_source/mod_languages/images/ur_pk.gif
diff --git a/build/media_source/mod_languages/images/us.gif b/media_source/mod_languages/images/us.gif
similarity index 100%
rename from build/media_source/mod_languages/images/us.gif
rename to media_source/mod_languages/images/us.gif
diff --git a/build/media_source/mod_languages/images/uz.gif b/media_source/mod_languages/images/uz.gif
similarity index 100%
rename from build/media_source/mod_languages/images/uz.gif
rename to media_source/mod_languages/images/uz.gif
diff --git a/build/media_source/mod_languages/images/uz_uz.gif b/media_source/mod_languages/images/uz_uz.gif
similarity index 100%
rename from build/media_source/mod_languages/images/uz_uz.gif
rename to media_source/mod_languages/images/uz_uz.gif
diff --git a/build/media_source/mod_languages/images/vi.gif b/media_source/mod_languages/images/vi.gif
similarity index 100%
rename from build/media_source/mod_languages/images/vi.gif
rename to media_source/mod_languages/images/vi.gif
diff --git a/build/media_source/mod_languages/images/vi_vn.gif b/media_source/mod_languages/images/vi_vn.gif
similarity index 100%
rename from build/media_source/mod_languages/images/vi_vn.gif
rename to media_source/mod_languages/images/vi_vn.gif
diff --git a/build/media_source/mod_languages/images/zh.gif b/media_source/mod_languages/images/zh.gif
similarity index 100%
rename from build/media_source/mod_languages/images/zh.gif
rename to media_source/mod_languages/images/zh.gif
diff --git a/build/media_source/mod_languages/images/zh_cn.gif b/media_source/mod_languages/images/zh_cn.gif
similarity index 100%
rename from build/media_source/mod_languages/images/zh_cn.gif
rename to media_source/mod_languages/images/zh_cn.gif
diff --git a/build/media_source/mod_languages/images/zh_tw.gif b/media_source/mod_languages/images/zh_tw.gif
similarity index 100%
rename from build/media_source/mod_languages/images/zh_tw.gif
rename to media_source/mod_languages/images/zh_tw.gif
diff --git a/build/media_source/mod_login/js/admin-login.es6.js b/media_source/mod_login/js/admin-login.es6.js
similarity index 100%
rename from build/media_source/mod_login/js/admin-login.es6.js
rename to media_source/mod_login/js/admin-login.es6.js
diff --git a/build/media_source/mod_menu/css/mod-menu.css b/media_source/mod_menu/css/mod-menu.css
similarity index 100%
rename from build/media_source/mod_menu/css/mod-menu.css
rename to media_source/mod_menu/css/mod-menu.css
diff --git a/build/media_source/mod_menu/joomla.asset.json b/media_source/mod_menu/joomla.asset.json
similarity index 100%
rename from build/media_source/mod_menu/joomla.asset.json
rename to media_source/mod_menu/joomla.asset.json
diff --git a/build/media_source/mod_menu/js/admin-menu.es6.js b/media_source/mod_menu/js/admin-menu.es6.js
similarity index 100%
rename from build/media_source/mod_menu/js/admin-menu.es6.js
rename to media_source/mod_menu/js/admin-menu.es6.js
diff --git a/build/media_source/mod_menu/js/menu.es6.js b/media_source/mod_menu/js/menu.es6.js
similarity index 100%
rename from build/media_source/mod_menu/js/menu.es6.js
rename to media_source/mod_menu/js/menu.es6.js
diff --git a/build/media_source/mod_quickicon/js/quickicon.es6.js b/media_source/mod_quickicon/js/quickicon.es6.js
similarity index 100%
rename from build/media_source/mod_quickicon/js/quickicon.es6.js
rename to media_source/mod_quickicon/js/quickicon.es6.js
diff --git a/build/media_source/mod_sampledata/js/sampledata-process.es6.js b/media_source/mod_sampledata/js/sampledata-process.es6.js
similarity index 100%
rename from build/media_source/mod_sampledata/js/sampledata-process.es6.js
rename to media_source/mod_sampledata/js/sampledata-process.es6.js
diff --git a/build/media_source/plg_behaviour_compat6/removed.asset.json b/media_source/plg_behaviour_compat6/removed.asset.json
similarity index 100%
rename from build/media_source/plg_behaviour_compat6/removed.asset.json
rename to media_source/plg_behaviour_compat6/removed.asset.json
diff --git a/build/media_source/plg_content_vote/css/rating.css b/media_source/plg_content_vote/css/rating.css
similarity index 100%
rename from build/media_source/plg_content_vote/css/rating.css
rename to media_source/plg_content_vote/css/rating.css
diff --git a/build/media_source/plg_content_vote/images/vote-star-half.svg b/media_source/plg_content_vote/images/vote-star-half.svg
similarity index 100%
rename from build/media_source/plg_content_vote/images/vote-star-half.svg
rename to media_source/plg_content_vote/images/vote-star-half.svg
diff --git a/build/media_source/plg_content_vote/images/vote-star.svg b/media_source/plg_content_vote/images/vote-star.svg
similarity index 100%
rename from build/media_source/plg_content_vote/images/vote-star.svg
rename to media_source/plg_content_vote/images/vote-star.svg
diff --git a/build/media_source/plg_editors-xtd_image/js/button-image.es6.js b/media_source/plg_editors-xtd_image/js/button-image.es6.js
similarity index 100%
rename from build/media_source/plg_editors-xtd_image/js/button-image.es6.js
rename to media_source/plg_editors-xtd_image/js/button-image.es6.js
diff --git a/media_source/plg_editors_codemirror/builder.mjs b/media_source/plg_editors_codemirror/builder.mjs
new file mode 100644
index 00000000000..3872c085efe
--- /dev/null
+++ b/media_source/plg_editors_codemirror/builder.mjs
@@ -0,0 +1,123 @@
+/**
+ * Assets Builder
+ */
+
+import path from 'node:path';
+import fsp from "node:fs/promises";
+import fs from "node:fs";
+import { createRequire } from 'node:module';
+import DefaultModuleBuilder from '../../build/build-modules-js/builder/default-module-builder.mjs';
+import { resolvePackageFile, getPackagesUnderScope } from '../../build/build-modules-js/utils/resolve-package.mjs';
+import { handleMJSFile } from '../../build/build-modules-js/javascript/js-handle.mjs';
+
+/**
+ * Update joomla.asset.json for codemirror
+ *
+ * @param { [['module', 'path']] } modules
+ * @param { string[] }externalModules
+ * @param { string } basePath
+ * @param { string } targetPath
+ * @return {Promise}
+ */
+const updateAssetRegistry = async (modules, externalModules, basePath, targetPath) => {
+ const srcPath = path.join(basePath, 'joomla.asset.json');
+ const destPath = path.join(targetPath, 'joomla.asset.json');
+ const require = createRequire(import.meta.url);
+
+ // Get base JSON and update
+ const registry = JSON.parse(fs.readFileSync(srcPath, { encoding: 'utf8' }));
+
+ // Add dependencies to base codemirror asset
+ registry.assets.forEach((asset) => {
+ if (asset.name === 'codemirror' && asset.type === 'script') {
+ asset.dependencies = externalModules;
+ }
+ });
+
+ // Create asset for each module
+ modules.forEach(([module, modulePath]) => {
+ const modulePathJson = resolvePackageFile(path.join(module, 'package.json'));
+ const moduleOptions = require(modulePathJson);
+ const asset = {
+ type: 'script',
+ name: module,
+ uri: modulePath.replace('.js', '.min.js'),
+ importmap: true,
+ version: moduleOptions.version,
+ };
+
+ registry.assets.push(asset);
+ });
+
+ // Write assets registry
+ return fsp.writeFile(destPath, JSON.stringify(registry, null, 2), { encoding: 'utf8', mode: 0o644 });
+};
+
+/**
+ * Copy/Prepare Codemirror modules
+ * @param { string } basePath
+ * @param { string } targetPath
+ * @return {Promise}
+ */
+const compileCodemirror = async (basePath, targetPath) => {
+ const cmModules = getPackagesUnderScope('@codemirror');
+ const lModules = getPackagesUnderScope('@lezer');
+ const externalModules = [...cmModules, ...lModules];
+ const destBasePath = 'media/vendor/codemirror/js';
+ const tasks = [];
+ const modules = [];
+
+ // Collect @codemirror modules
+ cmModules.forEach((module) => {
+ const destFile = `${module.replace('@codemirror/', 'codemirror-')}.js`;
+ const destPath = path.join(destBasePath, destFile);
+
+ modules.push([module, destPath]);
+ });
+
+ // Collect @lezer modules which @codemirror depends on
+ lModules.forEach((module) => {
+ const destFile = `${module.replace('@lezer/', 'lezer-')}.js`;
+ const destPath = path.join(destBasePath, destFile);
+
+ modules.push([module, destPath]);
+ });
+
+ // Copy/Compile the modules
+ modules.forEach(([ module, destPath ]) => {
+ tasks.push(handleMJSFile(module, destPath));
+ });
+
+ return Promise.all(tasks).then(() => {
+ return updateAssetRegistry(modules, externalModules, basePath, targetPath);
+ });
+};
+
+export default class CodemirrorModuleBuilder extends DefaultModuleBuilder
+{
+ /**
+ * Remove files associated with the builder
+ * @returns { Promise }
+ */
+ async clear() {
+ await super.clear();
+
+ const vendorPath = 'media/vendor/codemirror';
+
+ if (!fs.existsSync(vendorPath)) {
+ return;
+ }
+
+ return fsp.rm(vendorPath, { recursive: true });
+ }
+
+ /**
+ * Process JavaScript files and Modules
+ * @returns { Promise }
+ */
+ async js() {
+ await super.js();
+
+ return compileCodemirror(this.basePath, this.targetPath);
+ }
+};
diff --git a/build/media_source/plg_editors_codemirror/css/codemirror.css b/media_source/plg_editors_codemirror/css/codemirror.css
similarity index 100%
rename from build/media_source/plg_editors_codemirror/css/codemirror.css
rename to media_source/plg_editors_codemirror/css/codemirror.css
diff --git a/build/media_source/plg_editors_codemirror/joomla.asset.json b/media_source/plg_editors_codemirror/joomla.asset.json
similarity index 100%
rename from build/media_source/plg_editors_codemirror/joomla.asset.json
rename to media_source/plg_editors_codemirror/joomla.asset.json
diff --git a/build/media_source/plg_editors_codemirror/js/codemirror.es6.js b/media_source/plg_editors_codemirror/js/codemirror.es6.js
similarity index 100%
rename from build/media_source/plg_editors_codemirror/js/codemirror.es6.js
rename to media_source/plg_editors_codemirror/js/codemirror.es6.js
diff --git a/build/media_source/plg_editors_codemirror/js/joomla-editor-codemirror.w-c.es6.js b/media_source/plg_editors_codemirror/js/joomla-editor-codemirror.w-c.es6.js
similarity index 100%
rename from build/media_source/plg_editors_codemirror/js/joomla-editor-codemirror.w-c.es6.js
rename to media_source/plg_editors_codemirror/js/joomla-editor-codemirror.w-c.es6.js
diff --git a/build/media_source/plg_editors_none/js/joomla-editor-none.w-c.es6.js b/media_source/plg_editors_none/js/joomla-editor-none.w-c.es6.js
similarity index 100%
rename from build/media_source/plg_editors_none/js/joomla-editor-none.w-c.es6.js
rename to media_source/plg_editors_none/js/joomla-editor-none.w-c.es6.js
diff --git a/media_source/plg_editors_tinymce/builder.mjs b/media_source/plg_editors_tinymce/builder.mjs
new file mode 100644
index 00000000000..adaab1cbee4
--- /dev/null
+++ b/media_source/plg_editors_tinymce/builder.mjs
@@ -0,0 +1,92 @@
+/**
+ * Assets Builder
+ */
+
+import path from 'node:path';
+import fsp from "node:fs/promises";
+import fs from "node:fs";
+import DefaultModuleBuilder from '../../build/build-modules-js/builder/default-module-builder.mjs';
+import { resolvePackageFile } from '../../build/build-modules-js/utils/resolve-package.mjs';
+
+
+export default class TinyMCEModuleBuilder extends DefaultModuleBuilder
+{
+ /**
+ * Copy files to target location.
+ *
+ * @returns { Promise }
+ */
+ async copy() {
+ await super.copy();
+
+ const rootPath = process.cwd();
+ const modulePathJson = resolvePackageFile(path.join('tinymce', 'package.json'));
+ const moduleLngPathJson = resolvePackageFile(path.join('tinymce-i18n', 'package.json'));
+
+ // This should never happen
+ if (!modulePathJson || !moduleLngPathJson) {
+ throw new Error(`Modules source for "tinymce" or for "tinymce-i18n" not found`);
+ }
+
+ const tinySrcPath = path.dirname(modulePathJson);
+ const tinyVendorPath = path.join(path.dirname(this.targetPath), 'vendor', 'tinymce');
+ const moduleOptions = await import(modulePathJson, { with: { type: 'json' } });
+ const version = moduleOptions.default.version;
+ const majorVersion = version.split('.')[0];
+ const tinyLngSrcPath = path.join(path.dirname(moduleLngPathJson), `langs${majorVersion}`);
+
+ // Copy vendor content
+ const promises = [];
+ const filterFunc = (src, dest) => {
+ return path.basename(src) !== 'index.js';
+ };
+
+ [
+ 'icons',
+ 'plugins',
+ 'skins',
+ 'themes',
+ 'models',
+ 'tinymce.js',
+ 'tinymce.min.js',
+ 'CHANGELOG.md',
+ 'license.md',
+ ].forEach((folder) => {
+ promises.push(fsp.cp(
+ path.join(tinySrcPath, folder),
+ path.join(tinyVendorPath, folder),
+ { preserveTimestamps: true, recursive: true, filter: filterFunc }
+ ));
+ });
+
+ // Copy translation files
+ if (fs.existsSync(tinyLngSrcPath)) {
+ promises.push(fsp.cp(
+ tinyLngSrcPath,
+ path.join(tinyVendorPath, 'langs'),
+ { preserveTimestamps: true, recursive: true }
+ ));
+ }
+
+ // Update the XML file for tinyMCE
+ const xmlVersionStr = /()(.+)(<\/version>)/;
+ const xmlPath = path.join(rootPath, '/plugins/editors/tinymce/tinymce.xml');
+ const xmlPromise = fsp.readFile(xmlPath).then((srcContent) => {
+ const content = srcContent.toString().replace(xmlVersionStr, `$1${version}$3`);
+ return fsp.writeFile(xmlPath, content, { encoding: 'utf8', mode: 0o644 });
+ });
+ promises.push(xmlPromise);
+
+ // Copy Joomla template snippets which is in vendor folder
+ // @TODO: the templates should be under plugin folder for better consistency?
+ const tmplSrcPath = path.join(path.dirname(this.basePath), 'vendor', 'tinymce', 'templates');
+ const tmplTargetPath = path.join(tinyVendorPath, 'templates');
+ promises.push(fsp.cp(
+ tmplSrcPath,
+ tmplTargetPath,
+ { preserveTimestamps: true, recursive: true }
+ ));
+
+ return Promise.all(promises);
+ }
+};
diff --git a/build/media_source/plg_editors_tinymce/joomla.asset.json b/media_source/plg_editors_tinymce/joomla.asset.json
similarity index 100%
rename from build/media_source/plg_editors_tinymce/joomla.asset.json
rename to media_source/plg_editors_tinymce/joomla.asset.json
diff --git a/build/media_source/plg_editors_tinymce/js/plugins/abbr/plugin.es6.js b/media_source/plg_editors_tinymce/js/plugins/abbr/plugin.es6.js
similarity index 100%
rename from build/media_source/plg_editors_tinymce/js/plugins/abbr/plugin.es6.js
rename to media_source/plg_editors_tinymce/js/plugins/abbr/plugin.es6.js
diff --git a/build/media_source/plg_editors_tinymce/js/plugins/dragdrop/plugin.es6.js b/media_source/plg_editors_tinymce/js/plugins/dragdrop/plugin.es6.js
similarity index 100%
rename from build/media_source/plg_editors_tinymce/js/plugins/dragdrop/plugin.es6.js
rename to media_source/plg_editors_tinymce/js/plugins/dragdrop/plugin.es6.js
diff --git a/build/media_source/plg_editors_tinymce/js/plugins/joomla-highlighter/plugin.es6.js b/media_source/plg_editors_tinymce/js/plugins/joomla-highlighter/plugin.es6.js
similarity index 100%
rename from build/media_source/plg_editors_tinymce/js/plugins/joomla-highlighter/plugin.es6.js
rename to media_source/plg_editors_tinymce/js/plugins/joomla-highlighter/plugin.es6.js
diff --git a/build/media_source/plg_editors_tinymce/js/plugins/jtemplate/plugin.es5.js b/media_source/plg_editors_tinymce/js/plugins/jtemplate/plugin.es5.js
similarity index 100%
rename from build/media_source/plg_editors_tinymce/js/plugins/jtemplate/plugin.es5.js
rename to media_source/plg_editors_tinymce/js/plugins/jtemplate/plugin.es5.js
diff --git a/build/media_source/plg_editors_tinymce/js/plugins/jxtdbuttons/plugin.es6.js b/media_source/plg_editors_tinymce/js/plugins/jxtdbuttons/plugin.es6.js
similarity index 100%
rename from build/media_source/plg_editors_tinymce/js/plugins/jxtdbuttons/plugin.es6.js
rename to media_source/plg_editors_tinymce/js/plugins/jxtdbuttons/plugin.es6.js
diff --git a/build/media_source/plg_editors_tinymce/js/tinymce-builder.es6.js b/media_source/plg_editors_tinymce/js/tinymce-builder.es6.js
similarity index 100%
rename from build/media_source/plg_editors_tinymce/js/tinymce-builder.es6.js
rename to media_source/plg_editors_tinymce/js/tinymce-builder.es6.js
diff --git a/build/media_source/plg_editors_tinymce/js/tinymce.es6.js b/media_source/plg_editors_tinymce/js/tinymce.es6.js
similarity index 100%
rename from build/media_source/plg_editors_tinymce/js/tinymce.es6.js
rename to media_source/plg_editors_tinymce/js/tinymce.es6.js
diff --git a/build/media_source/plg_editors_tinymce/scss/tinymce-builder.scss b/media_source/plg_editors_tinymce/scss/tinymce-builder.scss
similarity index 100%
rename from build/media_source/plg_editors_tinymce/scss/tinymce-builder.scss
rename to media_source/plg_editors_tinymce/scss/tinymce-builder.scss
diff --git a/build/media_source/plg_installer_folderinstaller/js/folderinstaller.es6.js b/media_source/plg_installer_folderinstaller/js/folderinstaller.es6.js
similarity index 100%
rename from build/media_source/plg_installer_folderinstaller/js/folderinstaller.es6.js
rename to media_source/plg_installer_folderinstaller/js/folderinstaller.es6.js
diff --git a/build/media_source/plg_installer_packageinstaller/js/packageinstaller.es6.js b/media_source/plg_installer_packageinstaller/js/packageinstaller.es6.js
similarity index 100%
rename from build/media_source/plg_installer_packageinstaller/js/packageinstaller.es6.js
rename to media_source/plg_installer_packageinstaller/js/packageinstaller.es6.js
diff --git a/build/media_source/plg_installer_urlinstaller/js/urlinstaller.es6.js b/media_source/plg_installer_urlinstaller/js/urlinstaller.es6.js
similarity index 100%
rename from build/media_source/plg_installer_urlinstaller/js/urlinstaller.es6.js
rename to media_source/plg_installer_urlinstaller/js/urlinstaller.es6.js
diff --git a/build/media_source/plg_installer_webinstaller/js/client.es6.js b/media_source/plg_installer_webinstaller/js/client.es6.js
similarity index 100%
rename from build/media_source/plg_installer_webinstaller/js/client.es6.js
rename to media_source/plg_installer_webinstaller/js/client.es6.js
diff --git a/build/media_source/plg_installer_webinstaller/scss/client.scss b/media_source/plg_installer_webinstaller/scss/client.scss
similarity index 94%
rename from build/media_source/plg_installer_webinstaller/scss/client.scss
rename to media_source/plg_installer_webinstaller/scss/client.scss
index bcccf58dd69..45fca4515ae 100644
--- a/build/media_source/plg_installer_webinstaller/scss/client.scss
+++ b/media_source/plg_installer_webinstaller/scss/client.scss
@@ -1,9 +1,9 @@
// Bootstrap functions
-@import "../../../../media/vendor/bootstrap/scss/functions";
+@import "../../../media/vendor/bootstrap/scss/functions";
// Bootstrap other
-@import "../../../../media/vendor/bootstrap/scss/mixins";
-@import "../../../../media/vendor/bootstrap/scss/variables";
+@import "../../../media/vendor/bootstrap/scss/mixins";
+@import "../../../media/vendor/bootstrap/scss/variables";
// Extension variables
$extension-types: (
diff --git a/build/media_source/plg_media-action_crop/js/crop.es6.js b/media_source/plg_media-action_crop/js/crop.es6.js
similarity index 100%
rename from build/media_source/plg_media-action_crop/js/crop.es6.js
rename to media_source/plg_media-action_crop/js/crop.es6.js
diff --git a/build/media_source/plg_media-action_resize/js/resize.es6.js b/media_source/plg_media-action_resize/js/resize.es6.js
similarity index 100%
rename from build/media_source/plg_media-action_resize/js/resize.es6.js
rename to media_source/plg_media-action_resize/js/resize.es6.js
diff --git a/build/media_source/plg_media-action_rotate/js/rotate.es6.js b/media_source/plg_media-action_rotate/js/rotate.es6.js
similarity index 95%
rename from build/media_source/plg_media-action_rotate/js/rotate.es6.js
rename to media_source/plg_media-action_rotate/js/rotate.es6.js
index f5a2871c69c..e4640b08f57 100644
--- a/build/media_source/plg_media-action_rotate/js/rotate.es6.js
+++ b/media_source/plg_media-action_rotate/js/rotate.es6.js
@@ -58,9 +58,14 @@ const initRotate = (image) => {
if (!activated) {
// The number input listener
document.getElementById('jform_rotate_a').addEventListener('change', ({ target }) => {
- rotate(parseInt(target.value, 10), image);
+ const angle = parseInt(target.value, 10);
+
+ if (Number.isNaN(angle)) {
+ return;
+ }
+
+ rotate(angle, image);
- target.value = 0;
// Deselect all buttons
document.querySelectorAll('#jform_rotate_distinct label').forEach((element) => element.classList.remove('active', 'focus'));
});
diff --git a/build/media_source/plg_multifactorauth_email/images/email.svg b/media_source/plg_multifactorauth_email/images/email.svg
similarity index 100%
rename from build/media_source/plg_multifactorauth_email/images/email.svg
rename to media_source/plg_multifactorauth_email/images/email.svg
diff --git a/build/media_source/plg_multifactorauth_fixed/images/fixed.svg b/media_source/plg_multifactorauth_fixed/images/fixed.svg
similarity index 100%
rename from build/media_source/plg_multifactorauth_fixed/images/fixed.svg
rename to media_source/plg_multifactorauth_fixed/images/fixed.svg
diff --git a/build/media_source/plg_multifactorauth_totp/images/totp.svg b/media_source/plg_multifactorauth_totp/images/totp.svg
similarity index 100%
rename from build/media_source/plg_multifactorauth_totp/images/totp.svg
rename to media_source/plg_multifactorauth_totp/images/totp.svg
diff --git a/build/media_source/plg_multifactorauth_totp/joomla.asset.json b/media_source/plg_multifactorauth_totp/joomla.asset.json
similarity index 100%
rename from build/media_source/plg_multifactorauth_totp/joomla.asset.json
rename to media_source/plg_multifactorauth_totp/joomla.asset.json
diff --git a/build/media_source/plg_multifactorauth_totp/js/setup.es6.js b/media_source/plg_multifactorauth_totp/js/setup.es6.js
similarity index 100%
rename from build/media_source/plg_multifactorauth_totp/js/setup.es6.js
rename to media_source/plg_multifactorauth_totp/js/setup.es6.js
diff --git a/build/media_source/plg_multifactorauth_webauthn/images/passkeys.svg b/media_source/plg_multifactorauth_webauthn/images/passkeys.svg
similarity index 100%
rename from build/media_source/plg_multifactorauth_webauthn/images/passkeys.svg
rename to media_source/plg_multifactorauth_webauthn/images/passkeys.svg
diff --git a/build/media_source/plg_multifactorauth_webauthn/images/webauthn.svg b/media_source/plg_multifactorauth_webauthn/images/webauthn.svg
similarity index 100%
rename from build/media_source/plg_multifactorauth_webauthn/images/webauthn.svg
rename to media_source/plg_multifactorauth_webauthn/images/webauthn.svg
diff --git a/build/media_source/plg_multifactorauth_webauthn/joomla.asset.json b/media_source/plg_multifactorauth_webauthn/joomla.asset.json
similarity index 100%
rename from build/media_source/plg_multifactorauth_webauthn/joomla.asset.json
rename to media_source/plg_multifactorauth_webauthn/joomla.asset.json
diff --git a/build/media_source/plg_multifactorauth_webauthn/js/webauthn.es6.js b/media_source/plg_multifactorauth_webauthn/js/webauthn.es6.js
similarity index 100%
rename from build/media_source/plg_multifactorauth_webauthn/js/webauthn.es6.js
rename to media_source/plg_multifactorauth_webauthn/js/webauthn.es6.js
diff --git a/build/media_source/plg_multifactorauth_yubikey/images/yubikey.svg b/media_source/plg_multifactorauth_yubikey/images/yubikey.svg
similarity index 100%
rename from build/media_source/plg_multifactorauth_yubikey/images/yubikey.svg
rename to media_source/plg_multifactorauth_yubikey/images/yubikey.svg
diff --git a/build/media_source/plg_quickicon_autoupdate/js/healthcheck.es6.js b/media_source/plg_quickicon_autoupdate/js/healthcheck.es6.js
similarity index 100%
rename from build/media_source/plg_quickicon_autoupdate/js/healthcheck.es6.js
rename to media_source/plg_quickicon_autoupdate/js/healthcheck.es6.js
diff --git a/build/media_source/plg_quickicon_eos/js/snooze.es6.js b/media_source/plg_quickicon_eos/js/snooze.es6.js
similarity index 100%
rename from build/media_source/plg_quickicon_eos/js/snooze.es6.js
rename to media_source/plg_quickicon_eos/js/snooze.es6.js
diff --git a/build/media_source/plg_quickicon_extensionupdate/js/extensionupdatecheck.es6.js b/media_source/plg_quickicon_extensionupdate/js/extensionupdatecheck.es6.js
similarity index 100%
rename from build/media_source/plg_quickicon_extensionupdate/js/extensionupdatecheck.es6.js
rename to media_source/plg_quickicon_extensionupdate/js/extensionupdatecheck.es6.js
diff --git a/build/media_source/plg_quickicon_joomlaupdate/js/jupdatecheck.es6.js b/media_source/plg_quickicon_joomlaupdate/js/jupdatecheck.es6.js
similarity index 100%
rename from build/media_source/plg_quickicon_joomlaupdate/js/jupdatecheck.es6.js
rename to media_source/plg_quickicon_joomlaupdate/js/jupdatecheck.es6.js
diff --git a/build/media_source/plg_quickicon_overridecheck/js/overridecheck.es6.js b/media_source/plg_quickicon_overridecheck/js/overridecheck.es6.js
similarity index 100%
rename from build/media_source/plg_quickicon_overridecheck/js/overridecheck.es6.js
rename to media_source/plg_quickicon_overridecheck/js/overridecheck.es6.js
diff --git a/build/media_source/plg_quickicon_privacycheck/js/privacycheck.es6.js b/media_source/plg_quickicon_privacycheck/js/privacycheck.es6.js
similarity index 100%
rename from build/media_source/plg_quickicon_privacycheck/js/privacycheck.es6.js
rename to media_source/plg_quickicon_privacycheck/js/privacycheck.es6.js
diff --git a/media_source/plg_system_debug/builder.mjs b/media_source/plg_system_debug/builder.mjs
new file mode 100644
index 00000000000..4573e55499d
--- /dev/null
+++ b/media_source/plg_system_debug/builder.mjs
@@ -0,0 +1,97 @@
+/**
+ * Assets Builder
+ */
+import path from 'node:path';
+import fsp from "node:fs/promises";
+import fs from "node:fs";
+import DefaultModuleBuilder from '../../build/build-modules-js/builder/default-module-builder.mjs';
+
+export default class PlgDebugModuleBuilder extends DefaultModuleBuilder
+{
+ /**
+ * Target location for vendor files of the debugbar
+ * @type {string}
+ */
+ vendorLocation = 'vendor/debugbar';
+
+ /**
+ * Remove files
+ * @returns { Promise }
+ */
+ async clear() {
+ await super.clear();
+
+ const pathMedia = path.dirname(this.targetPath);
+ const pathVendor = path.join(pathMedia, this.vendorLocation);
+
+ if (!fs.existsSync(pathVendor)) {
+ return;
+ }
+
+ return fsp.rm(pathVendor, { recursive: true });
+ }
+
+ /**
+ * Copy files to target location.
+ *
+ * @returns { Promise }
+ */
+ async copy() {
+ await super.copy();
+
+ // Copy DebugBar assets to vendor folder
+ const pathSrc = 'libraries/vendor/php-debugbar/php-debugbar/src/DebugBar/Resources';
+ const pathMedia = path.dirname(this.targetPath);
+ const pathVendor = path.join(pathMedia, this.vendorLocation);
+
+ if (!fs.existsSync(pathSrc)) {
+ throw new Error('DebugBar/Resources not found. Make sure you have run "composer install" first.')
+ }
+
+ return fsp.cp(pathSrc, pathVendor, { recursive: true, preserveTimestamps: true }).then(() => {
+ // Remove unused
+ return Promise.all([
+ fsp.rm(path.join(pathVendor, 'vendor/font-awesome'), { recursive: true }),
+ fsp.rm(path.join(pathVendor, 'vendor/jquery'), { recursive: true }),
+ ]);
+ });
+ }
+
+ /**
+ * Process CSS files
+ * @returns { Promise }
+ */
+ async css() {
+ await super.css();
+
+ // Run default css builder for vendor files
+ const pathMedia = path.dirname(this.targetPath);
+ const builder = new DefaultModuleBuilder(
+ this.vendorLocation,
+ pathMedia,
+ pathMedia,
+ this.options
+ );
+
+ return builder.css();
+ }
+
+ /**
+ * Process JavaScript files and Modules
+ * @returns { Promise }
+ */
+ async js() {
+ await super.js();
+
+ // Run default js builder for vendor files
+ const pathMedia = path.dirname(this.targetPath);
+ const builder = new DefaultModuleBuilder(
+ this.vendorLocation,
+ pathMedia,
+ pathMedia,
+ this.options
+ );
+
+ return builder.js();
+ }
+};
diff --git a/build/media_source/plg_system_debug/css/debug.css b/media_source/plg_system_debug/css/debug.css
similarity index 100%
rename from build/media_source/plg_system_debug/css/debug.css
rename to media_source/plg_system_debug/css/debug.css
diff --git a/build/media_source/plg_system_debug/js/debug.es6.js b/media_source/plg_system_debug/js/debug.es6.js
similarity index 100%
rename from build/media_source/plg_system_debug/js/debug.es6.js
rename to media_source/plg_system_debug/js/debug.es6.js
diff --git a/build/media_source/plg_system_debug/widgets/info/widget.css b/media_source/plg_system_debug/widgets/info/widget.css
similarity index 100%
rename from build/media_source/plg_system_debug/widgets/info/widget.css
rename to media_source/plg_system_debug/widgets/info/widget.css
diff --git a/build/media_source/plg_system_debug/widgets/info/widget.es5.js b/media_source/plg_system_debug/widgets/info/widget.es5.js
similarity index 100%
rename from build/media_source/plg_system_debug/widgets/info/widget.es5.js
rename to media_source/plg_system_debug/widgets/info/widget.es5.js
diff --git a/build/media_source/plg_system_debug/widgets/languageErrors/widget.css b/media_source/plg_system_debug/widgets/languageErrors/widget.css
similarity index 100%
rename from build/media_source/plg_system_debug/widgets/languageErrors/widget.css
rename to media_source/plg_system_debug/widgets/languageErrors/widget.css
diff --git a/build/media_source/plg_system_debug/widgets/languageErrors/widget.es5.js b/media_source/plg_system_debug/widgets/languageErrors/widget.es5.js
similarity index 100%
rename from build/media_source/plg_system_debug/widgets/languageErrors/widget.es5.js
rename to media_source/plg_system_debug/widgets/languageErrors/widget.es5.js
diff --git a/build/media_source/plg_system_debug/widgets/languageFiles/widget.css b/media_source/plg_system_debug/widgets/languageFiles/widget.css
similarity index 100%
rename from build/media_source/plg_system_debug/widgets/languageFiles/widget.css
rename to media_source/plg_system_debug/widgets/languageFiles/widget.css
diff --git a/build/media_source/plg_system_debug/widgets/languageFiles/widget.es5.js b/media_source/plg_system_debug/widgets/languageFiles/widget.es5.js
similarity index 100%
rename from build/media_source/plg_system_debug/widgets/languageFiles/widget.es5.js
rename to media_source/plg_system_debug/widgets/languageFiles/widget.es5.js
diff --git a/build/media_source/plg_system_debug/widgets/languageStrings/widget.css b/media_source/plg_system_debug/widgets/languageStrings/widget.css
similarity index 100%
rename from build/media_source/plg_system_debug/widgets/languageStrings/widget.css
rename to media_source/plg_system_debug/widgets/languageStrings/widget.css
diff --git a/build/media_source/plg_system_debug/widgets/languageStrings/widget.es5.js b/media_source/plg_system_debug/widgets/languageStrings/widget.es5.js
similarity index 100%
rename from build/media_source/plg_system_debug/widgets/languageStrings/widget.es5.js
rename to media_source/plg_system_debug/widgets/languageStrings/widget.es5.js
diff --git a/build/media_source/plg_system_debug/widgets/sqlqueries/widget.css b/media_source/plg_system_debug/widgets/sqlqueries/widget.css
similarity index 100%
rename from build/media_source/plg_system_debug/widgets/sqlqueries/widget.css
rename to media_source/plg_system_debug/widgets/sqlqueries/widget.css
diff --git a/build/media_source/plg_system_debug/widgets/sqlqueries/widget.es5.js b/media_source/plg_system_debug/widgets/sqlqueries/widget.es5.js
similarity index 100%
rename from build/media_source/plg_system_debug/widgets/sqlqueries/widget.es5.js
rename to media_source/plg_system_debug/widgets/sqlqueries/widget.es5.js
diff --git a/build/media_source/plg_system_guidedtours/joomla.asset.json b/media_source/plg_system_guidedtours/joomla.asset.json
similarity index 100%
rename from build/media_source/plg_system_guidedtours/joomla.asset.json
rename to media_source/plg_system_guidedtours/joomla.asset.json
diff --git a/build/media_source/plg_system_guidedtours/js/guidedtours.es6.js b/media_source/plg_system_guidedtours/js/guidedtours.es6.js
similarity index 100%
rename from build/media_source/plg_system_guidedtours/js/guidedtours.es6.js
rename to media_source/plg_system_guidedtours/js/guidedtours.es6.js
diff --git a/build/media_source/plg_system_guidedtours/scss/guidedtours.scss b/media_source/plg_system_guidedtours/scss/guidedtours.scss
similarity index 97%
rename from build/media_source/plg_system_guidedtours/scss/guidedtours.scss
rename to media_source/plg_system_guidedtours/scss/guidedtours.scss
index e4b2bfa87b0..9b276889371 100644
--- a/build/media_source/plg_system_guidedtours/scss/guidedtours.scss
+++ b/media_source/plg_system_guidedtours/scss/guidedtours.scss
@@ -3,7 +3,7 @@
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
-@import "../../../../node_modules/shepherd.js/dist/css/shepherd";
+@import "../../../node_modules/shepherd.js/dist/css/shepherd";
.shepherd-target.shepherd-enabled {
z-index: 9998;
diff --git a/build/media_source/plg_system_jooa11y/joomla.asset.json b/media_source/plg_system_jooa11y/joomla.asset.json
similarity index 100%
rename from build/media_source/plg_system_jooa11y/joomla.asset.json
rename to media_source/plg_system_jooa11y/joomla.asset.json
diff --git a/build/media_source/plg_system_jooa11y/js/jooa11y.es6.js b/media_source/plg_system_jooa11y/js/jooa11y.es6.js
similarity index 100%
rename from build/media_source/plg_system_jooa11y/js/jooa11y.es6.js
rename to media_source/plg_system_jooa11y/js/jooa11y.es6.js
diff --git a/build/media_source/plg_system_schedulerunner/joomla.asset.json b/media_source/plg_system_schedulerunner/joomla.asset.json
similarity index 100%
rename from build/media_source/plg_system_schedulerunner/joomla.asset.json
rename to media_source/plg_system_schedulerunner/joomla.asset.json
diff --git a/build/media_source/plg_system_schedulerunner/js/run-schedule.es6.js b/media_source/plg_system_schedulerunner/js/run-schedule.es6.js
similarity index 100%
rename from build/media_source/plg_system_schedulerunner/js/run-schedule.es6.js
rename to media_source/plg_system_schedulerunner/js/run-schedule.es6.js
diff --git a/build/media_source/plg_system_shortcut/js/shortcut.es6.js b/media_source/plg_system_shortcut/js/shortcut.es6.js
similarity index 100%
rename from build/media_source/plg_system_shortcut/js/shortcut.es6.js
rename to media_source/plg_system_shortcut/js/shortcut.es6.js
diff --git a/build/media_source/plg_system_stats/js/stats-message.es6.js b/media_source/plg_system_stats/js/stats-message.es6.js
similarity index 100%
rename from build/media_source/plg_system_stats/js/stats-message.es6.js
rename to media_source/plg_system_stats/js/stats-message.es6.js
diff --git a/build/media_source/plg_system_stats/js/stats.es6.js b/media_source/plg_system_stats/js/stats.es6.js
similarity index 100%
rename from build/media_source/plg_system_stats/js/stats.es6.js
rename to media_source/plg_system_stats/js/stats.es6.js
diff --git a/build/media_source/plg_system_webauthn/images/fido-passkey-black.svg b/media_source/plg_system_webauthn/images/fido-passkey-black.svg
similarity index 100%
rename from build/media_source/plg_system_webauthn/images/fido-passkey-black.svg
rename to media_source/plg_system_webauthn/images/fido-passkey-black.svg
diff --git a/build/media_source/plg_system_webauthn/images/fido.png b/media_source/plg_system_webauthn/images/fido.png
similarity index 100%
rename from build/media_source/plg_system_webauthn/images/fido.png
rename to media_source/plg_system_webauthn/images/fido.png
diff --git a/build/media_source/plg_system_webauthn/images/webauthn.svg b/media_source/plg_system_webauthn/images/webauthn.svg
similarity index 100%
rename from build/media_source/plg_system_webauthn/images/webauthn.svg
rename to media_source/plg_system_webauthn/images/webauthn.svg
diff --git a/build/media_source/plg_system_webauthn/js/login.es6.js b/media_source/plg_system_webauthn/js/login.es6.js
similarity index 100%
rename from build/media_source/plg_system_webauthn/js/login.es6.js
rename to media_source/plg_system_webauthn/js/login.es6.js
diff --git a/build/media_source/plg_system_webauthn/js/management.es6.js b/media_source/plg_system_webauthn/js/management.es6.js
similarity index 100%
rename from build/media_source/plg_system_webauthn/js/management.es6.js
rename to media_source/plg_system_webauthn/js/management.es6.js
diff --git a/build/media_source/plg_system_webauthn/scss/button.scss b/media_source/plg_system_webauthn/scss/button.scss
similarity index 100%
rename from build/media_source/plg_system_webauthn/scss/button.scss
rename to media_source/plg_system_webauthn/scss/button.scss
diff --git a/build/media_source/plg_user_token/js/token.es6.js b/media_source/plg_user_token/js/token.es6.js
similarity index 100%
rename from build/media_source/plg_user_token/js/token.es6.js
rename to media_source/plg_user_token/js/token.es6.js
diff --git a/build/media_source/system/css/fields/calendar.css b/media_source/system/css/fields/calendar.css
similarity index 100%
rename from build/media_source/system/css/fields/calendar.css
rename to media_source/system/css/fields/calendar.css
diff --git a/build/media_source/system/css/fields/joomla-media-select.css b/media_source/system/css/fields/joomla-media-select.css
similarity index 100%
rename from build/media_source/system/css/fields/joomla-media-select.css
rename to media_source/system/css/fields/joomla-media-select.css
diff --git a/build/media_source/system/images/ajax-loader.gif b/media_source/system/images/ajax-loader.gif
similarity index 100%
rename from build/media_source/system/images/ajax-loader.gif
rename to media_source/system/images/ajax-loader.gif
diff --git a/build/media_source/system/images/calendar-select-bg-dark-rtl.svg b/media_source/system/images/calendar-select-bg-dark-rtl.svg
similarity index 100%
rename from build/media_source/system/images/calendar-select-bg-dark-rtl.svg
rename to media_source/system/images/calendar-select-bg-dark-rtl.svg
diff --git a/build/media_source/system/images/calendar-select-bg-dark.svg b/media_source/system/images/calendar-select-bg-dark.svg
similarity index 100%
rename from build/media_source/system/images/calendar-select-bg-dark.svg
rename to media_source/system/images/calendar-select-bg-dark.svg
diff --git a/build/media_source/system/images/calendar.png b/media_source/system/images/calendar.png
similarity index 100%
rename from build/media_source/system/images/calendar.png
rename to media_source/system/images/calendar.png
diff --git a/build/media_source/system/images/favicon.ico b/media_source/system/images/favicon.ico
similarity index 100%
rename from build/media_source/system/images/favicon.ico
rename to media_source/system/images/favicon.ico
diff --git a/build/media_source/system/images/joomla-favicon-pinned.svg b/media_source/system/images/joomla-favicon-pinned.svg
similarity index 100%
rename from build/media_source/system/images/joomla-favicon-pinned.svg
rename to media_source/system/images/joomla-favicon-pinned.svg
diff --git a/build/media_source/system/images/joomla-favicon.svg b/media_source/system/images/joomla-favicon.svg
similarity index 100%
rename from build/media_source/system/images/joomla-favicon.svg
rename to media_source/system/images/joomla-favicon.svg
diff --git a/build/media_source/system/images/joomla-loader.svg b/media_source/system/images/joomla-loader.svg
similarity index 100%
rename from build/media_source/system/images/joomla-loader.svg
rename to media_source/system/images/joomla-loader.svg
diff --git a/build/media_source/system/images/select-bg-dark.svg b/media_source/system/images/select-bg-dark.svg
similarity index 100%
rename from build/media_source/system/images/select-bg-dark.svg
rename to media_source/system/images/select-bg-dark.svg
diff --git a/build/media_source/templates/administrator/atum/images/select-bg-rtl.svg b/media_source/system/images/select-bg-rtl.svg
similarity index 100%
rename from build/media_source/templates/administrator/atum/images/select-bg-rtl.svg
rename to media_source/system/images/select-bg-rtl.svg
diff --git a/build/media_source/templates/administrator/atum/images/select-bg.svg b/media_source/system/images/select-bg.svg
similarity index 100%
rename from build/media_source/templates/administrator/atum/images/select-bg.svg
rename to media_source/system/images/select-bg.svg
diff --git a/build/media_source/system/images/template_thumb.svg b/media_source/system/images/template_thumb.svg
similarity index 99%
rename from build/media_source/system/images/template_thumb.svg
rename to media_source/system/images/template_thumb.svg
index 80f936b80b8..f2e0ebc7a24 100644
--- a/build/media_source/system/images/template_thumb.svg
+++ b/media_source/system/images/template_thumb.svg
@@ -1,5 +1,5 @@
-
-
-
-
-
+
+
+
+
+
diff --git a/build/media_source/system/joomla.asset.json b/media_source/system/joomla.asset.json
similarity index 100%
rename from build/media_source/system/joomla.asset.json
rename to media_source/system/joomla.asset.json
diff --git a/build/media_source/system/js/core.es6.js b/media_source/system/js/core.es6.js
similarity index 100%
rename from build/media_source/system/js/core.es6.js
rename to media_source/system/js/core.es6.js
diff --git a/build/media_source/system/js/draggable.es6.js b/media_source/system/js/draggable.es6.js
similarity index 100%
rename from build/media_source/system/js/draggable.es6.js
rename to media_source/system/js/draggable.es6.js
diff --git a/build/media_source/system/js/editors/editor-api.es6.js b/media_source/system/js/editors/editor-api.es6.js
similarity index 100%
rename from build/media_source/system/js/editors/editor-api.es6.js
rename to media_source/system/js/editors/editor-api.es6.js
diff --git a/build/media_source/system/js/editors/editor-decorator.es6.js b/media_source/system/js/editors/editor-decorator.es6.js
similarity index 100%
rename from build/media_source/system/js/editors/editor-decorator.es6.js
rename to media_source/system/js/editors/editor-decorator.es6.js
diff --git a/build/media_source/system/js/editors/editors.es6.js b/media_source/system/js/editors/editors.es6.js
similarity index 100%
rename from build/media_source/system/js/editors/editors.es6.js
rename to media_source/system/js/editors/editors.es6.js
diff --git a/build/media_source/system/js/fields/calendar-locales/date/gregorian/date-helper.es5.js b/media_source/system/js/fields/calendar-locales/date/gregorian/date-helper.es5.js
similarity index 100%
rename from build/media_source/system/js/fields/calendar-locales/date/gregorian/date-helper.es5.js
rename to media_source/system/js/fields/calendar-locales/date/gregorian/date-helper.es5.js
diff --git a/build/media_source/system/js/fields/calendar-locales/date/jalali/date-helper.es5.js b/media_source/system/js/fields/calendar-locales/date/jalali/date-helper.es5.js
similarity index 100%
rename from build/media_source/system/js/fields/calendar-locales/date/jalali/date-helper.es5.js
rename to media_source/system/js/fields/calendar-locales/date/jalali/date-helper.es5.js
diff --git a/build/media_source/system/js/fields/calendar.es5.js b/media_source/system/js/fields/calendar.es5.js
similarity index 100%
rename from build/media_source/system/js/fields/calendar.es5.js
rename to media_source/system/js/fields/calendar.es5.js
diff --git a/build/media_source/system/js/fields/color-field-adv-init.es5.js b/media_source/system/js/fields/color-field-adv-init.es5.js
similarity index 100%
rename from build/media_source/system/js/fields/color-field-adv-init.es5.js
rename to media_source/system/js/fields/color-field-adv-init.es5.js
diff --git a/build/media_source/system/js/fields/joomla-field-color-slider.es6.js b/media_source/system/js/fields/joomla-field-color-slider.es6.js
similarity index 100%
rename from build/media_source/system/js/fields/joomla-field-color-slider.es6.js
rename to media_source/system/js/fields/joomla-field-color-slider.es6.js
diff --git a/build/media_source/system/js/fields/joomla-field-fancy-select.w-c.es6.js b/media_source/system/js/fields/joomla-field-fancy-select.w-c.es6.js
similarity index 98%
rename from build/media_source/system/js/fields/joomla-field-fancy-select.w-c.es6.js
rename to media_source/system/js/fields/joomla-field-fancy-select.w-c.es6.js
index 36973a9b0af..16cf1be52c4 100644
--- a/build/media_source/system/js/fields/joomla-field-fancy-select.w-c.es6.js
+++ b/media_source/system/js/fields/joomla-field-fancy-select.w-c.es6.js
@@ -244,8 +244,10 @@ window.customElements.define('joomla-field-fancy-select', class extends HTMLElem
// Handle remote search
if (this.remoteSearch && this.url) {
// Cache existing
- this.choicesInstance.config.choices.forEach((choiceItem) => {
- this.choicesCache[choiceItem.value] = choiceItem.label;
+ this.choicesInstance.passedElement.optionsAsChoices().forEach((choiceItem) => {
+ if (choiceItem.value !== undefined) {
+ this.choicesCache[choiceItem.value] = choiceItem.label;
+ }
});
const lookupDelay = 300;
diff --git a/build/media_source/system/js/fields/joomla-field-media.w-c.es6.js b/media_source/system/js/fields/joomla-field-media.w-c.es6.js
similarity index 97%
rename from build/media_source/system/js/fields/joomla-field-media.w-c.es6.js
rename to media_source/system/js/fields/joomla-field-media.w-c.es6.js
index 5e2f5c6080e..75240307983 100644
--- a/build/media_source/system/js/fields/joomla-field-media.w-c.es6.js
+++ b/media_source/system/js/fields/joomla-field-media.w-c.es6.js
@@ -95,6 +95,7 @@ class JoomlaFieldMedia extends HTMLElement {
this.button = this.querySelector(this.buttonSelect);
this.inputElement = this.querySelector(this.input);
this.buttonClearEl = this.querySelector(this.buttonClear);
+ this.inputGroup = this.querySelector('.input-group');
this.previewElement = this.querySelector('.field-media-preview');
if (!this.button || !this.inputElement || !this.buttonClearEl) {
@@ -308,11 +309,15 @@ class JoomlaFieldMedia extends HTMLElement {
const { value } = this.inputElement;
const { supportedExtensions } = this;
if (!value) {
- this.buttonClearEl.style.display = 'none';
+ if (this.buttonClearEl.parentElement) {
+ this.buttonClearEl.remove();
+ }
this.previewElement.innerHTML = Joomla.sanitizeHtml(' ');
} else {
let type;
- this.buttonClearEl.style.display = '';
+ if (!this.buttonClearEl.parentElement && this.inputGroup) {
+ this.inputGroup.appendChild(this.buttonClearEl);
+ }
this.previewElement.innerHTML = '';
const ext = getExtension(value).toLowerCase();
diff --git a/build/media_source/system/js/fields/joomla-field-module-order.w-c.es6.js b/media_source/system/js/fields/joomla-field-module-order.w-c.es6.js
similarity index 100%
rename from build/media_source/system/js/fields/joomla-field-module-order.w-c.es6.js
rename to media_source/system/js/fields/joomla-field-module-order.w-c.es6.js
diff --git a/build/media_source/system/js/fields/joomla-field-permissions.w-c.es6.js b/media_source/system/js/fields/joomla-field-permissions.w-c.es6.js
similarity index 100%
rename from build/media_source/system/js/fields/joomla-field-permissions.w-c.es6.js
rename to media_source/system/js/fields/joomla-field-permissions.w-c.es6.js
diff --git a/build/media_source/system/js/fields/joomla-field-send-test-mail.w-c.es6.js b/media_source/system/js/fields/joomla-field-send-test-mail.w-c.es6.js
similarity index 100%
rename from build/media_source/system/js/fields/joomla-field-send-test-mail.w-c.es6.js
rename to media_source/system/js/fields/joomla-field-send-test-mail.w-c.es6.js
diff --git a/build/media_source/system/js/fields/joomla-field-simple-color.w-c.es6.js b/media_source/system/js/fields/joomla-field-simple-color.w-c.es6.js
similarity index 100%
rename from build/media_source/system/js/fields/joomla-field-simple-color.w-c.es6.js
rename to media_source/system/js/fields/joomla-field-simple-color.w-c.es6.js
diff --git a/build/media_source/system/js/fields/joomla-field-subform.w-c.es6.js b/media_source/system/js/fields/joomla-field-subform.w-c.es6.js
similarity index 100%
rename from build/media_source/system/js/fields/joomla-field-subform.w-c.es6.js
rename to media_source/system/js/fields/joomla-field-subform.w-c.es6.js
diff --git a/build/media_source/system/js/fields/joomla-field-user.w-c.es6.js b/media_source/system/js/fields/joomla-field-user.w-c.es6.js
similarity index 100%
rename from build/media_source/system/js/fields/joomla-field-user.w-c.es6.js
rename to media_source/system/js/fields/joomla-field-user.w-c.es6.js
diff --git a/build/media_source/system/js/fields/joomla-media-select.w-c.es6.js b/media_source/system/js/fields/joomla-media-select.w-c.es6.js
similarity index 100%
rename from build/media_source/system/js/fields/joomla-media-select.w-c.es6.js
rename to media_source/system/js/fields/joomla-media-select.w-c.es6.js
diff --git a/build/media_source/system/js/fields/modal-content-select-field.es6.js b/media_source/system/js/fields/modal-content-select-field.es6.js
similarity index 100%
rename from build/media_source/system/js/fields/modal-content-select-field.es6.js
rename to media_source/system/js/fields/modal-content-select-field.es6.js
diff --git a/build/media_source/system/js/fields/modal-fields.es5.js b/media_source/system/js/fields/modal-fields.es5.js
similarity index 100%
rename from build/media_source/system/js/fields/modal-fields.es5.js
rename to media_source/system/js/fields/modal-fields.es5.js
diff --git a/build/media_source/system/js/fields/passwordstrength.es6.js b/media_source/system/js/fields/passwordstrength.es6.js
similarity index 100%
rename from build/media_source/system/js/fields/passwordstrength.es6.js
rename to media_source/system/js/fields/passwordstrength.es6.js
diff --git a/build/media_source/system/js/fields/passwordview.es6.js b/media_source/system/js/fields/passwordview.es6.js
similarity index 100%
rename from build/media_source/system/js/fields/passwordview.es6.js
rename to media_source/system/js/fields/passwordview.es6.js
diff --git a/build/media_source/system/js/fields/select-colour.es6.js b/media_source/system/js/fields/select-colour.es6.js
similarity index 100%
rename from build/media_source/system/js/fields/select-colour.es6.js
rename to media_source/system/js/fields/select-colour.es6.js
diff --git a/build/media_source/system/js/fields/validate.es6.js b/media_source/system/js/fields/validate.es6.js
similarity index 100%
rename from build/media_source/system/js/fields/validate.es6.js
rename to media_source/system/js/fields/validate.es6.js
diff --git a/build/media_source/system/js/highlight.es6.js b/media_source/system/js/highlight.es6.js
similarity index 100%
rename from build/media_source/system/js/highlight.es6.js
rename to media_source/system/js/highlight.es6.js
diff --git a/build/media_source/system/js/inlinehelp.es6.js b/media_source/system/js/inlinehelp.es6.js
similarity index 100%
rename from build/media_source/system/js/inlinehelp.es6.js
rename to media_source/system/js/inlinehelp.es6.js
diff --git a/build/media_source/system/js/joomla-core-loader.w-c.es6.js b/media_source/system/js/joomla-core-loader.w-c.es6.js
similarity index 100%
rename from build/media_source/system/js/joomla-core-loader.w-c.es6.js
rename to media_source/system/js/joomla-core-loader.w-c.es6.js
diff --git a/build/media_source/system/js/joomla-dialog-autocreate.es6.js b/media_source/system/js/joomla-dialog-autocreate.es6.js
similarity index 100%
rename from build/media_source/system/js/joomla-dialog-autocreate.es6.js
rename to media_source/system/js/joomla-dialog-autocreate.es6.js
diff --git a/build/media_source/system/js/joomla-dialog.w-c.es6.js b/media_source/system/js/joomla-dialog.w-c.es6.js
similarity index 100%
rename from build/media_source/system/js/joomla-dialog.w-c.es6.js
rename to media_source/system/js/joomla-dialog.w-c.es6.js
diff --git a/build/media_source/system/js/joomla-hidden-mail.w-c.es6.js b/media_source/system/js/joomla-hidden-mail.w-c.es6.js
similarity index 100%
rename from build/media_source/system/js/joomla-hidden-mail.w-c.es6.js
rename to media_source/system/js/joomla-hidden-mail.w-c.es6.js
diff --git a/build/media_source/system/js/joomla-toolbar-button.w-c.es6.js b/media_source/system/js/joomla-toolbar-button.w-c.es6.js
similarity index 100%
rename from build/media_source/system/js/joomla-toolbar-button.w-c.es6.js
rename to media_source/system/js/joomla-toolbar-button.w-c.es6.js
diff --git a/build/media_source/system/js/keepalive.es6.js b/media_source/system/js/keepalive.es6.js
similarity index 100%
rename from build/media_source/system/js/keepalive.es6.js
rename to media_source/system/js/keepalive.es6.js
diff --git a/build/media_source/system/js/list-view.es6.js b/media_source/system/js/list-view.es6.js
similarity index 100%
rename from build/media_source/system/js/list-view.es6.js
rename to media_source/system/js/list-view.es6.js
diff --git a/build/media_source/system/js/messages.es6.js b/media_source/system/js/messages.es6.js
similarity index 100%
rename from build/media_source/system/js/messages.es6.js
rename to media_source/system/js/messages.es6.js
diff --git a/build/media_source/system/js/modal-content-select.es6.js b/media_source/system/js/modal-content-select.es6.js
similarity index 100%
rename from build/media_source/system/js/modal-content-select.es6.js
rename to media_source/system/js/modal-content-select.es6.js
diff --git a/build/media_source/system/js/multiselect.es6.js b/media_source/system/js/multiselect.es6.js
similarity index 100%
rename from build/media_source/system/js/multiselect.es6.js
rename to media_source/system/js/multiselect.es6.js
diff --git a/build/media_source/system/js/searchtools.es6.js b/media_source/system/js/searchtools.es6.js
similarity index 100%
rename from build/media_source/system/js/searchtools.es6.js
rename to media_source/system/js/searchtools.es6.js
diff --git a/build/media_source/system/js/showon.es6.js b/media_source/system/js/showon.es6.js
similarity index 100%
rename from build/media_source/system/js/showon.es6.js
rename to media_source/system/js/showon.es6.js
diff --git a/build/media_source/system/js/table-columns.es6.js b/media_source/system/js/table-columns.es6.js
similarity index 100%
rename from build/media_source/system/js/table-columns.es6.js
rename to media_source/system/js/table-columns.es6.js
diff --git a/build/media_source/system/js/treeselectmenu.es6.js b/media_source/system/js/treeselectmenu.es6.js
similarity index 100%
rename from build/media_source/system/js/treeselectmenu.es6.js
rename to media_source/system/js/treeselectmenu.es6.js
diff --git a/build/media_source/system/scss/_icomoon.scss b/media_source/system/scss/_icomoon.scss
similarity index 100%
rename from build/media_source/system/scss/_icomoon.scss
rename to media_source/system/scss/_icomoon.scss
diff --git a/build/media_source/system/scss/_jquery-minicolors.scss b/media_source/system/scss/_jquery-minicolors.scss
similarity index 100%
rename from build/media_source/system/scss/_jquery-minicolors.scss
rename to media_source/system/scss/_jquery-minicolors.scss
diff --git a/build/media_source/system/scss/editor.scss b/media_source/system/scss/editor.scss
similarity index 100%
rename from build/media_source/system/scss/editor.scss
rename to media_source/system/scss/editor.scss
diff --git a/build/media_source/system/scss/fields/joomla-field-media.scss b/media_source/system/scss/fields/joomla-field-media.scss
similarity index 86%
rename from build/media_source/system/scss/fields/joomla-field-media.scss
rename to media_source/system/scss/fields/joomla-field-media.scss
index c8f6b051ea9..271cef598b3 100644
--- a/build/media_source/system/scss/fields/joomla-field-media.scss
+++ b/media_source/system/scss/fields/joomla-field-media.scss
@@ -21,10 +21,17 @@ joomla-field-media .field-media-preview-icon {
joomla-field-media .field-media-input {
border-top-left-radius: 0;
+ border-start-start-radius: 0;
+}
+
+joomla-field-media .input-group > .btn.btn-success.button-select {
+ border-top-right-radius: 0;
+ border-start-end-radius: 0;
}
joomla-field-media .button-clear {
border-top-right-radius: 0;
+ border-start-end-radius: 0;
}
joomla-field-media img {
diff --git a/build/media_source/system/scss/fields/joomla-field-permissions.scss b/media_source/system/scss/fields/joomla-field-permissions.scss
similarity index 100%
rename from build/media_source/system/scss/fields/joomla-field-permissions.scss
rename to media_source/system/scss/fields/joomla-field-permissions.scss
diff --git a/build/media_source/system/scss/fields/joomla-field-simple-color.scss b/media_source/system/scss/fields/joomla-field-simple-color.scss
similarity index 100%
rename from build/media_source/system/scss/fields/joomla-field-simple-color.scss
rename to media_source/system/scss/fields/joomla-field-simple-color.scss
diff --git a/build/media_source/system/scss/fields/switcher.scss b/media_source/system/scss/fields/switcher.scss
similarity index 100%
rename from build/media_source/system/scss/fields/switcher.scss
rename to media_source/system/scss/fields/switcher.scss
diff --git a/media_source/system/scss/joomla-fontawesome.scss b/media_source/system/scss/joomla-fontawesome.scss
new file mode 100644
index 00000000000..e16a9631c3f
--- /dev/null
+++ b/media_source/system/scss/joomla-fontawesome.scss
@@ -0,0 +1,17 @@
+// Override the font path
+$fa-font-path: "../../../media/vendor/fontawesome-free/webfonts" !default;
+$fa-font-display: block !default;
+
+// Font Awesome 6 Free
+@import "../../../media/vendor/fontawesome-free/scss/fontawesome";
+@import "../../../media/vendor/fontawesome-free/scss/regular";
+@import "../../../media/vendor/fontawesome-free/scss/solid";
+
+// Brands must be imported last
+@import "../../../media/vendor/fontawesome-free/scss/brands";
+
+// B/C with Font Awesome 5
+@import "../../../media/vendor/fontawesome-free/scss/shims";
+
+// B/C for Icomoon
+@import "icomoon";
diff --git a/build/media_source/system/scss/joomla-toolbar-button.scss b/media_source/system/scss/joomla-toolbar-button.scss
similarity index 100%
rename from build/media_source/system/scss/joomla-toolbar-button.scss
rename to media_source/system/scss/joomla-toolbar-button.scss
diff --git a/build/media_source/system/scss/system-admin-error.scss b/media_source/system/scss/system-admin-error.scss
similarity index 100%
rename from build/media_source/system/scss/system-admin-error.scss
rename to media_source/system/scss/system-admin-error.scss
diff --git a/build/media_source/system/scss/system-admin-system.scss b/media_source/system/scss/system-admin-system.scss
similarity index 100%
rename from build/media_source/system/scss/system-admin-system.scss
rename to media_source/system/scss/system-admin-system.scss
diff --git a/build/media_source/system/scss/system-site-error.scss b/media_source/system/scss/system-site-error.scss
similarity index 100%
rename from build/media_source/system/scss/system-site-error.scss
rename to media_source/system/scss/system-site-error.scss
diff --git a/build/media_source/system/scss/system-site-error_rtl.scss b/media_source/system/scss/system-site-error_rtl.scss
similarity index 100%
rename from build/media_source/system/scss/system-site-error_rtl.scss
rename to media_source/system/scss/system-site-error_rtl.scss
diff --git a/build/media_source/system/scss/system-site-general.scss b/media_source/system/scss/system-site-general.scss
similarity index 100%
rename from build/media_source/system/scss/system-site-general.scss
rename to media_source/system/scss/system-site-general.scss
diff --git a/build/media_source/system/scss/system-site-offline.scss b/media_source/system/scss/system-site-offline.scss
similarity index 100%
rename from build/media_source/system/scss/system-site-offline.scss
rename to media_source/system/scss/system-site-offline.scss
diff --git a/build/media_source/templates/administrator/atum/images/icons/dashboard.svg b/media_source/templates/administrator/atum/images/icons/dashboard.svg
similarity index 100%
rename from build/media_source/templates/administrator/atum/images/icons/dashboard.svg
rename to media_source/templates/administrator/atum/images/icons/dashboard.svg
diff --git a/build/media_source/templates/administrator/atum/images/joomla-pattern.svg b/media_source/templates/administrator/atum/images/joomla-pattern.svg
similarity index 100%
rename from build/media_source/templates/administrator/atum/images/joomla-pattern.svg
rename to media_source/templates/administrator/atum/images/joomla-pattern.svg
diff --git a/build/media_source/templates/administrator/atum/images/logos/brand-large.svg b/media_source/templates/administrator/atum/images/logos/brand-large.svg
similarity index 100%
rename from build/media_source/templates/administrator/atum/images/logos/brand-large.svg
rename to media_source/templates/administrator/atum/images/logos/brand-large.svg
diff --git a/build/media_source/templates/administrator/atum/images/logos/brand-small.svg b/media_source/templates/administrator/atum/images/logos/brand-small.svg
similarity index 100%
rename from build/media_source/templates/administrator/atum/images/logos/brand-small.svg
rename to media_source/templates/administrator/atum/images/logos/brand-small.svg
diff --git a/build/media_source/templates/administrator/atum/images/logos/login.svg b/media_source/templates/administrator/atum/images/logos/login.svg
similarity index 100%
rename from build/media_source/templates/administrator/atum/images/logos/login.svg
rename to media_source/templates/administrator/atum/images/logos/login.svg
diff --git a/build/media_source/templates/administrator/atum/images/select-bg-active-rtl.svg b/media_source/templates/administrator/atum/images/select-bg-active-rtl.svg
similarity index 100%
rename from build/media_source/templates/administrator/atum/images/select-bg-active-rtl.svg
rename to media_source/templates/administrator/atum/images/select-bg-active-rtl.svg
diff --git a/build/media_source/templates/administrator/atum/images/select-bg-active.svg b/media_source/templates/administrator/atum/images/select-bg-active.svg
similarity index 100%
rename from build/media_source/templates/administrator/atum/images/select-bg-active.svg
rename to media_source/templates/administrator/atum/images/select-bg-active.svg
diff --git a/build/media_source/templates/administrator/atum/images/select-bg-dark.svg b/media_source/templates/administrator/atum/images/select-bg-dark.svg
similarity index 100%
rename from build/media_source/templates/administrator/atum/images/select-bg-dark.svg
rename to media_source/templates/administrator/atum/images/select-bg-dark.svg
diff --git a/installation/template/images/select-bg-rtl-dark.svg b/media_source/templates/administrator/atum/images/select-bg-rtl-dark.svg
similarity index 100%
rename from installation/template/images/select-bg-rtl-dark.svg
rename to media_source/templates/administrator/atum/images/select-bg-rtl-dark.svg
diff --git a/build/media_source/templates/site/cassiopeia/images/select-bg-rtl.svg b/media_source/templates/administrator/atum/images/select-bg-rtl.svg
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/images/select-bg-rtl.svg
rename to media_source/templates/administrator/atum/images/select-bg-rtl.svg
diff --git a/build/media_source/templates/site/cassiopeia/images/select-bg.svg b/media_source/templates/administrator/atum/images/select-bg.svg
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/images/select-bg.svg
rename to media_source/templates/administrator/atum/images/select-bg.svg
diff --git a/build/media_source/templates/administrator/atum/images/template_preview.png b/media_source/templates/administrator/atum/images/template_preview.png
similarity index 100%
rename from build/media_source/templates/administrator/atum/images/template_preview.png
rename to media_source/templates/administrator/atum/images/template_preview.png
diff --git a/build/media_source/templates/administrator/atum/images/template_thumbnail.png b/media_source/templates/administrator/atum/images/template_thumbnail.png
similarity index 100%
rename from build/media_source/templates/administrator/atum/images/template_thumbnail.png
rename to media_source/templates/administrator/atum/images/template_thumbnail.png
diff --git a/build/media_source/templates/administrator/atum/js/template.es6.js b/media_source/templates/administrator/atum/js/template.es6.js
similarity index 100%
rename from build/media_source/templates/administrator/atum/js/template.es6.js
rename to media_source/templates/administrator/atum/js/template.es6.js
diff --git a/build/media_source/templates/administrator/atum/scss/_maps-atum.scss b/media_source/templates/administrator/atum/scss/_maps-atum.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/_maps-atum.scss
rename to media_source/templates/administrator/atum/scss/_maps-atum.scss
diff --git a/build/media_source/templates/administrator/atum/scss/_variables-dark.scss b/media_source/templates/administrator/atum/scss/_variables-dark.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/_variables-dark.scss
rename to media_source/templates/administrator/atum/scss/_variables-dark.scss
diff --git a/build/media_source/templates/administrator/atum/scss/_variables.scss b/media_source/templates/administrator/atum/scss/_variables.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/_variables.scss
rename to media_source/templates/administrator/atum/scss/_variables.scss
diff --git a/build/media_source/templates/administrator/atum/scss/blocks/_alerts.scss b/media_source/templates/administrator/atum/scss/blocks/_alerts.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/blocks/_alerts.scss
rename to media_source/templates/administrator/atum/scss/blocks/_alerts.scss
diff --git a/build/media_source/templates/administrator/atum/scss/blocks/_calendar.scss b/media_source/templates/administrator/atum/scss/blocks/_calendar.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/blocks/_calendar.scss
rename to media_source/templates/administrator/atum/scss/blocks/_calendar.scss
diff --git a/build/media_source/templates/administrator/atum/scss/blocks/_edit.scss b/media_source/templates/administrator/atum/scss/blocks/_edit.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/blocks/_edit.scss
rename to media_source/templates/administrator/atum/scss/blocks/_edit.scss
diff --git a/build/media_source/templates/administrator/atum/scss/blocks/_form.scss b/media_source/templates/administrator/atum/scss/blocks/_form.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/blocks/_form.scss
rename to media_source/templates/administrator/atum/scss/blocks/_form.scss
diff --git a/build/media_source/templates/administrator/atum/scss/blocks/_global.scss b/media_source/templates/administrator/atum/scss/blocks/_global.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/blocks/_global.scss
rename to media_source/templates/administrator/atum/scss/blocks/_global.scss
diff --git a/build/media_source/templates/administrator/atum/scss/blocks/_header.scss b/media_source/templates/administrator/atum/scss/blocks/_header.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/blocks/_header.scss
rename to media_source/templates/administrator/atum/scss/blocks/_header.scss
diff --git a/build/media_source/templates/administrator/atum/scss/blocks/_icons.scss b/media_source/templates/administrator/atum/scss/blocks/_icons.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/blocks/_icons.scss
rename to media_source/templates/administrator/atum/scss/blocks/_icons.scss
diff --git a/build/media_source/templates/administrator/atum/scss/blocks/_iframe.scss b/media_source/templates/administrator/atum/scss/blocks/_iframe.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/blocks/_iframe.scss
rename to media_source/templates/administrator/atum/scss/blocks/_iframe.scss
diff --git a/build/media_source/templates/administrator/atum/scss/blocks/_layout.scss b/media_source/templates/administrator/atum/scss/blocks/_layout.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/blocks/_layout.scss
rename to media_source/templates/administrator/atum/scss/blocks/_layout.scss
diff --git a/build/media_source/templates/administrator/atum/scss/blocks/_lists.scss b/media_source/templates/administrator/atum/scss/blocks/_lists.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/blocks/_lists.scss
rename to media_source/templates/administrator/atum/scss/blocks/_lists.scss
diff --git a/build/media_source/templates/administrator/atum/scss/blocks/_login.scss b/media_source/templates/administrator/atum/scss/blocks/_login.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/blocks/_login.scss
rename to media_source/templates/administrator/atum/scss/blocks/_login.scss
diff --git a/build/media_source/templates/administrator/atum/scss/blocks/_modals.scss b/media_source/templates/administrator/atum/scss/blocks/_modals.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/blocks/_modals.scss
rename to media_source/templates/administrator/atum/scss/blocks/_modals.scss
diff --git a/build/media_source/templates/administrator/atum/scss/blocks/_quickicons.scss b/media_source/templates/administrator/atum/scss/blocks/_quickicons.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/blocks/_quickicons.scss
rename to media_source/templates/administrator/atum/scss/blocks/_quickicons.scss
diff --git a/build/media_source/templates/administrator/atum/scss/blocks/_shepard-modals.scss b/media_source/templates/administrator/atum/scss/blocks/_shepard-modals.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/blocks/_shepard-modals.scss
rename to media_source/templates/administrator/atum/scss/blocks/_shepard-modals.scss
diff --git a/build/media_source/templates/administrator/atum/scss/blocks/_sidebar-nav.scss b/media_source/templates/administrator/atum/scss/blocks/_sidebar-nav.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/blocks/_sidebar-nav.scss
rename to media_source/templates/administrator/atum/scss/blocks/_sidebar-nav.scss
diff --git a/build/media_source/templates/administrator/atum/scss/blocks/_sidebar.scss b/media_source/templates/administrator/atum/scss/blocks/_sidebar.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/blocks/_sidebar.scss
rename to media_source/templates/administrator/atum/scss/blocks/_sidebar.scss
diff --git a/build/media_source/templates/administrator/atum/scss/blocks/_switcher.scss b/media_source/templates/administrator/atum/scss/blocks/_switcher.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/blocks/_switcher.scss
rename to media_source/templates/administrator/atum/scss/blocks/_switcher.scss
diff --git a/build/media_source/templates/administrator/atum/scss/blocks/_toolbar.scss b/media_source/templates/administrator/atum/scss/blocks/_toolbar.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/blocks/_toolbar.scss
rename to media_source/templates/administrator/atum/scss/blocks/_toolbar.scss
diff --git a/build/media_source/templates/administrator/atum/scss/blocks/_treeselect.scss b/media_source/templates/administrator/atum/scss/blocks/_treeselect.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/blocks/_treeselect.scss
rename to media_source/templates/administrator/atum/scss/blocks/_treeselect.scss
diff --git a/build/media_source/templates/administrator/atum/scss/blocks/_utilities.scss b/media_source/templates/administrator/atum/scss/blocks/_utilities.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/blocks/_utilities.scss
rename to media_source/templates/administrator/atum/scss/blocks/_utilities.scss
diff --git a/build/media_source/templates/administrator/atum/scss/pages/_com_config.scss b/media_source/templates/administrator/atum/scss/pages/_com_config.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/pages/_com_config.scss
rename to media_source/templates/administrator/atum/scss/pages/_com_config.scss
diff --git a/build/media_source/templates/administrator/atum/scss/pages/_com_content.scss b/media_source/templates/administrator/atum/scss/pages/_com_content.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/pages/_com_content.scss
rename to media_source/templates/administrator/atum/scss/pages/_com_content.scss
diff --git a/build/media_source/templates/administrator/atum/scss/pages/_com_cpanel.scss b/media_source/templates/administrator/atum/scss/pages/_com_cpanel.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/pages/_com_cpanel.scss
rename to media_source/templates/administrator/atum/scss/pages/_com_cpanel.scss
diff --git a/build/media_source/templates/administrator/atum/scss/pages/_com_joomlaupdate.scss b/media_source/templates/administrator/atum/scss/pages/_com_joomlaupdate.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/pages/_com_joomlaupdate.scss
rename to media_source/templates/administrator/atum/scss/pages/_com_joomlaupdate.scss
diff --git a/build/media_source/templates/administrator/atum/scss/pages/_com_media.scss b/media_source/templates/administrator/atum/scss/pages/_com_media.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/pages/_com_media.scss
rename to media_source/templates/administrator/atum/scss/pages/_com_media.scss
diff --git a/build/media_source/templates/administrator/atum/scss/pages/_com_modules.scss b/media_source/templates/administrator/atum/scss/pages/_com_modules.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/pages/_com_modules.scss
rename to media_source/templates/administrator/atum/scss/pages/_com_modules.scss
diff --git a/build/media_source/templates/administrator/atum/scss/pages/_com_privacy.scss b/media_source/templates/administrator/atum/scss/pages/_com_privacy.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/pages/_com_privacy.scss
rename to media_source/templates/administrator/atum/scss/pages/_com_privacy.scss
diff --git a/build/media_source/templates/administrator/atum/scss/pages/_com_scheduler.scss b/media_source/templates/administrator/atum/scss/pages/_com_scheduler.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/pages/_com_scheduler.scss
rename to media_source/templates/administrator/atum/scss/pages/_com_scheduler.scss
diff --git a/build/media_source/templates/administrator/atum/scss/pages/_com_tags.scss b/media_source/templates/administrator/atum/scss/pages/_com_tags.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/pages/_com_tags.scss
rename to media_source/templates/administrator/atum/scss/pages/_com_tags.scss
diff --git a/build/media_source/templates/administrator/atum/scss/pages/_com_templates.scss b/media_source/templates/administrator/atum/scss/pages/_com_templates.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/pages/_com_templates.scss
rename to media_source/templates/administrator/atum/scss/pages/_com_templates.scss
diff --git a/build/media_source/templates/administrator/atum/scss/pages/_com_users.scss b/media_source/templates/administrator/atum/scss/pages/_com_users.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/pages/_com_users.scss
rename to media_source/templates/administrator/atum/scss/pages/_com_users.scss
diff --git a/build/media_source/templates/administrator/atum/scss/pages/_plg_web_installer.scss b/media_source/templates/administrator/atum/scss/pages/_plg_web_installer.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/pages/_plg_web_installer.scss
rename to media_source/templates/administrator/atum/scss/pages/_plg_web_installer.scss
diff --git a/build/media_source/templates/administrator/atum/scss/system/fields/_calendar.scss b/media_source/templates/administrator/atum/scss/system/fields/_calendar.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/system/fields/_calendar.scss
rename to media_source/templates/administrator/atum/scss/system/fields/_calendar.scss
diff --git a/build/media_source/templates/administrator/atum/scss/system/fields/_switcher.scss b/media_source/templates/administrator/atum/scss/system/fields/_switcher.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/system/fields/_switcher.scss
rename to media_source/templates/administrator/atum/scss/system/fields/_switcher.scss
diff --git a/build/media_source/templates/administrator/atum/scss/system/searchtools/searchtools.scss b/media_source/templates/administrator/atum/scss/system/searchtools/searchtools.scss
similarity index 95%
rename from build/media_source/templates/administrator/atum/scss/system/searchtools/searchtools.scss
rename to media_source/templates/administrator/atum/scss/system/searchtools/searchtools.scss
index 44d2baa2c98..c03f7731225 100644
--- a/build/media_source/templates/administrator/atum/scss/system/searchtools/searchtools.scss
+++ b/media_source/templates/administrator/atum/scss/system/searchtools/searchtools.scss
@@ -1,5 +1,5 @@
@import "../../variables";
-@import "../../../../../../../../media/vendor/bootstrap/scss/mixins";
+@import "../../../../../../../media/vendor/bootstrap/scss/mixins";
// Search tools
diff --git a/installation/template/scss/template-rtl.scss b/media_source/templates/administrator/atum/scss/template-rtl.scss
similarity index 100%
rename from installation/template/scss/template-rtl.scss
rename to media_source/templates/administrator/atum/scss/template-rtl.scss
diff --git a/build/media_source/templates/administrator/atum/scss/template.scss b/media_source/templates/administrator/atum/scss/template.scss
similarity index 87%
rename from build/media_source/templates/administrator/atum/scss/template.scss
rename to media_source/templates/administrator/atum/scss/template.scss
index e8fa8e138b2..19c53e4c9ed 100644
--- a/build/media_source/templates/administrator/atum/scss/template.scss
+++ b/media_source/templates/administrator/atum/scss/template.scss
@@ -1,27 +1,27 @@
// Bootstrap functions
-@import "../../../../../../media/vendor/bootstrap/scss/functions";
+@import "../../../../../media/vendor/bootstrap/scss/functions";
// Atum Variables
@import "variables";
@import "variables-dark";
-@import "../../../../../../media/vendor/bootstrap/scss/variables";
-@import "../../../../../../media/vendor/bootstrap/scss/variables-dark";
-@import "../../../../../../media/vendor/bootstrap/scss/maps";
+@import "../../../../../media/vendor/bootstrap/scss/variables";
+@import "../../../../../media/vendor/bootstrap/scss/variables-dark";
+@import "../../../../../media/vendor/bootstrap/scss/maps";
@import "maps-atum";
-@import "../../../../../../media/vendor/bootstrap/scss/mixins";
-@import "../../../../../../media/vendor/bootstrap/scss/utilities";
+@import "../../../../../media/vendor/bootstrap/scss/mixins";
+@import "../../../../../media/vendor/bootstrap/scss/utilities";
// Bootstrap other
-@import "../../../../../../media/vendor/bootstrap/scss/bootstrap";
+@import "../../../../../media/vendor/bootstrap/scss/bootstrap";
// Fonts
-@import "../../../../../../media/vendor/roboto-fontface/scss/roboto/sass/roboto-fontface";
+@import "../../../../../media/vendor/roboto-fontface/scss/roboto/sass/roboto-fontface";
@import "blocks/global"; // Leave this first
// jQuery Minicolors
-@import "../../../../../../media/system/scss/jquery-minicolors";
+@import "../../../../../media/system/scss/jquery-minicolors";
// System overrides
@import "system/fields/calendar";
diff --git a/build/media_source/templates/administrator/atum/scss/vendor/_codemirror.scss b/media_source/templates/administrator/atum/scss/vendor/_codemirror.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/vendor/_codemirror.scss
rename to media_source/templates/administrator/atum/scss/vendor/_codemirror.scss
diff --git a/build/media_source/templates/administrator/atum/scss/vendor/_dragula.scss b/media_source/templates/administrator/atum/scss/vendor/_dragula.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/vendor/_dragula.scss
rename to media_source/templates/administrator/atum/scss/vendor/_dragula.scss
diff --git a/build/media_source/templates/administrator/atum/scss/vendor/_tinymce.scss b/media_source/templates/administrator/atum/scss/vendor/_tinymce.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/vendor/_tinymce.scss
rename to media_source/templates/administrator/atum/scss/vendor/_tinymce.scss
diff --git a/media_source/templates/administrator/atum/scss/vendor/awesomplete/awesomplete.scss b/media_source/templates/administrator/atum/scss/vendor/awesomplete/awesomplete.scss
new file mode 100644
index 00000000000..fa45accb488
--- /dev/null
+++ b/media_source/templates/administrator/atum/scss/vendor/awesomplete/awesomplete.scss
@@ -0,0 +1,6 @@
+// Awesomplete
+@import "../../../../../../../media/vendor/awesomplete/css/awesomplete";
+
+.awesomplete {
+ display: block;
+}
diff --git a/build/media_source/templates/administrator/atum/scss/vendor/bootstrap/_accordion.scss b/media_source/templates/administrator/atum/scss/vendor/bootstrap/_accordion.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/vendor/bootstrap/_accordion.scss
rename to media_source/templates/administrator/atum/scss/vendor/bootstrap/_accordion.scss
diff --git a/build/media_source/templates/administrator/atum/scss/vendor/bootstrap/_badge.scss b/media_source/templates/administrator/atum/scss/vendor/bootstrap/_badge.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/vendor/bootstrap/_badge.scss
rename to media_source/templates/administrator/atum/scss/vendor/bootstrap/_badge.scss
diff --git a/build/media_source/templates/administrator/atum/scss/vendor/bootstrap/_buttons.scss b/media_source/templates/administrator/atum/scss/vendor/bootstrap/_buttons.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/vendor/bootstrap/_buttons.scss
rename to media_source/templates/administrator/atum/scss/vendor/bootstrap/_buttons.scss
diff --git a/build/media_source/templates/administrator/atum/scss/vendor/bootstrap/_card.scss b/media_source/templates/administrator/atum/scss/vendor/bootstrap/_card.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/vendor/bootstrap/_card.scss
rename to media_source/templates/administrator/atum/scss/vendor/bootstrap/_card.scss
diff --git a/build/media_source/templates/administrator/atum/scss/vendor/bootstrap/_collapse.scss b/media_source/templates/administrator/atum/scss/vendor/bootstrap/_collapse.scss
similarity index 95%
rename from build/media_source/templates/administrator/atum/scss/vendor/bootstrap/_collapse.scss
rename to media_source/templates/administrator/atum/scss/vendor/bootstrap/_collapse.scss
index 516e1f748f6..e450e761079 100644
--- a/build/media_source/templates/administrator/atum/scss/vendor/bootstrap/_collapse.scss
+++ b/media_source/templates/administrator/atum/scss/vendor/bootstrap/_collapse.scss
@@ -1,28 +1,28 @@
-// Collapse
-
-.accordion {
-
- .card-header {
- display: block;
- font-size: $h5-font-size;
- font-weight: $font-weight-bold;
- line-height: $headings-line-height;
- }
-
- /**
- * TODO: This seems fairly specifically built for the menu types view and might be better scoped to
- * that view rather than just being overridden for everything.
- */
- .list-group-item {
- --list-group-color: var(--link-color);
- --list-group-bg: var(--white-offset);
- }
-
- @if $enable-dark-mode {
- @include color-mode(dark) {
- .list-group-item {
- --list-group-bg: var(--gray-800);
- }
- }
- }
-}
+// Collapse
+
+.accordion {
+
+ .card-header {
+ display: block;
+ font-size: $h5-font-size;
+ font-weight: $font-weight-bold;
+ line-height: $headings-line-height;
+ }
+
+ /**
+ * TODO: This seems fairly specifically built for the menu types view and might be better scoped to
+ * that view rather than just being overridden for everything.
+ */
+ .list-group-item {
+ --list-group-color: var(--link-color);
+ --list-group-bg: var(--white-offset);
+ }
+
+ @if $enable-dark-mode {
+ @include color-mode(dark) {
+ .list-group-item {
+ --list-group-bg: var(--gray-800);
+ }
+ }
+ }
+}
diff --git a/build/media_source/templates/administrator/atum/scss/vendor/bootstrap/_custom-forms.scss b/media_source/templates/administrator/atum/scss/vendor/bootstrap/_custom-forms.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/vendor/bootstrap/_custom-forms.scss
rename to media_source/templates/administrator/atum/scss/vendor/bootstrap/_custom-forms.scss
diff --git a/build/media_source/templates/administrator/atum/scss/vendor/bootstrap/_dropdown.scss b/media_source/templates/administrator/atum/scss/vendor/bootstrap/_dropdown.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/vendor/bootstrap/_dropdown.scss
rename to media_source/templates/administrator/atum/scss/vendor/bootstrap/_dropdown.scss
diff --git a/build/media_source/templates/administrator/atum/scss/vendor/bootstrap/_form.scss b/media_source/templates/administrator/atum/scss/vendor/bootstrap/_form.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/vendor/bootstrap/_form.scss
rename to media_source/templates/administrator/atum/scss/vendor/bootstrap/_form.scss
diff --git a/build/media_source/templates/administrator/atum/scss/vendor/bootstrap/_list-group.scss b/media_source/templates/administrator/atum/scss/vendor/bootstrap/_list-group.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/vendor/bootstrap/_list-group.scss
rename to media_source/templates/administrator/atum/scss/vendor/bootstrap/_list-group.scss
diff --git a/build/media_source/templates/administrator/atum/scss/vendor/bootstrap/_lists.scss b/media_source/templates/administrator/atum/scss/vendor/bootstrap/_lists.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/vendor/bootstrap/_lists.scss
rename to media_source/templates/administrator/atum/scss/vendor/bootstrap/_lists.scss
diff --git a/build/media_source/templates/administrator/atum/scss/vendor/bootstrap/_modal.scss b/media_source/templates/administrator/atum/scss/vendor/bootstrap/_modal.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/vendor/bootstrap/_modal.scss
rename to media_source/templates/administrator/atum/scss/vendor/bootstrap/_modal.scss
diff --git a/build/media_source/templates/administrator/atum/scss/vendor/bootstrap/_pagination.scss b/media_source/templates/administrator/atum/scss/vendor/bootstrap/_pagination.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/vendor/bootstrap/_pagination.scss
rename to media_source/templates/administrator/atum/scss/vendor/bootstrap/_pagination.scss
diff --git a/build/media_source/templates/administrator/atum/scss/vendor/bootstrap/_reboot.scss b/media_source/templates/administrator/atum/scss/vendor/bootstrap/_reboot.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/vendor/bootstrap/_reboot.scss
rename to media_source/templates/administrator/atum/scss/vendor/bootstrap/_reboot.scss
diff --git a/build/media_source/templates/administrator/atum/scss/vendor/bootstrap/_table.scss b/media_source/templates/administrator/atum/scss/vendor/bootstrap/_table.scss
similarity index 100%
rename from build/media_source/templates/administrator/atum/scss/vendor/bootstrap/_table.scss
rename to media_source/templates/administrator/atum/scss/vendor/bootstrap/_table.scss
diff --git a/build/media_source/templates/administrator/atum/scss/vendor/choicesjs/choices.scss b/media_source/templates/administrator/atum/scss/vendor/choicesjs/choices.scss
similarity index 94%
rename from build/media_source/templates/administrator/atum/scss/vendor/choicesjs/choices.scss
rename to media_source/templates/administrator/atum/scss/vendor/choicesjs/choices.scss
index 372627631bb..76d5180bbc3 100644
--- a/build/media_source/templates/administrator/atum/scss/vendor/choicesjs/choices.scss
+++ b/media_source/templates/administrator/atum/scss/vendor/choicesjs/choices.scss
@@ -1,14 +1,14 @@
-@import "../../../../../../../../media/vendor/bootstrap/scss/functions";
+@import "../../../../../../../media/vendor/bootstrap/scss/functions";
// Atum Variables
@import "../../variables";
@import "../../variables-dark";
-@import "../../../../../../../../media/vendor/bootstrap/scss/variables";
-@import "../../../../../../../../media/vendor/bootstrap/scss/mixins";
+@import "../../../../../../../media/vendor/bootstrap/scss/variables";
+@import "../../../../../../../media/vendor/bootstrap/scss/mixins";
// choices.js
-@import "../../../../../../../../media/vendor/choicesjs/scss/choices";
+@import "../../../../../../../media/vendor/choicesjs/scss/choices";
.choices {
border: $form-select-border; //$form-select-border-width solid $form-select-border-color;
diff --git a/build/media_source/templates/administrator/atum/scss/vendor/fontawesome-free/fontawesome.scss b/media_source/templates/administrator/atum/scss/vendor/fontawesome-free/fontawesome.scss
similarity index 61%
rename from build/media_source/templates/administrator/atum/scss/vendor/fontawesome-free/fontawesome.scss
rename to media_source/templates/administrator/atum/scss/vendor/fontawesome-free/fontawesome.scss
index 7af0051d9c1..c2ad33d50d7 100644
--- a/build/media_source/templates/administrator/atum/scss/vendor/fontawesome-free/fontawesome.scss
+++ b/media_source/templates/administrator/atum/scss/vendor/fontawesome-free/fontawesome.scss
@@ -3,15 +3,15 @@ $fa-css-prefix: fa;
$fa-font-path: "../../../../../../vendor/fontawesome-free/webfonts" !default;
// Font Awesome 6 Free
-@import "../../../../../../../../media/vendor/fontawesome-free/scss/fontawesome";
-@import "../../../../../../../../media/vendor/fontawesome-free/scss/regular";
-@import "../../../../../../../../media/vendor/fontawesome-free/scss/solid";
+@import "../../../../../../../media/vendor/fontawesome-free/scss/fontawesome";
+@import "../../../../../../../media/vendor/fontawesome-free/scss/regular";
+@import "../../../../../../../media/vendor/fontawesome-free/scss/solid";
// Brands must be imported last
-@import "../../../../../../../../media/vendor/fontawesome-free/scss/brands";
+@import "../../../../../../../media/vendor/fontawesome-free/scss/brands";
// B/C with Font Awesome 5
-@import "../../../../../../../../media/vendor/fontawesome-free/scss/shims";
+@import "../../../../../../../media/vendor/fontawesome-free/scss/shims";
// B/C for Icomoon
@import "../../../../../../system/scss/icomoon";
diff --git a/build/media_source/templates/administrator/atum/scss/vendor/joomla-custom-elements/joomla-alert.scss b/media_source/templates/administrator/atum/scss/vendor/joomla-custom-elements/joomla-alert.scss
similarity index 97%
rename from build/media_source/templates/administrator/atum/scss/vendor/joomla-custom-elements/joomla-alert.scss
rename to media_source/templates/administrator/atum/scss/vendor/joomla-custom-elements/joomla-alert.scss
index 27b42c6159f..8cc5fd5a6cf 100644
--- a/build/media_source/templates/administrator/atum/scss/vendor/joomla-custom-elements/joomla-alert.scss
+++ b/media_source/templates/administrator/atum/scss/vendor/joomla-custom-elements/joomla-alert.scss
@@ -1,7 +1,7 @@
@import "../../variables";
@import "../../variables-dark";
-@import "../../../../../../../../media/vendor/joomla-custom-elements/css/joomla-alert";
-@import "../../../../../../../../media/vendor/bootstrap/scss/mixins/color-mode";
+@import "../../../../../../../media/vendor/joomla-custom-elements/css/joomla-alert";
+@import "../../../../../../../media/vendor/bootstrap/scss/mixins/color-mode";
// The following is a restyle for the system alerts
diff --git a/build/media_source/templates/administrator/atum/scss/vendor/joomla-custom-elements/joomla-tab.scss b/media_source/templates/administrator/atum/scss/vendor/joomla-custom-elements/joomla-tab.scss
similarity index 97%
rename from build/media_source/templates/administrator/atum/scss/vendor/joomla-custom-elements/joomla-tab.scss
rename to media_source/templates/administrator/atum/scss/vendor/joomla-custom-elements/joomla-tab.scss
index 53cc4b37a00..f6d2507e350 100644
--- a/build/media_source/templates/administrator/atum/scss/vendor/joomla-custom-elements/joomla-tab.scss
+++ b/media_source/templates/administrator/atum/scss/vendor/joomla-custom-elements/joomla-tab.scss
@@ -1,10 +1,10 @@
-@import "../../../../../../../../media/vendor/bootstrap/scss/functions";
+@import "../../../../../../../media/vendor/bootstrap/scss/functions";
// Atum Variables
@import "../../variables";
-@import "../../../../../../../../media/vendor/bootstrap/scss/variables";
-@import "../../../../../../../../media/vendor/bootstrap/scss/mixins";
+@import "../../../../../../../media/vendor/bootstrap/scss/variables";
+@import "../../../../../../../media/vendor/bootstrap/scss/mixins";
// Tabs
diff --git a/build/media_source/templates/administrator/atum/scss/vendor/minicolors/minicolors.scss b/media_source/templates/administrator/atum/scss/vendor/minicolors/minicolors.scss
similarity index 68%
rename from build/media_source/templates/administrator/atum/scss/vendor/minicolors/minicolors.scss
rename to media_source/templates/administrator/atum/scss/vendor/minicolors/minicolors.scss
index e649737dccb..6930253b2e4 100644
--- a/build/media_source/templates/administrator/atum/scss/vendor/minicolors/minicolors.scss
+++ b/media_source/templates/administrator/atum/scss/vendor/minicolors/minicolors.scss
@@ -1,5 +1,5 @@
// Minicolours
-@import "../../../../../../../../media/vendor/minicolors/css/jquery.minicolors";
+@import "../../../../../../../media/vendor/minicolors/css/jquery.minicolors";
.minicolors-theme-bootstrap {
diff --git a/build/media_source/templates/site/cassiopeia/images/logo.svg b/media_source/templates/site/cassiopeia/images/logo.svg
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/images/logo.svg
rename to media_source/templates/site/cassiopeia/images/logo.svg
diff --git a/build/media_source/templates/site/cassiopeia/images/select-bg-active-rtl.svg b/media_source/templates/site/cassiopeia/images/select-bg-active-rtl.svg
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/images/select-bg-active-rtl.svg
rename to media_source/templates/site/cassiopeia/images/select-bg-active-rtl.svg
diff --git a/build/media_source/templates/site/cassiopeia/images/select-bg-active.svg b/media_source/templates/site/cassiopeia/images/select-bg-active.svg
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/images/select-bg-active.svg
rename to media_source/templates/site/cassiopeia/images/select-bg-active.svg
diff --git a/installation/template/images/select-bg-rtl.svg b/media_source/templates/site/cassiopeia/images/select-bg-rtl.svg
similarity index 100%
rename from installation/template/images/select-bg-rtl.svg
rename to media_source/templates/site/cassiopeia/images/select-bg-rtl.svg
diff --git a/installation/template/images/select-bg.svg b/media_source/templates/site/cassiopeia/images/select-bg.svg
similarity index 100%
rename from installation/template/images/select-bg.svg
rename to media_source/templates/site/cassiopeia/images/select-bg.svg
diff --git a/build/media_source/templates/site/cassiopeia/images/template_preview.png b/media_source/templates/site/cassiopeia/images/template_preview.png
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/images/template_preview.png
rename to media_source/templates/site/cassiopeia/images/template_preview.png
diff --git a/build/media_source/templates/site/cassiopeia/images/template_thumbnail.png b/media_source/templates/site/cassiopeia/images/template_thumbnail.png
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/images/template_thumbnail.png
rename to media_source/templates/site/cassiopeia/images/template_thumbnail.png
diff --git a/build/media_source/templates/site/cassiopeia/js/mod_menu/menu-metismenu.es6.js b/media_source/templates/site/cassiopeia/js/mod_menu/menu-metismenu.es6.js
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/js/mod_menu/menu-metismenu.es6.js
rename to media_source/templates/site/cassiopeia/js/mod_menu/menu-metismenu.es6.js
diff --git a/build/media_source/templates/site/cassiopeia/js/template.es6.js b/media_source/templates/site/cassiopeia/js/template.es6.js
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/js/template.es6.js
rename to media_source/templates/site/cassiopeia/js/template.es6.js
diff --git a/build/media_source/templates/site/cassiopeia/scss/blocks/_alerts.scss b/media_source/templates/site/cassiopeia/scss/blocks/_alerts.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/blocks/_alerts.scss
rename to media_source/templates/site/cassiopeia/scss/blocks/_alerts.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/blocks/_back-to-top.scss b/media_source/templates/site/cassiopeia/scss/blocks/_back-to-top.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/blocks/_back-to-top.scss
rename to media_source/templates/site/cassiopeia/scss/blocks/_back-to-top.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/blocks/_banner.scss b/media_source/templates/site/cassiopeia/scss/blocks/_banner.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/blocks/_banner.scss
rename to media_source/templates/site/cassiopeia/scss/blocks/_banner.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/blocks/_css-grid.scss b/media_source/templates/site/cassiopeia/scss/blocks/_css-grid.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/blocks/_css-grid.scss
rename to media_source/templates/site/cassiopeia/scss/blocks/_css-grid.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/blocks/_footer.scss b/media_source/templates/site/cassiopeia/scss/blocks/_footer.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/blocks/_footer.scss
rename to media_source/templates/site/cassiopeia/scss/blocks/_footer.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/blocks/_form.scss b/media_source/templates/site/cassiopeia/scss/blocks/_form.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/blocks/_form.scss
rename to media_source/templates/site/cassiopeia/scss/blocks/_form.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/blocks/_frontend-edit.scss b/media_source/templates/site/cassiopeia/scss/blocks/_frontend-edit.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/blocks/_frontend-edit.scss
rename to media_source/templates/site/cassiopeia/scss/blocks/_frontend-edit.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/blocks/_global.scss b/media_source/templates/site/cassiopeia/scss/blocks/_global.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/blocks/_global.scss
rename to media_source/templates/site/cassiopeia/scss/blocks/_global.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/blocks/_header.scss b/media_source/templates/site/cassiopeia/scss/blocks/_header.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/blocks/_header.scss
rename to media_source/templates/site/cassiopeia/scss/blocks/_header.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/blocks/_icons.scss b/media_source/templates/site/cassiopeia/scss/blocks/_icons.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/blocks/_icons.scss
rename to media_source/templates/site/cassiopeia/scss/blocks/_icons.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/blocks/_iframe.scss b/media_source/templates/site/cassiopeia/scss/blocks/_iframe.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/blocks/_iframe.scss
rename to media_source/templates/site/cassiopeia/scss/blocks/_iframe.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/blocks/_layout.scss b/media_source/templates/site/cassiopeia/scss/blocks/_layout.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/blocks/_layout.scss
rename to media_source/templates/site/cassiopeia/scss/blocks/_layout.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/blocks/_legacy.scss b/media_source/templates/site/cassiopeia/scss/blocks/_legacy.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/blocks/_legacy.scss
rename to media_source/templates/site/cassiopeia/scss/blocks/_legacy.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/blocks/_modals.scss b/media_source/templates/site/cassiopeia/scss/blocks/_modals.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/blocks/_modals.scss
rename to media_source/templates/site/cassiopeia/scss/blocks/_modals.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/blocks/_modifiers.scss b/media_source/templates/site/cassiopeia/scss/blocks/_modifiers.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/blocks/_modifiers.scss
rename to media_source/templates/site/cassiopeia/scss/blocks/_modifiers.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/blocks/_tags.scss b/media_source/templates/site/cassiopeia/scss/blocks/_tags.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/blocks/_tags.scss
rename to media_source/templates/site/cassiopeia/scss/blocks/_tags.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/blocks/_toolbar.scss b/media_source/templates/site/cassiopeia/scss/blocks/_toolbar.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/blocks/_toolbar.scss
rename to media_source/templates/site/cassiopeia/scss/blocks/_toolbar.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/blocks/_utilities.scss b/media_source/templates/site/cassiopeia/scss/blocks/_utilities.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/blocks/_utilities.scss
rename to media_source/templates/site/cassiopeia/scss/blocks/_utilities.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/editor.scss b/media_source/templates/site/cassiopeia/scss/editor.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/editor.scss
rename to media_source/templates/site/cassiopeia/scss/editor.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/global/colors_alternative.scss b/media_source/templates/site/cassiopeia/scss/global/colors_alternative.scss
similarity index 88%
rename from build/media_source/templates/site/cassiopeia/scss/global/colors_alternative.scss
rename to media_source/templates/site/cassiopeia/scss/global/colors_alternative.scss
index 61b1c546f2f..a4c9ef8af24 100644
--- a/build/media_source/templates/site/cassiopeia/scss/global/colors_alternative.scss
+++ b/media_source/templates/site/cassiopeia/scss/global/colors_alternative.scss
@@ -1,6 +1,6 @@
// Variables, Functions and Mixins
@import "../tools/tools";
-@import "../../../../../../../media/vendor/bootstrap/scss/functions";
+@import "../../../../../../media/vendor/bootstrap/scss/functions";
:root {
--cassiopeia-color-primary: #{$alternative-color-primary};
diff --git a/build/media_source/templates/site/cassiopeia/scss/global/colors_standard.scss b/media_source/templates/site/cassiopeia/scss/global/colors_standard.scss
similarity index 88%
rename from build/media_source/templates/site/cassiopeia/scss/global/colors_standard.scss
rename to media_source/templates/site/cassiopeia/scss/global/colors_standard.scss
index 3b72dbad656..c968cc56d60 100644
--- a/build/media_source/templates/site/cassiopeia/scss/global/colors_standard.scss
+++ b/media_source/templates/site/cassiopeia/scss/global/colors_standard.scss
@@ -1,6 +1,6 @@
// Variables, Functions and Mixins
@import "../tools/tools";
-@import "../../../../../../../media/vendor/bootstrap/scss/functions";
+@import "../../../../../../media/vendor/bootstrap/scss/functions";
:root {
--cassiopeia-color-primary: #{$standard-color-primary};
diff --git a/build/media_source/templates/site/cassiopeia/scss/global/fonts-local_roboto.scss b/media_source/templates/site/cassiopeia/scss/global/fonts-local_roboto.scss
similarity index 75%
rename from build/media_source/templates/site/cassiopeia/scss/global/fonts-local_roboto.scss
rename to media_source/templates/site/cassiopeia/scss/global/fonts-local_roboto.scss
index 1e11feb32bc..0c2dbe8e65a 100644
--- a/build/media_source/templates/site/cassiopeia/scss/global/fonts-local_roboto.scss
+++ b/media_source/templates/site/cassiopeia/scss/global/fonts-local_roboto.scss
@@ -1,6 +1,6 @@
// Fonts
$roboto-font-path: "../../../../../vendor/roboto-fontface/fonts" !default;
-@import "../../../../../../../media/vendor/roboto-fontface/scss/roboto/sass/roboto-fontface";
+@import "../../../../../../media/vendor/roboto-fontface/scss/roboto/sass/roboto-fontface";
:root {
--cassiopeia-font-family-body: "Roboto", sans-serif;
diff --git a/build/media_source/templates/site/cassiopeia/scss/offline.scss b/media_source/templates/site/cassiopeia/scss/offline.scss
similarity index 95%
rename from build/media_source/templates/site/cassiopeia/scss/offline.scss
rename to media_source/templates/site/cassiopeia/scss/offline.scss
index 69376dfdc5d..b7b2c39161e 100644
--- a/build/media_source/templates/site/cassiopeia/scss/offline.scss
+++ b/media_source/templates/site/cassiopeia/scss/offline.scss
@@ -1,5 +1,5 @@
// Bootstrap functions
-@import "../../../../../../media/vendor/bootstrap/scss/functions";
+@import "../../../../../media/vendor/bootstrap/scss/functions";
// Variables, Functions and Mixins
@import "tools/tools";
diff --git a/build/media_source/templates/site/cassiopeia/scss/system/fields/calendar.scss b/media_source/templates/site/cassiopeia/scss/system/fields/calendar.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/system/fields/calendar.scss
rename to media_source/templates/site/cassiopeia/scss/system/fields/calendar.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/system/searchtools/searchtools.scss b/media_source/templates/site/cassiopeia/scss/system/searchtools/searchtools.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/system/searchtools/searchtools.scss
rename to media_source/templates/site/cassiopeia/scss/system/searchtools/searchtools.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/template-rtl.scss b/media_source/templates/site/cassiopeia/scss/template-rtl.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/template-rtl.scss
rename to media_source/templates/site/cassiopeia/scss/template-rtl.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/template.scss b/media_source/templates/site/cassiopeia/scss/template.scss
similarity index 71%
rename from build/media_source/templates/site/cassiopeia/scss/template.scss
rename to media_source/templates/site/cassiopeia/scss/template.scss
index 97ff07e477c..fa8ca715d43 100644
--- a/build/media_source/templates/site/cassiopeia/scss/template.scss
+++ b/media_source/templates/site/cassiopeia/scss/template.scss
@@ -1,20 +1,20 @@
// Bootstrap functions
-@import "../../../../../../media/vendor/bootstrap/scss/functions";
+@import "../../../../../media/vendor/bootstrap/scss/functions";
@import "tools/variables/variables";
-@import "../../../../../../media/vendor/bootstrap/scss/variables";
-@import "../../../../../../media/vendor/bootstrap/scss/variables-dark";
-@import "../../../../../../media/vendor/bootstrap/scss/maps";
-@import "../../../../../../media/vendor/bootstrap/scss/mixins";
-@import "../../../../../../media/vendor/bootstrap/scss/utilities";
+@import "../../../../../media/vendor/bootstrap/scss/variables";
+@import "../../../../../media/vendor/bootstrap/scss/variables-dark";
+@import "../../../../../media/vendor/bootstrap/scss/maps";
+@import "../../../../../media/vendor/bootstrap/scss/mixins";
+@import "../../../../../media/vendor/bootstrap/scss/utilities";
// Variables, Functions and Mixins
@import "tools/tools";
// Bootstrap
-@import "../../../../../../media/vendor/bootstrap/scss/bootstrap";
+@import "../../../../../media/vendor/bootstrap/scss/bootstrap";
// jQuery Minicolors
-@import "../../../../../../media/system/scss/jquery-minicolors";
+@import "../../../../../media/system/scss/jquery-minicolors";
// Blocks
@import "blocks/global"; // Leave this first
diff --git a/build/media_source/templates/site/cassiopeia/scss/tools/_tools.scss b/media_source/templates/site/cassiopeia/scss/tools/_tools.scss
similarity index 59%
rename from build/media_source/templates/site/cassiopeia/scss/tools/_tools.scss
rename to media_source/templates/site/cassiopeia/scss/tools/_tools.scss
index 9d37de1a8b1..6ebe99adcf0 100644
--- a/build/media_source/templates/site/cassiopeia/scss/tools/_tools.scss
+++ b/media_source/templates/site/cassiopeia/scss/tools/_tools.scss
@@ -1,5 +1,5 @@
// Vendor
-@import "../../../../../../../media/vendor/bootstrap/scss/functions";
+@import "../../../../../../media/vendor/bootstrap/scss/functions";
// Variables
diff --git a/build/media_source/templates/site/cassiopeia/scss/tools/functions/_max-width.scss b/media_source/templates/site/cassiopeia/scss/tools/functions/_max-width.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/tools/functions/_max-width.scss
rename to media_source/templates/site/cassiopeia/scss/tools/functions/_max-width.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/tools/variables/_variables.scss b/media_source/templates/site/cassiopeia/scss/tools/variables/_variables.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/tools/variables/_variables.scss
rename to media_source/templates/site/cassiopeia/scss/tools/variables/_variables.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/vendor/_awesomplete.scss b/media_source/templates/site/cassiopeia/scss/vendor/_awesomplete.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/vendor/_awesomplete.scss
rename to media_source/templates/site/cassiopeia/scss/vendor/_awesomplete.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/vendor/_dragula.scss b/media_source/templates/site/cassiopeia/scss/vendor/_dragula.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/vendor/_dragula.scss
rename to media_source/templates/site/cassiopeia/scss/vendor/_dragula.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/vendor/_minicolors.scss b/media_source/templates/site/cassiopeia/scss/vendor/_minicolors.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/vendor/_minicolors.scss
rename to media_source/templates/site/cassiopeia/scss/vendor/_minicolors.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/vendor/_tinymce.scss b/media_source/templates/site/cassiopeia/scss/vendor/_tinymce.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/vendor/_tinymce.scss
rename to media_source/templates/site/cassiopeia/scss/vendor/_tinymce.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_buttons.scss b/media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_buttons.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_buttons.scss
rename to media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_buttons.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_collapse.scss b/media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_collapse.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_collapse.scss
rename to media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_collapse.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_custom-forms.scss b/media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_custom-forms.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_custom-forms.scss
rename to media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_custom-forms.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_dropdown.scss b/media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_dropdown.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_dropdown.scss
rename to media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_dropdown.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_forms.scss b/media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_forms.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_forms.scss
rename to media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_forms.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_lists.scss b/media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_lists.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_lists.scss
rename to media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_lists.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_modal.scss b/media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_modal.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_modal.scss
rename to media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_modal.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_nav.scss b/media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_nav.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_nav.scss
rename to media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_nav.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_pagination.scss b/media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_pagination.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_pagination.scss
rename to media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_pagination.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_table.scss b/media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_table.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_table.scss
rename to media_source/templates/site/cassiopeia/scss/vendor/bootstrap/_table.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/vendor/choicesjs/choices.scss b/media_source/templates/site/cassiopeia/scss/vendor/choicesjs/choices.scss
similarity index 89%
rename from build/media_source/templates/site/cassiopeia/scss/vendor/choicesjs/choices.scss
rename to media_source/templates/site/cassiopeia/scss/vendor/choicesjs/choices.scss
index a41bdd5c4db..afac338e8a8 100644
--- a/build/media_source/templates/site/cassiopeia/scss/vendor/choicesjs/choices.scss
+++ b/media_source/templates/site/cassiopeia/scss/vendor/choicesjs/choices.scss
@@ -1,10 +1,10 @@
-@import "../../../../../../../../media/vendor/bootstrap/scss/functions";
-@import "../../../../../../../../media/templates/site/cassiopeia/scss/tools/variables/variables";
-@import "../../../../../../../../media/vendor/bootstrap/scss/variables";
-@import "../../../../../../../../media/vendor/bootstrap/scss/mixins";
+@import "../../../../../../../media/vendor/bootstrap/scss/functions";
+@import "../../../../../../../media/templates/site/cassiopeia/scss/tools/variables/variables";
+@import "../../../../../../../media/vendor/bootstrap/scss/variables";
+@import "../../../../../../../media/vendor/bootstrap/scss/mixins";
// choices.js
-@import "../../../../../../../../media/vendor/choicesjs/scss/choices";
+@import "../../../../../../../media/vendor/choicesjs/scss/choices";
// Cassiopea Variables, Functions and Mixins
@import "../../tools/tools";
diff --git a/build/media_source/templates/site/cassiopeia/scss/vendor/joomla-custom-elements/joomla-alert.scss b/media_source/templates/site/cassiopeia/scss/vendor/joomla-custom-elements/joomla-alert.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/vendor/joomla-custom-elements/joomla-alert.scss
rename to media_source/templates/site/cassiopeia/scss/vendor/joomla-custom-elements/joomla-alert.scss
diff --git a/build/media_source/templates/site/cassiopeia/scss/vendor/metismenu/_metismenu.scss b/media_source/templates/site/cassiopeia/scss/vendor/metismenu/_metismenu.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia/scss/vendor/metismenu/_metismenu.scss
rename to media_source/templates/site/cassiopeia/scss/vendor/metismenu/_metismenu.scss
diff --git a/build/media_source/templates/site/cassiopeia_extended/images/template_preview.png b/media_source/templates/site/cassiopeia_extended/images/template_preview.png
similarity index 100%
rename from build/media_source/templates/site/cassiopeia_extended/images/template_preview.png
rename to media_source/templates/site/cassiopeia_extended/images/template_preview.png
diff --git a/build/media_source/templates/site/cassiopeia_extended/images/template_thumbnail.png b/media_source/templates/site/cassiopeia_extended/images/template_thumbnail.png
similarity index 100%
rename from build/media_source/templates/site/cassiopeia_extended/images/template_thumbnail.png
rename to media_source/templates/site/cassiopeia_extended/images/template_thumbnail.png
diff --git a/build/media_source/templates/site/cassiopeia_extended/scss/global/colors.scss b/media_source/templates/site/cassiopeia_extended/scss/global/colors.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia_extended/scss/global/colors.scss
rename to media_source/templates/site/cassiopeia_extended/scss/global/colors.scss
diff --git a/build/media_source/templates/site/cassiopeia_extended/scss/global/fonts.scss b/media_source/templates/site/cassiopeia_extended/scss/global/fonts.scss
similarity index 100%
rename from build/media_source/templates/site/cassiopeia_extended/scss/global/fonts.scss
rename to media_source/templates/site/cassiopeia_extended/scss/global/fonts.scss
diff --git a/media_source/vendor/bootstrap/builder.mjs b/media_source/vendor/bootstrap/builder.mjs
new file mode 100644
index 00000000000..363b1b084b3
--- /dev/null
+++ b/media_source/vendor/bootstrap/builder.mjs
@@ -0,0 +1,150 @@
+/**
+ * Assets Builder
+ */
+import fs from 'node:fs';
+import fsp from 'node:fs/promises';
+import path from 'node:path';
+import { rollup } from 'rollup';
+import { nodeResolve } from '@rollup/plugin-node-resolve';
+import replace from '@rollup/plugin-replace';
+import { babel } from '@rollup/plugin-babel';
+import DefaultModuleBuilder from '../../../build/build-modules-js/builder/default-module-builder.mjs';
+import { resolvePackageFile } from '../../../build/build-modules-js/utils/resolve-package.mjs';
+import { minifyJSContent } from '../../../build/build-modules-js/javascript/js-handle.mjs';
+
+const minifyBootstrapModule = async (targetFile, code) => {
+ const code2 = code
+ .replace('./popper.js', './popper.min.js')
+ .replace('./dom.js', './dom.min.js');
+
+ return minifyJSContent(code2).then((jsMin) => {
+ return fsp.writeFile(
+ targetFile.replace('.js', '.min.js'),
+ jsMin,
+ { encoding: 'utf8', mode: 0o644 }
+ );
+ });
+};
+
+const compileBootstrapJS = async (basePath, targetPath) => {
+ const modulePathJson = resolvePackageFile(path.join('bootstrap', 'package.json'));
+
+ if (!modulePathJson) {
+ throw new Error(`Package "bootstrap" not found`);
+ }
+
+ const moduleOptions = JSON.parse(fs.readFileSync(modulePathJson, { encoding: 'utf8' }));
+ const modulePathBase = path.dirname(modulePathJson);
+ const domImports = fs.readdirSync(path.join(modulePathBase, 'js/src/dom'));
+ const utilImports = fs.readdirSync(path.join(modulePathBase, 'js/src/util'));
+ const bsVersion = moduleOptions.version;
+
+ return rollup({
+ input: path.join(basePath, 'js', 'index.es6.js'),
+ plugins: [
+ nodeResolve(),
+ replace({
+ preventAssignment: true,
+ 'process.env.NODE_ENV': "'production'",
+ }),
+ babel({
+ exclude: 'node_modules/core-js/**',
+ babelHelpers: 'bundled',
+ babelrc: false,
+ presets: [
+ [
+ '@babel/preset-env',
+ {
+ targets: {
+ browsers: ['> 1%', 'not op_mini all'],
+ },
+ },
+ ],
+ ],
+ }),
+ {
+ name: 'bootstrap-version-plugin',
+ renderChunk(code) {
+ return code
+ .replace('./popper.js', `./popper.js?${bsVersion}`)
+ .replace('./dom.js', `./dom.js?${bsVersion}`);
+ }
+ }
+ ],
+ }).then((build) => {
+ return build.write({
+ format: 'es',
+ sourcemap: false,
+ dir: path.join(targetPath, 'js'),
+ chunkFileNames: '[name].js',
+ manualChunks: {
+ alert: ['media_source/vendor/bootstrap/js/alert.es6.js'],
+ button: ['media_source/vendor/bootstrap/js/button.es6.js'],
+ carousel: ['media_source/vendor/bootstrap/js/carousel.es6.js'],
+ collapse: ['media_source/vendor/bootstrap/js/collapse.es6.js'],
+ dropdown: ['media_source/vendor/bootstrap/js/dropdown.es6.js'],
+ modal: ['media_source/vendor/bootstrap/js/modal.es6.js'],
+ offcanvas: ['media_source/vendor/bootstrap/js/offcanvas.es6.js'],
+ popover: ['media_source/vendor/bootstrap/js/popover.es6.js'],
+ scrollspy: ['media_source/vendor/bootstrap/js/scrollspy.es6.js'],
+ tab: ['media_source/vendor/bootstrap/js/tab.es6.js'],
+ toast: ['media_source/vendor/bootstrap/js/toast.es6.js'],
+ popper: ['@popperjs/core'],
+ dom: [
+ 'node_modules/bootstrap/js/src/base-component.js',
+ ...domImports.map((file) => `node_modules/bootstrap/js/src/dom/${file}`),
+ ...utilImports.map((file) => `node_modules/bootstrap/js/src/util/${file}`),
+ ],
+ },
+ }).then((result) => {
+ fs.unlinkSync(path.join(targetPath, 'js', 'index.es6.js'));
+
+ const promises = [];
+ result.output.forEach((chunk) => {
+ if (chunk.fileName === 'index.es6.js') return;
+
+ promises.push(minifyBootstrapModule(
+ path.join(targetPath, 'js', chunk.fileName),
+ chunk.code
+ ));
+ });
+
+ return Promise.all(promises).then(() => build.close());
+ });
+ });
+}
+
+export default class BootstrapModuleBuilder extends DefaultModuleBuilder
+{
+ /**
+ * Remove files on target location
+ * @returns { Promise }
+ */
+ async clear() {
+ // Do not clear whole target because it is mix of customized JS and source files from the bootstrap package.
+ // Remove only related JS
+ const jsPath = path.join(this.targetPath, 'js');
+
+ if (!fs.existsSync(jsPath)) {
+ return;
+ }
+
+ return fsp.rm(jsPath, { recursive: true });
+ }
+
+ /**
+ * Process CSS files
+ * @returns { Promise }
+ */
+ async css() {
+ // Nothing to do here
+ }
+
+ /**
+ * Process JavaScript files and Modules
+ * @returns { Promise }
+ */
+ async js() {
+ return compileBootstrapJS(this.basePath, this.targetPath);
+ }
+};
diff --git a/build/media_source/vendor/bootstrap/js/alert.es6.js b/media_source/vendor/bootstrap/js/alert.es6.js
similarity index 100%
rename from build/media_source/vendor/bootstrap/js/alert.es6.js
rename to media_source/vendor/bootstrap/js/alert.es6.js
diff --git a/build/media_source/vendor/bootstrap/js/button.es6.js b/media_source/vendor/bootstrap/js/button.es6.js
similarity index 100%
rename from build/media_source/vendor/bootstrap/js/button.es6.js
rename to media_source/vendor/bootstrap/js/button.es6.js
diff --git a/build/media_source/vendor/bootstrap/js/carousel.es6.js b/media_source/vendor/bootstrap/js/carousel.es6.js
similarity index 100%
rename from build/media_source/vendor/bootstrap/js/carousel.es6.js
rename to media_source/vendor/bootstrap/js/carousel.es6.js
diff --git a/build/media_source/vendor/bootstrap/js/collapse.es6.js b/media_source/vendor/bootstrap/js/collapse.es6.js
similarity index 100%
rename from build/media_source/vendor/bootstrap/js/collapse.es6.js
rename to media_source/vendor/bootstrap/js/collapse.es6.js
diff --git a/build/media_source/vendor/bootstrap/js/dropdown.es6.js b/media_source/vendor/bootstrap/js/dropdown.es6.js
similarity index 100%
rename from build/media_source/vendor/bootstrap/js/dropdown.es6.js
rename to media_source/vendor/bootstrap/js/dropdown.es6.js
diff --git a/build/media_source/vendor/bootstrap/js/index.es6.js b/media_source/vendor/bootstrap/js/index.es6.js
similarity index 100%
rename from build/media_source/vendor/bootstrap/js/index.es6.js
rename to media_source/vendor/bootstrap/js/index.es6.js
diff --git a/build/media_source/vendor/bootstrap/js/modal.es6.js b/media_source/vendor/bootstrap/js/modal.es6.js
similarity index 100%
rename from build/media_source/vendor/bootstrap/js/modal.es6.js
rename to media_source/vendor/bootstrap/js/modal.es6.js
diff --git a/build/media_source/vendor/bootstrap/js/offcanvas.es6.js b/media_source/vendor/bootstrap/js/offcanvas.es6.js
similarity index 100%
rename from build/media_source/vendor/bootstrap/js/offcanvas.es6.js
rename to media_source/vendor/bootstrap/js/offcanvas.es6.js
diff --git a/build/media_source/vendor/bootstrap/js/popover.es6.js b/media_source/vendor/bootstrap/js/popover.es6.js
similarity index 100%
rename from build/media_source/vendor/bootstrap/js/popover.es6.js
rename to media_source/vendor/bootstrap/js/popover.es6.js
diff --git a/build/media_source/vendor/bootstrap/js/scrollspy.es6.js b/media_source/vendor/bootstrap/js/scrollspy.es6.js
similarity index 100%
rename from build/media_source/vendor/bootstrap/js/scrollspy.es6.js
rename to media_source/vendor/bootstrap/js/scrollspy.es6.js
diff --git a/build/media_source/vendor/bootstrap/js/tab.es6.js b/media_source/vendor/bootstrap/js/tab.es6.js
similarity index 100%
rename from build/media_source/vendor/bootstrap/js/tab.es6.js
rename to media_source/vendor/bootstrap/js/tab.es6.js
diff --git a/build/media_source/vendor/bootstrap/js/toast.es6.js b/media_source/vendor/bootstrap/js/toast.es6.js
similarity index 100%
rename from build/media_source/vendor/bootstrap/js/toast.es6.js
rename to media_source/vendor/bootstrap/js/toast.es6.js
diff --git a/media_source/vendor/builder.mjs b/media_source/vendor/builder.mjs
new file mode 100644
index 00000000000..bb73b9f24f3
--- /dev/null
+++ b/media_source/vendor/builder.mjs
@@ -0,0 +1,244 @@
+/**
+ * Assets Builder
+ */
+import path from 'node:path';
+import fsp from "node:fs/promises";
+import fs from "node:fs";
+
+import pkgOptions from '../../package.json' with { type: 'json' };
+import buildSettings from '../../build/build-modules-js/settings.json' with { type: 'json' };
+import DefaultModuleBuilder from '../../build/build-modules-js/builder/default-module-builder.mjs';
+import { resolvePackageFile } from '../../build/build-modules-js/utils/resolve-package.mjs';
+import { handleJSFile } from '../../build/build-modules-js/javascript/js-handle.mjs';
+
+/**
+ * Copy package files.
+ *
+ * @param {Object} vendor Vendor info from settings.json
+ * @param {String} packageName Original package name. This may be different from vendor.name.
+ * @param {String} mediaVendorPath Full path to /media/vendor
+ *
+ * @returns { Promise }
+ */
+const copyVendorFiles = async (vendor, packageName, mediaVendorPath) => {
+ const vendorName = vendor.name || packageName;
+ const modulePathJson = resolvePackageFile(path.join(packageName, 'package.json'));
+
+ if (!modulePathJson) {
+ throw new Error(`Package "${packageName}" not found`);
+ }
+
+ const modulePathRoot = path.dirname(modulePathJson);
+ const modulePathTarget = path.join(mediaVendorPath, vendorName);
+
+ // Make sure target folder exists
+ if (!fs.existsSync(modulePathTarget)) {
+ fs.mkdirSync(modulePathTarget);
+ }
+
+ // Check files that need to copy
+ const promises = [];
+ ['js', 'css', 'filesExtra'].forEach((type) => {
+ if (!vendor[type]) return;
+ const files = vendor[type];
+
+ for (const srcFile in files) {
+ promises.push(fsp.cp(
+ path.join(modulePathRoot, srcFile),
+ path.join(modulePathTarget, files[srcFile]),
+ { preserveTimestamps: true, recursive: true }
+ ));
+ }
+ });
+
+ // Copy the license if exists
+ const licensePath = vendor.licenseFilename ? resolvePackageFile(path.join(packageName, vendor.licenseFilename)) : false;
+ if (licensePath) {
+ promises.push(fsp.cp(licensePath, path.join(modulePathTarget, vendor.licenseFilename), { preserveTimestamps: true }));
+ }
+
+ return Promise.all(promises);
+};
+
+/**
+ * Create Asset entries for the Registry
+ *
+ * @param {Object} vendor Vendor info from settings.json
+ * @param {String} packageName Original package name. This may be different from vendor.name.
+ *
+ * @returns { Promise<[]> } List of asset entries for the vendor.
+ */
+const prepareVendorAssets = async (vendor, packageName) => {
+ if (!vendor.provideAssets || !vendor.provideAssets.length) {
+ return [];
+ }
+
+ const vendorName = vendor.name || packageName;
+ const modulePathJson = resolvePackageFile(path.join(packageName, 'package.json'));
+
+ if (!modulePathJson) {
+ throw new Error(`Package "${packageName}" not found`);
+ }
+
+ const moduleOptions = await import(modulePathJson, { with: { type: 'json' } });
+
+ const entries = [];
+ vendor.provideAssets.forEach((assetInfo) => {
+ const entryBase = {
+ package: packageName,
+ name: assetInfo.name || vendorName,
+ version: moduleOptions.default.version,
+ type: assetInfo.type,
+ };
+
+ const entry = Object.assign(assetInfo, entryBase);
+
+ // 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.startsWith('http://') && !itemPath.startsWith('https://') && !itemPath.startsWith('//')) {
+ itemPath = `vendor/${vendorName}/${itemPath}`;
+ }
+
+ entry.uri = itemPath;
+ }
+
+ entries.push(entry);
+ });
+
+ return entries;
+};
+
+export default class VendorModuleBuilder extends DefaultModuleBuilder
+{
+ /**
+ * Copy all vendor files according to Joomla's specs from build/settings.json
+ * And create vendor/joomla.asset.json registry.
+ *
+ * @returns { Promise }
+ */
+ async copy() {
+ const modulesSrcBasePath = path.join(process.cwd(), 'node_modules');
+
+ // This should never happen
+ if (!fs.existsSync(modulesSrcBasePath)) {
+ throw new Error(`Modules source "${modulesSrcBasePath}" not found`);
+ }
+
+ // Prepare target
+ if (!fs.existsSync(this.targetPath)) {
+ fs.mkdirSync(this.targetPath, { recursive: true, mode: 0o755});
+ }
+
+ const promises = [];
+ // Store entries as object to keep sorting steady
+ const assets = {};
+
+ // Loop the vendors
+ Object.keys(buildSettings.settings.vendors).forEach((packageName) => {
+ const vendor = buildSettings.settings.vendors[packageName];
+ const vendorName = vendor.name || packageName;
+ // Keep sorting steady
+ assets[vendorName] = [];
+
+ promises.push(
+ copyVendorFiles(vendor, packageName, this.targetPath)
+ .then(() => prepareVendorAssets(vendor, packageName))
+ .then((entries) => {
+ if (!entries.length) return;
+ assets[vendorName] = entries;
+ })
+ );
+ });
+
+ // Prepare registry data
+ const registry = {
+ $schema: 'https://developer.joomla.org/schemas/json-schema/web_assets.json',
+ name: pkgOptions.name,
+ version: pkgOptions.version,
+ description: pkgOptions.description,
+ license: pkgOptions.license,
+ assets: [],
+ };
+
+ return Promise.all(promises).then(() => {
+ // Finalize and save the Registry file
+ const assetsArray = [];
+
+ // Transform from Object to List
+ Object.keys(assets).forEach((vendorName) => {
+ assetsArray.push(...assets[vendorName]);
+ });
+
+ registry.assets = assetsArray;
+
+ return fsp.writeFile(
+ path.join(this.targetPath, 'joomla.asset.json'),
+ JSON.stringify(registry, null, 2),
+ { encoding: 'utf8', mode: 0o644 }
+ );
+ });
+ }
+
+ /**
+ * Process CSS files
+ * @returns { Promise }
+ */
+ async css() {
+ // Nothing to do here
+ }
+
+ /**
+ * Process JavaScript files and Modules
+ * @returns { Promise }
+ */
+ async js() {
+ // Minify few non minified files
+ const folders = [
+ 'diff/js',
+ 'es-module-shims/js',
+ 'qrcode/js',
+ ];
+
+ const promises = [];
+ folders.forEach((folder) => {
+ const basePath = path.join(this.targetPath, folder);
+
+ promises.push(
+ fsp.readdir(basePath, { recursive: false, withFileTypes: true })
+ .then((files) => {
+ const jsFiles = [];
+
+ files.forEach((file) => {
+ if (!file.isFile()) return;
+
+ const baseName = file.name;
+ const ext = path.extname(baseName);
+ const fullSrcPath = path.join(file.parentPath, file.name);
+
+ if (ext !== '.js' || baseName.endsWith('.min.js')) return;
+
+ jsFiles.push(handleJSFile(
+ fullSrcPath,
+ fullSrcPath
+ ));
+ });
+
+ return Promise.all(jsFiles);
+ })
+ );
+ });
+
+ return Promise.all(promises);
+ }
+
+ /**
+ * Watch handler
+ * @returns { Promise }
+ */
+ async watch() {
+ throw new Error(`Watch is not implemented for [${this.name}]`);
+ }
+};
diff --git a/media_source/vendor/jquery/builder.mjs b/media_source/vendor/jquery/builder.mjs
new file mode 100644
index 00000000000..a36fc93e817
--- /dev/null
+++ b/media_source/vendor/jquery/builder.mjs
@@ -0,0 +1,19 @@
+/**
+ * Assets Builder
+ */
+import fs from "node:fs";
+import path from "node:path";
+import fsp from "node:fs/promises";
+
+import DefaultModuleBuilder from '../../../build/build-modules-js/builder/default-module-builder.mjs';
+
+export default class VendorJQueryModuleBuilder extends DefaultModuleBuilder
+{
+ /**
+ * Remove files on target location
+ * @returns { Promise }
+ */
+ async clear() {
+ // Bypass clear, it is conflicting with Vendor builder
+ }
+};
diff --git a/media_source/vendor/jquery/js/jquery-noconflict.es6.js b/media_source/vendor/jquery/js/jquery-noconflict.es6.js
new file mode 100644
index 00000000000..7641941cf21
--- /dev/null
+++ b/media_source/vendor/jquery/js/jquery-noconflict.es6.js
@@ -0,0 +1 @@
+window.$ = jQuery.noConflict();
diff --git a/media_source/vendor/short-and-sweet/builder.mjs b/media_source/vendor/short-and-sweet/builder.mjs
new file mode 100644
index 00000000000..58b87a32c09
--- /dev/null
+++ b/media_source/vendor/short-and-sweet/builder.mjs
@@ -0,0 +1,26 @@
+/**
+ * Assets Builder
+ */
+import fs from "node:fs";
+import fsp from "node:fs/promises";
+import path from "node:path";
+
+import DefaultModuleBuilder from '../../../build/build-modules-js/builder/default-module-builder.mjs';
+
+export default class ShortAndSweetModuleBuilder extends DefaultModuleBuilder
+{
+ /**
+ * Remove files on target location
+ * @returns { Promise }
+ */
+ async clear() {
+ // Remove only custom files from this builder and leave vendor files
+ const jsPath = path.join(this.targetPath, 'js');
+
+ if (!fs.existsSync(jsPath)) {
+ return;
+ }
+
+ return fsp.rm(jsPath, { recursive: true });
+ }
+};
diff --git a/build/media_source/vendor/short-and-sweet/js/short-and-sweet.es6.js b/media_source/vendor/short-and-sweet/js/short-and-sweet.es6.js
similarity index 100%
rename from build/media_source/vendor/short-and-sweet/js/short-and-sweet.es6.js
rename to media_source/vendor/short-and-sweet/js/short-and-sweet.es6.js
diff --git a/build/media_source/vendor/tinymce/templates/layout1.html b/media_source/vendor/tinymce/templates/layout1.html
similarity index 100%
rename from build/media_source/vendor/tinymce/templates/layout1.html
rename to media_source/vendor/tinymce/templates/layout1.html
diff --git a/build/media_source/vendor/tinymce/templates/snippet1.html b/media_source/vendor/tinymce/templates/snippet1.html
similarity index 100%
rename from build/media_source/vendor/tinymce/templates/snippet1.html
rename to media_source/vendor/tinymce/templates/snippet1.html
diff --git a/modules/mod_articles/src/Helper/ArticlesHelper.php b/modules/mod_articles/src/Helper/ArticlesHelper.php
index 8c0e7914a1d..9a31f838fa9 100644
--- a/modules/mod_articles/src/Helper/ArticlesHelper.php
+++ b/modules/mod_articles/src/Helper/ArticlesHelper.php
@@ -343,9 +343,13 @@ public function getArticles(Registry $params, SiteApplication $app)
'params' => $item->params,
];
- // Extra content from events
+ // onContentPrepare plugins work on $item->text
+ if (!isset($item->text)) {
+ $item->text = $item->introtext . ' ' . $item->fulltext;
+ }
$contentEvents = [
+ 'onContentPrepare' => new Content\ContentPrepareEvent('onContentPrepare', $contentEventArguments),
'afterDisplayTitle' => new Content\AfterTitleEvent('onContentAfterTitle', $contentEventArguments),
'beforeDisplayContent' => new Content\BeforeDisplayEvent('onContentBeforeDisplay', $contentEventArguments),
'afterDisplayContent' => new Content\AfterDisplayEvent('onContentAfterDisplay', $contentEventArguments),
@@ -357,6 +361,7 @@ public function getArticles(Registry $params, SiteApplication $app)
$item->event->{$resultKey} = $results ? trim(implode("\n", $results)) : '';
}
} else {
+ $item->event->onContentPrepare = '';
$item->event->afterDisplayTitle = '';
$item->event->beforeDisplayContent = '';
$item->event->afterDisplayContent = '';
diff --git a/modules/mod_articles/tmpl/default_items.php b/modules/mod_articles/tmpl/default_items.php
index bb807f0fb59..57d84087c43 100644
--- a/modules/mod_articles/tmpl/default_items.php
+++ b/modules/mod_articles/tmpl/default_items.php
@@ -42,7 +42,7 @@
title, ENT_COMPAT, 'UTF-8', false); ?>
- title; ?>
+ title, ENT_QUOTES, 'UTF-8'); ?>
>
@@ -73,7 +73,7 @@
displayAuthorName) : ?>
'icon-user icon-fw']); ?>
- displayAuthorName; ?>
+ displayAuthorName, ENT_QUOTES, 'UTF-8'); ?>
@@ -82,10 +82,10 @@
'icon-folder-open icon-fw']); ?>
displayCategoryLink) : ?>
- displayCategoryTitle; ?>
+ displayCategoryTitle, ENT_QUOTES, 'UTF-8'); ?>
- displayCategoryTitle; ?>
+ displayCategoryTitle, ENT_QUOTES, 'UTF-8'); ?>
@@ -93,7 +93,7 @@
displayDate) : ?>
'icon-calendar icon-fw']); ?>
- displayDate; ?>
+ displayDate, ENT_QUOTES, 'UTF-8'); ?>
diff --git a/modules/mod_articles/tmpl/default_titles.php b/modules/mod_articles/tmpl/default_titles.php
index dcabe184abe..7e570c09f5c 100644
--- a/modules/mod_articles/tmpl/default_titles.php
+++ b/modules/mod_articles/tmpl/default_titles.php
@@ -21,7 +21,7 @@
active ? 'class="' . $item->active . '" ' : ''; ?>href="link; ?>" itemprop="url">
- title; ?>
+ title, ENT_QUOTES, 'UTF-8'); ?>
diff --git a/modules/mod_articles_categories/tmpl/default_items.php b/modules/mod_articles_categories/tmpl/default_items.php
index c959d2ccca9..0adb6d345f5 100644
--- a/modules/mod_articles_categories/tmpl/default_items.php
+++ b/modules/mod_articles_categories/tmpl/default_items.php
@@ -25,7 +25,7 @@
echo ' class="active"';
} ?>>
- title; ?>
+ title, ENT_QUOTES, 'UTF-8'); ?>
get('numitems')) : ?>
(numitems; ?>)
diff --git a/modules/mod_articles_category/tmpl/default_items.php b/modules/mod_articles_category/tmpl/default_items.php
index f4e499cddec..52095b8f765 100644
--- a/modules/mod_articles_category/tmpl/default_items.php
+++ b/modules/mod_articles_category/tmpl/default_items.php
@@ -23,7 +23,7 @@
title, ENT_COMPAT, 'UTF-8', false); ?>
- title; ?>
+ title, ENT_COMPAT, 'UTF-8'); ?>
displayHits) : ?>
@@ -34,18 +34,18 @@
get('show_author')) : ?>
- displayAuthorName; ?>
+ displayAuthorName, ENT_COMPAT, 'UTF-8'); ?>
displayCategoryTitle) : ?>
- (displayCategoryTitle; ?>)
+ (displayCategoryTitle, ENT_COMPAT, 'UTF-8'); ?>)
displayDate) : ?>
- displayDate; ?>
+ displayDate, ENT_COMPAT, 'UTF-8'); ?>
get('show_tags', 0) && $item->tags->itemTags) : ?>
@@ -67,13 +67,13 @@
alternative_readmore) : ?>
alternative_readmore; ?>
- title, $params->get('readmore_limit')); ?>
+ title, $params->get('readmore_limit'), false); ?>
get('show_readmore_title', 0)) : ?>
- title, $params->get('readmore_limit')); ?>
+ title, $params->get('readmore_limit'), false); ?>
get('show_readmore_title', 0)) : ?>
- title, $params->get('readmore_limit')); ?>
+ title, $params->get('readmore_limit'), false); ?>
diff --git a/modules/mod_articles_latest/tmpl/default.php b/modules/mod_articles_latest/tmpl/default.php
index f438151e4cd..4c339016998 100644
--- a/modules/mod_articles_latest/tmpl/default.php
+++ b/modules/mod_articles_latest/tmpl/default.php
@@ -20,7 +20,7 @@
- title; ?>
+ title, ENT_QUOTES, 'UTF-8'); ?>
diff --git a/modules/mod_articles_news/tmpl/_item.php b/modules/mod_articles_news/tmpl/_item.php
index 09cc05c84d4..d82362e1865 100644
--- a/modules/mod_articles_news/tmpl/_item.php
+++ b/modules/mod_articles_news/tmpl/_item.php
@@ -17,10 +17,10 @@
< class="newsflash-title">
link !== '' && $params->get('link_titles')) : ?>
- title; ?>
+ title, ENT_QUOTES, 'UTF-8'); ?>
- title; ?>
+ title, ENT_QUOTES, 'UTF-8'); ?>
>
@@ -36,7 +36,7 @@
); ?>
imageCaption)) : ?>
- imageCaption; ?>
+ imageCaption, ENT_QUOTES, 'UTF-8'); ?>
diff --git a/modules/mod_articles_popular/tmpl/default.php b/modules/mod_articles_popular/tmpl/default.php
index a3cf9ce24ea..3c5edcc27d0 100644
--- a/modules/mod_articles_popular/tmpl/default.php
+++ b/modules/mod_articles_popular/tmpl/default.php
@@ -23,7 +23,7 @@
- title; ?>
+ title, ENT_QUOTES, 'UTF-8'); ?>
diff --git a/modules/mod_related_items/tmpl/default.php b/modules/mod_related_items/tmpl/default.php
index fee02728356..bd8aee7b793 100644
--- a/modules/mod_related_items/tmpl/default.php
+++ b/modules/mod_related_items/tmpl/default.php
@@ -25,7 +25,7 @@
created, Text::_('DATE_FORMAT_LC4')) . ' - ';
} ?>
- title; ?>
+ title, ENT_QUOTES, 'UTF-8'); ?>
diff --git a/package-lock.json b/package-lock.json
index ed0026ddcd4..16c168c6138 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4764,9 +4764,9 @@
}
},
"node_modules/brace-expansion": {
- "version": "1.1.12",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
- "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "version": "1.1.13",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
+ "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -6795,9 +6795,9 @@
}
},
"node_modules/flatted": {
- "version": "3.3.4",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.4.tgz",
- "integrity": "sha512-3+mMldrTAPdta5kjX2G2J7iX4zxtnwpdA8Tr2ZSjkyPSanvbZAcy6flmtnXbEybHrDcU9641lxrMfFuUxVz9vA==",
+ "version": "3.4.2",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz",
+ "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==",
"license": "ISC"
},
"node_modules/focus-lock": {
@@ -7102,9 +7102,9 @@
}
},
"node_modules/glob/node_modules/brace-expansion": {
- "version": "5.0.4",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz",
- "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==",
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
+ "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -8772,9 +8772,9 @@
}
},
"node_modules/lodash": {
- "version": "4.17.23",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz",
- "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==",
+ "version": "4.18.1",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz",
+ "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==",
"dev": true,
"license": "MIT"
},
@@ -8918,9 +8918,9 @@
}
},
"node_modules/mailparser": {
- "version": "3.9.3",
- "resolved": "https://registry.npmjs.org/mailparser/-/mailparser-3.9.3.tgz",
- "integrity": "sha512-AnB0a3zROum6fLaa52L+/K2SoRJVyFDk78Ea6q1D0ofcZLxWEWDtsS1+OrVqKbV7r5dulKL/AwYQccFGAPpuYQ==",
+ "version": "3.9.6",
+ "resolved": "https://registry.npmjs.org/mailparser/-/mailparser-3.9.6.tgz",
+ "integrity": "sha512-EJYTDWMrOS1kddK1mTsRkrx2Ngh2nYsg54SRMWVVWGVEGbHH4tod8tqqU9hIRPgGQVboSjFubDn9cboSitbM3Q==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -8931,7 +8931,7 @@
"iconv-lite": "0.7.2",
"libmime": "5.3.7",
"linkify-it": "5.0.0",
- "nodemailer": "7.0.13",
+ "nodemailer": "8.0.4",
"punycode.js": "2.3.1",
"tlds": "1.261.0"
}
@@ -9031,9 +9031,9 @@
}
},
"node_modules/micromatch/node_modules/picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
+ "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -9202,9 +9202,9 @@
"license": "MIT"
},
"node_modules/nodemailer": {
- "version": "7.0.13",
- "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.13.tgz",
- "integrity": "sha512-PNDFSJdP+KFgdsG3ZzMXCgquO7I6McjY2vlqILjtJd0hy8wEvtugS9xKRF2NWlPNGxvLCXlTNIae4serI7dinw==",
+ "version": "8.0.4",
+ "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-8.0.4.tgz",
+ "integrity": "sha512-k+jf6N8PfQJ0Fe8ZhJlgqU5qJU44Lpvp2yvidH3vp1lPnVQMgi4yEEMPXg5eJS1gFIJTVq1NHBk7Ia9ARdSBdQ==",
"dev": true,
"license": "MIT-0",
"engines": {
@@ -9706,9 +9706,9 @@
"license": "ISC"
},
"node_modules/picomatch": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
- "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"dev": true,
"license": "MIT",
"engines": {
@@ -11155,14 +11155,14 @@
}
},
"node_modules/smtp-server": {
- "version": "3.18.1",
- "resolved": "https://registry.npmjs.org/smtp-server/-/smtp-server-3.18.1.tgz",
- "integrity": "sha512-zlUXA6n3HkO0jMyNNc2S67uw7DWHOoLU9vjPo5oW2c8ehJMpRlSumyw4riuvfWPfW/8mryd7ED5PVf4YVg8Y6w==",
+ "version": "3.18.3",
+ "resolved": "https://registry.npmjs.org/smtp-server/-/smtp-server-3.18.3.tgz",
+ "integrity": "sha512-bPEqRNHFYcb2s7kPIka3pkF//2V87miqGUy2bMm+CJu3zbRpePMLpF7sUAIUFcZgkUzDB7ivxe6zKgNrxsZ00w==",
"dev": true,
"license": "MIT-0",
"dependencies": {
"ipv6-normalize": "1.0.1",
- "nodemailer": "7.0.13",
+ "nodemailer": "8.0.4",
"punycode.js": "2.3.1"
},
"engines": {
diff --git a/package.json b/package.json
index 9edc90382fb..2805389120e 100644
--- a/package.json
+++ b/package.json
@@ -12,24 +12,17 @@
"npm": ">=10.1.0"
},
"scripts": {
- "build:js": "node build/build.mjs --compile-js",
- "build:css": "node build/build.mjs --compile-css",
- "build:bs5": "node build/build.mjs --compile-bs",
- "build:com_media": "node --env-file=./build/production.env build/build.mjs --com-media",
- "build:com_media:dev": "node --env-file=./build/development.env build/build.mjs --com-media",
- "build:com_workflow": "node --env-file=./build/production.env build/build.mjs --com-workflow",
- "build:com_workflow:dev": "node --env-file=./build/development.env build/build.mjs --com-workflow",
- "watch": "node build/build.mjs --watch",
- "watch:com_media": "node build/build.mjs --watch-com-media",
- "watch:com_Workflow": "node build/build.mjs --watch-com-workflow",
- "lint:js": "eslint --config build/eslint.config.mjs build administrator/components/com_media/resources/scripts",
+ "builders-list": "node --env-file=./build/production.env build/build.mjs builders-list",
+ "build": "node --env-file=./build/production.env build/build.mjs build",
+ "build:dev": "node --env-file=./build/development.env build/build.mjs build",
+ "watch": "node --env-file=./build/production.env build/build.mjs watch",
+ "watch:dev": "node --env-file=./build/development.env build/build.mjs watch",
+ "lint:js": "eslint --config build/eslint.config.mjs build/ media_source/",
"lint:testjs": "eslint --config build/eslint-tests.mjs tests/System",
- "lint:css": "stylelint --config build/.stylelintrc.json \"administrator/components/com_media/resources/**/*.scss\" \"administrator/templates/**/*.scss\" \"build/media_source/**/*.scss\" \"build/media_source/**/*.css\" \"templates/**/*.scss\" \"installation/template/**/*.scss\"",
- "install": "node build/build.mjs --prepare",
- "update": "node build/build.mjs --copy-assets && node build/build.mjs --build-pages && node build/build.mjs --compile-js && node build/build.mjs --compile-css && node build/build.mjs --compile-bs && node --env-file=./build/production.env build/build.mjs --com-media",
- "gzip": "node build/build.mjs --gzip",
- "cssversioning": "node build/build.mjs --cssversioning",
- "versioning": "node build/build.mjs --versioning",
+ "lint:css": "stylelint --config build/.stylelintrc.json \"administrator/templates/**/*.scss\" \"media_source/**/*.scss\" \"media_source/**/*.css\" \"templates/**/*.scss\" \"installation/template/**/*.scss\"",
+ "install": "node --env-file=./build/production.env build/build.mjs build -a",
+ "update": "node --env-file=./build/production.env build/build.mjs build -a",
+ "gzip": "node build/build.mjs build -a -t gzip",
"browserlist:update": "npx update-browserslist-db@latest",
"cypress:install": "cypress install",
"cypress:open": "cypress open --config-file cypress.config.mjs",
diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon
index 807c849722e..59f46752a93 100644
--- a/phpstan-baseline.neon
+++ b/phpstan-baseline.neon
@@ -576,7 +576,7 @@ parameters:
Catch thrown Exceptions instead of getError$#
'''
identifier: method.deprecated
- count: 18
+ count: 14
path: administrator/components/com_categories/src/Model/CategoryModel.php
-
@@ -610,7 +610,7 @@ parameters:
Throw an Exception instead of using setError$#
'''
identifier: method.deprecated
- count: 32
+ count: 26
path: administrator/components/com_categories/src/Model/CategoryModel.php
-
@@ -631,16 +631,6 @@ parameters:
count: 2
path: administrator/components/com_categories/src/Model/CategoryModel.php
- -
- message: '''
- #^Call to method triggerEvent\(\) of deprecated interface Joomla\\CMS\\Application\\EventAwareInterface\:
- 4\.3 will be removed in 7\.0
- This interface will be removed without replacement as the Joomla 3\.x compatibility layer will be removed$#
- '''
- identifier: method.deprecatedInterface
- count: 2
- path: administrator/components/com_categories/src/Model/CategoryModel.php
-
-
message: '''
#^Instantiation of deprecated class Joomla\\CMS\\UCM\\UCMType\:
@@ -1871,18 +1861,6 @@ parameters:
count: 1
path: administrator/components/com_finder/src/Indexer/Helper.php
- -
- message: '''
- #^Call to deprecated method getSession\(\) of class Joomla\\CMS\\Factory\:
- 4\.3 will be removed in 7\.0
- Use the session service in the DI container or get from the application object
- Example\:
- Factory\:\:getApplication\(\)\-\>getSession\(\);$#
- '''
- identifier: staticMethod.deprecated
- count: 2
- path: administrator/components/com_finder/src/Indexer/Indexer.php
-
-
message: '''
#^Call to method triggerEvent\(\) of deprecated interface Joomla\\CMS\\Application\\EventAwareInterface\:
@@ -2247,30 +2225,6 @@ parameters:
count: 1
path: administrator/components/com_finder/tmpl/filter/edit.php
- -
- message: '''
- #^Call to deprecated method getSession\(\) of class Joomla\\CMS\\Factory\:
- 4\.3 will be removed in 7\.0
- Use the session service in the DI container or get from the application object
- Example\:
- Factory\:\:getApplication\(\)\-\>getSession\(\);$#
- '''
- identifier: staticMethod.deprecated
- count: 1
- path: administrator/components/com_finder/tmpl/indexer/debug.php
-
- -
- message: '''
- #^Call to deprecated method getSession\(\) of class Joomla\\CMS\\Factory\:
- 4\.3 will be removed in 7\.0
- Use the session service in the DI container or get from the application object
- Example\:
- Factory\:\:getApplication\(\)\-\>getSession\(\);$#
- '''
- identifier: staticMethod.deprecated
- count: 1
- path: administrator/components/com_finder/tmpl/indexer/default.php
-
-
message: '''
#^Call to deprecated method getLanguage\(\) of class Joomla\\CMS\\Factory\:
@@ -2897,18 +2851,6 @@ parameters:
count: 1
path: administrator/components/com_joomlaupdate/tmpl/joomlaupdate/update.php
- -
- message: '''
- #^Call to deprecated method getSession\(\) of class Joomla\\CMS\\Factory\:
- 4\.3 will be removed in 7\.0
- Use the session service in the DI container or get from the application object
- Example\:
- Factory\:\:getApplication\(\)\-\>getSession\(\);$#
- '''
- identifier: staticMethod.deprecated
- count: 1
- path: administrator/components/com_joomlaupdate/tmpl/update/default.php
-
-
message: '''
#^Access to deprecated static property \$language of class Joomla\\CMS\\Factory\:
@@ -4109,7 +4051,7 @@ parameters:
Catch thrown Exceptions instead of getError$#
'''
identifier: method.deprecated
- count: 11
+ count: 7
path: administrator/components/com_modules/src/Model/ModuleModel.php
-
@@ -4154,7 +4096,7 @@ parameters:
Throw an Exception instead of using setError$#
'''
identifier: method.deprecated
- count: 14
+ count: 10
path: administrator/components/com_modules/src/Model/ModuleModel.php
-
@@ -4164,7 +4106,7 @@ parameters:
This interface will be removed without replacement as the Joomla 3\.x compatibility layer will be removed$#
'''
identifier: method.deprecatedInterface
- count: 4
+ count: 3
path: administrator/components/com_modules/src/Model/ModuleModel.php
-
@@ -4532,18 +4474,6 @@ parameters:
count: 1
path: administrator/components/com_postinstall/src/View/Messages/HtmlView.php
- -
- message: '''
- #^Call to deprecated method getSession\(\) of class Joomla\\CMS\\Factory\:
- 4\.3 will be removed in 7\.0
- Use the session service in the DI container or get from the application object
- Example\:
- Factory\:\:getApplication\(\)\-\>getSession\(\);$#
- '''
- identifier: staticMethod.deprecated
- count: 1
- path: administrator/components/com_postinstall/src/View/Messages/HtmlView.php
-
-
message: '#^Access to an undefined property Joomla\\Component\\Postinstall\\Administrator\\View\\Messages\\HtmlView\:\:\$eid\.$#'
identifier: property.notFound
@@ -4805,18 +4735,6 @@ parameters:
count: 1
path: administrator/components/com_privacy/src/View/Requests/HtmlView.php
- -
- message: '''
- #^Call to deprecated method getSession\(\) of class Joomla\\CMS\\Factory\:
- 4\.3 will be removed in 7\.0
- Use the session service in the DI container or get from the application object
- Example\:
- Factory\:\:getApplication\(\)\-\>getSession\(\);$#
- '''
- identifier: staticMethod.deprecated
- count: 2
- path: administrator/components/com_privacy/tmpl/requests/default.php
-
-
message: '''
#^Call to deprecated method getError\(\) of class Joomla\\CMS\\MVC\\Model\\BaseModel\:
@@ -6501,7 +6419,7 @@ parameters:
-
message: '''
#^Access to deprecated property \$document of class Joomla\\CMS\\MVC\\View\\AbstractView\:
- 4\.4\.0 will be removed in 7\.0
+ 4\.4\.0 will be made private in 7\.0
Use \$this\-\>getDocument\(\) instead$#
'''
identifier: property.deprecated
@@ -6530,18 +6448,6 @@ parameters:
count: 1
path: components/com_contact/src/Controller/ContactController.php
- -
- message: '''
- #^Call to deprecated method getSession\(\) of class Joomla\\CMS\\Factory\:
- 4\.3 will be removed in 7\.0
- Use the session service in the DI container or get from the application object
- Example\:
- Factory\:\:getApplication\(\)\-\>getSession\(\);$#
- '''
- identifier: staticMethod.deprecated
- count: 1
- path: components/com_contact/src/Controller/ContactController.php
-
-
message: '''
#^Call to deprecated method getInstance\(\) of class Joomla\\CMS\\Categories\\Categories\:
@@ -7964,18 +7870,6 @@ parameters:
count: 1
path: installation/src/Form/Field/Installation/LanguageField.php
- -
- message: '''
- #^Call to deprecated method getSession\(\) of class Joomla\\CMS\\Factory\:
- 4\.3 will be removed in 7\.0
- Use the session service in the DI container or get from the application object
- Example\:
- Factory\:\:getApplication\(\)\-\>getSession\(\);$#
- '''
- identifier: staticMethod.deprecated
- count: 1
- path: installation/src/Form/Field/Installation/PrefixField.php
-
-
message: '''
#^Call to deprecated method getInstance\(\) of class Joomla\\Database\\DatabaseDriver\:
@@ -7985,30 +7879,6 @@ parameters:
count: 1
path: installation/src/Helper/DatabaseHelper.php
- -
- message: '''
- #^Call to deprecated method getSession\(\) of class Joomla\\CMS\\Factory\:
- 4\.3 will be removed in 7\.0
- Use the session service in the DI container or get from the application object
- Example\:
- Factory\:\:getApplication\(\)\-\>getSession\(\);$#
- '''
- identifier: staticMethod.deprecated
- count: 9
- path: installation/src/Helper/DatabaseHelper.php
-
- -
- message: '''
- #^Call to deprecated method getSession\(\) of class Joomla\\CMS\\Factory\:
- 4\.3 will be removed in 7\.0
- Use the session service in the DI container or get from the application object
- Example\:
- Factory\:\:getApplication\(\)\-\>getSession\(\);$#
- '''
- identifier: staticMethod.deprecated
- count: 1
- path: installation/src/Model/BaseInstallationModel.php
-
-
message: '''
#^Call to deprecated method getInstance\(\) of class Joomla\\CMS\\Form\\Form\:
@@ -8020,18 +7890,6 @@ parameters:
count: 1
path: installation/src/Model/ChecksModel.php
- -
- message: '''
- #^Call to deprecated method getSession\(\) of class Joomla\\CMS\\Factory\:
- 4\.3 will be removed in 7\.0
- Use the session service in the DI container or get from the application object
- Example\:
- Factory\:\:getApplication\(\)\-\>getSession\(\);$#
- '''
- identifier: staticMethod.deprecated
- count: 3
- path: installation/src/Model/ConfigurationModel.php
-
-
message: '''
#^Call to deprecated method getInstance\(\) of class Joomla\\Database\\DatabaseDriver\:
@@ -8053,18 +7911,6 @@ parameters:
count: 1
path: installation/src/Model/DatabaseModel.php
- -
- message: '''
- #^Call to deprecated method getSession\(\) of class Joomla\\CMS\\Factory\:
- 4\.3 will be removed in 7\.0
- Use the session service in the DI container or get from the application object
- Example\:
- Factory\:\:getApplication\(\)\-\>getSession\(\);$#
- '''
- identifier: staticMethod.deprecated
- count: 1
- path: installation/src/Model/DatabaseModel.php
-
-
message: '''
#^Call to deprecated method getError\(\) of class Joomla\\CMS\\Table\\Table\:
@@ -8116,18 +7962,6 @@ parameters:
count: 2
path: installation/src/Model/SetupModel.php
- -
- message: '''
- #^Call to deprecated method getSession\(\) of class Joomla\\CMS\\Factory\:
- 4\.3 will be removed in 7\.0
- Use the session service in the DI container or get from the application object
- Example\:
- Factory\:\:getApplication\(\)\-\>getSession\(\);$#
- '''
- identifier: staticMethod.deprecated
- count: 1
- path: installation/src/Model/SetupModel.php
-
-
message: '''
#^Call to deprecated method getLanguage\(\) of class Joomla\\CMS\\Factory\:
@@ -8713,18 +8547,6 @@ parameters:
count: 1
path: libraries/src/Changelog/Changelog.php
- -
- message: '''
- #^Call to deprecated method getSession\(\) of class Joomla\\CMS\\Factory\:
- 4\.3 will be removed in 7\.0
- Use the session service in the DI container or get from the application object
- Example\:
- Factory\:\:getApplication\(\)\-\>getSession\(\);$#
- '''
- identifier: staticMethod.deprecated
- count: 3
- path: libraries/src/Client/ClientHelper.php
-
-
message: '#^Unsafe usage of new static\(\)\.$#'
identifier: new.static
@@ -11993,7 +11815,7 @@ parameters:
Factory\:\:getContainer\(\)\-\>get\(DatabaseInterface\:\:class\);$#
'''
identifier: staticMethod.deprecated
- count: 2
+ count: 1
path: libraries/src/Language/Multilanguage.php
-
@@ -12115,7 +11937,7 @@ parameters:
Catch thrown Exceptions instead of getError$#
'''
identifier: method.deprecated
- count: 7
+ count: 5
path: libraries/src/MVC/Controller/FormController.php
-
@@ -12372,7 +12194,7 @@ parameters:
-
message: '''
#^Access to deprecated property \$document of class Joomla\\CMS\\MVC\\View\\AbstractView\:
- 4\.4\.0 will be removed in 7\.0
+ 4\.4\.0 will be made private in 7\.0
Use \$this\-\>getDocument\(\) instead$#
'''
identifier: property.deprecated
@@ -12687,18 +12509,6 @@ parameters:
count: 2
path: libraries/src/Menu/AbstractMenu.php
- -
- message: '''
- #^Call to deprecated method getLanguage\(\) of class Joomla\\CMS\\Factory\:
- 4\.3 will be removed in 7\.0
- Use the language service in the DI container or get from the application object
- Example\:
- Factory\:\:getApplication\(\)\-\>getLanguage\(\);$#
- '''
- identifier: staticMethod.deprecated
- count: 2
- path: libraries/src/Menu/SiteMenu.php
-
-
message: '''
#^Call to deprecated method getLanguage\(\) of class Joomla\\CMS\\Factory\:
@@ -13716,18 +13526,6 @@ parameters:
count: 5
path: libraries/src/User/UserHelper.php
- -
- message: '''
- #^Call to deprecated method getSession\(\) of class Joomla\\CMS\\Factory\:
- 4\.3 will be removed in 7\.0
- Use the session service in the DI container or get from the application object
- Example\:
- Factory\:\:getApplication\(\)\-\>getSession\(\);$#
- '''
- identifier: staticMethod.deprecated
- count: 3
- path: libraries/src/User/UserHelper.php
-
-
message: '''
#^Call to deprecated method getUser\(\) of class Joomla\\CMS\\Factory\:
@@ -14244,16 +14042,6 @@ parameters:
count: 4
path: plugins/system/cache/src/Extension/Cache.php
- -
- message: '''
- #^Call to deprecated method setDispatcher\(\) of class Joomla\\Plugin\\System\\Cache\\Extension\\Cache\:
- 5\.2 will be removed in 7\.0
- Plugin should implement DispatcherAwareInterface on its own, when it is needed\.$#
- '''
- identifier: method.deprecated
- count: 1
- path: plugins/system/cache/src/Extension/Cache.php
-
-
message: '''
#^Call to deprecated method getLanguage\(\) of class Joomla\\CMS\\Factory\:
@@ -14494,18 +14282,6 @@ parameters:
count: 3
path: plugins/user/joomla/src/Extension/Joomla.php
- -
- message: '''
- #^Call to deprecated method getSession\(\) of class Joomla\\CMS\\Factory\:
- 4\.3 will be removed in 7\.0
- Use the session service in the DI container or get from the application object
- Example\:
- Factory\:\:getApplication\(\)\-\>getSession\(\);$#
- '''
- identifier: staticMethod.deprecated
- count: 1
- path: plugins/user/joomla/src/Extension/Joomla.php
-
-
message: '''
#^Call to deprecated method register\(\) of class Joomla\\CMS\\HTML\\HTMLHelper\:
diff --git a/plugins/content/loadmodule/src/Extension/LoadModule.php b/plugins/content/loadmodule/src/Extension/LoadModule.php
index d9f6f7f4cda..d54e6f0cebf 100644
--- a/plugins/content/loadmodule/src/Extension/LoadModule.php
+++ b/plugins/content/loadmodule/src/Extension/LoadModule.php
@@ -31,6 +31,8 @@ final class LoadModule extends CMSPlugin implements SubscriberInterface
protected static $mods = [];
+ protected static $recursionProtection = [];
+
/**
* Returns an array of events this subscriber will listen to.
*
@@ -56,6 +58,11 @@ public static function getSubscribedEvents(): array
*/
public function onContentPrepare(ContentPrepareEvent $event)
{
+ if ($this->getApplication()->isClient('api')) {
+ // Skip processing loadmodule/loadmoduleid tags for API
+ return;
+ }
+
$context = $event->getContext();
$article = $event->getItem();
@@ -105,6 +112,12 @@ public function onContentPrepare(ContentPrepareEvent $event)
// No matches, skip this
if ($matches) {
foreach ($matches as $match) {
+ if (isset(self::$recursionProtection[$match[1]])) {
+ continue;
+ }
+
+ self::$recursionProtection[$match[1]] = true;
+
$matcheslist = explode(',', $match[1]);
// We may not have a module style so fall back to the plugin default.
@@ -121,6 +134,8 @@ public function onContentPrepare(ContentPrepareEvent $event)
if (($start = strpos($article->text, $match[0])) !== false) {
$article->text = substr_replace($article->text, $output, $start, \strlen($match[0]));
}
+
+ unset(self::$recursionProtection[$match[1]]);
}
}
}
@@ -132,6 +147,12 @@ public function onContentPrepare(ContentPrepareEvent $event)
// If no matches, skip this
if ($matchesmod) {
foreach ($matchesmod as $matchmod) {
+ if (isset(self::$recursionProtection[$matchmod[1]])) {
+ continue;
+ }
+
+ self::$recursionProtection[$matchmod[1]] = true;
+
$matchesmodlist = explode(',', $matchmod[1]);
// First parameter is the module, will be prefixed with mod_ later
@@ -157,6 +178,8 @@ public function onContentPrepare(ContentPrepareEvent $event)
if (($start = strpos($article->text, $matchmod[0])) !== false) {
$article->text = substr_replace($article->text, $output, $start, \strlen($matchmod[0]));
}
+
+ unset(self::$recursionProtection[$matchmod[1]]);
}
}
}
@@ -168,6 +191,12 @@ public function onContentPrepare(ContentPrepareEvent $event)
// If no matches, skip this
if ($matchesmodid) {
foreach ($matchesmodid as $match) {
+ if (isset(self::$recursionProtection[$match[1]])) {
+ continue;
+ }
+
+ self::$recursionProtection[$match[1]] = true;
+
$id = trim($match[1]);
$output = $this->loadID($id);
@@ -175,6 +204,8 @@ public function onContentPrepare(ContentPrepareEvent $event)
if (($start = strpos($article->text, $match[0])) !== false) {
$article->text = substr_replace($article->text, $output, $start, \strlen($match[0]));
}
+
+ unset(self::$recursionProtection[$match[1]]);
}
}
}
diff --git a/plugins/editors/tinymce/src/PluginTraits/ResolveFiles.php b/plugins/editors/tinymce/src/PluginTraits/ResolveFiles.php
index 92c97fe783a..fecc7cab59f 100644
--- a/plugins/editors/tinymce/src/PluginTraits/ResolveFiles.php
+++ b/plugins/editors/tinymce/src/PluginTraits/ResolveFiles.php
@@ -112,6 +112,10 @@ protected static function resolveFileUrl($path = '')
return Uri::root(true) . str_replace(JPATH_ROOT, '', $minifiedPath);
}
+ if (is_file($path)) {
+ return Uri::root(true) . str_replace(JPATH_ROOT, '', $path);
+ }
+
return '';
}
}
diff --git a/plugins/fields/media/src/Extension/Media.php b/plugins/fields/media/src/Extension/Media.php
index 7c04a0f7938..986a6800446 100644
--- a/plugins/fields/media/src/Extension/Media.php
+++ b/plugins/fields/media/src/Extension/Media.php
@@ -11,6 +11,7 @@
namespace Joomla\Plugin\Fields\Media\Extension;
use Joomla\CMS\Event\CustomFields\BeforePrepareFieldEvent;
+use Joomla\CMS\Event\Model\PrepareDataEvent;
use Joomla\CMS\Form\Form;
use Joomla\Component\Fields\Administrator\Plugin\FieldsPlugin;
use Joomla\Event\SubscriberInterface;
@@ -36,10 +37,42 @@ final class Media extends FieldsPlugin implements SubscriberInterface
public static function getSubscribedEvents(): array
{
return array_merge(parent::getSubscribedEvents(), [
+ 'onContentPrepareData' => 'prepareContentData',
'onCustomFieldsBeforePrepareField' => 'beforePrepareField',
]);
}
+ /**
+ * Unset the fieldparams[types] parameter because the default value from the
+ * XML form get not overridden on field reload
+ *
+ * @param PrepareDataEvent $event The event instance.
+ *
+ * @return void
+ * @since 6.1.0
+ */
+ public function prepareContentData(PrepareDataEvent $event)
+ {
+ $context = $event->getContext();
+ $data = $event->getData();
+
+ if ($context !== 'com_fields.field') {
+ return;
+ }
+
+ if (!empty($data->type) && $data->type !== 'media') {
+ return;
+ }
+
+ if (\is_array($data)) {
+ unset($data['fieldparams']['types']);
+ } elseif (\is_object($data)) {
+ unset($data->fieldparams['types']);
+ }
+
+ $event->updateData($data);
+ }
+
/**
* Transforms the field into a DOM XML element and appends it as a child on the given parent.
*
diff --git a/plugins/filesystem/local/src/Adapter/LocalAdapter.php b/plugins/filesystem/local/src/Adapter/LocalAdapter.php
index 9f8ecd9a2d9..c012dd9ce75 100644
--- a/plugins/filesystem/local/src/Adapter/LocalAdapter.php
+++ b/plugins/filesystem/local/src/Adapter/LocalAdapter.php
@@ -13,7 +13,6 @@
use Joomla\CMS\Date\Date;
use Joomla\CMS\Factory;
use Joomla\CMS\Helper\MediaHelper;
-use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Image\Exception\UnparsableImageException;
use Joomla\CMS\Image\Image;
use Joomla\CMS\Language\Text;
@@ -408,9 +407,9 @@ private function getPathInformation(string $path): \stdClass
// Dates
$obj->create_date = $createDate->format('c', true);
- $obj->create_date_formatted = HTMLHelper::_('date', $createDate, Text::_('DATE_FORMAT_LC5'));
+ $obj->create_date_formatted = $createDate->format(Text::_('DATE_FORMAT_LC5'), true);
$obj->modified_date = $modifiedDate->format('c', true);
- $obj->modified_date_formatted = HTMLHelper::_('date', $modifiedDate, Text::_('DATE_FORMAT_LC5'));
+ $obj->modified_date_formatted = $modifiedDate->format(Text::_('DATE_FORMAT_LC5'), true);
if ($obj->mime_type === 'image/svg+xml' && $obj->extension === 'svg') {
$obj->thumb_path = $this->getUrl($obj->path);
diff --git a/plugins/system/sef/src/Extension/Sef.php b/plugins/system/sef/src/Extension/Sef.php
index 65d990a5072..f4e0013e851 100644
--- a/plugins/system/sef/src/Extension/Sef.php
+++ b/plugins/system/sef/src/Extension/Sef.php
@@ -10,10 +10,12 @@
namespace Joomla\Plugin\System\Sef\Extension;
+use Joomla\CMS\Document\ErrorDocument;
use Joomla\CMS\Event\Application\AfterDispatchEvent;
use Joomla\CMS\Event\Application\AfterInitialiseEvent;
use Joomla\CMS\Event\Application\AfterRenderEvent;
use Joomla\CMS\Event\Application\AfterRouteEvent;
+use Joomla\CMS\Event\Application\BeforeRespondEvent;
use Joomla\CMS\Language\LanguageHelper;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Router\Route;
@@ -36,6 +38,15 @@ final class Sef extends CMSPlugin implements SubscriberInterface
{
use SiteRouterAwareTrait;
+ /**
+ * Internal flag to make sure we don't process the buffer twice
+ *
+ * @var bool
+ *
+ * @since 5.4.4
+ */
+ protected $isRewritten = false;
+
/**
* Returns an array of CMS events this plugin will listen to and the respective handlers.
*
@@ -55,6 +66,7 @@ public static function getSubscribedEvents(): array
'onAfterRoute' => 'onAfterRoute',
'onAfterDispatch' => 'onAfterDispatch',
'onAfterRender' => 'onAfterRender',
+ 'onBeforeRespond' => 'onBeforeRespond',
];
}
@@ -219,6 +231,50 @@ public function onAfterRender(AfterRenderEvent $event)
return;
}
+ $this->rewriteUrls($app);
+ }
+
+ /**
+ * Handle URL rewriting for error pages since they skip the normal render flow
+ *
+ * @param BeforeRespondEvent $event The event instance
+ *
+ * @return void
+ *
+ * @since 5.4.4
+ */
+ public function onBeforeRespond(BeforeRespondEvent $event)
+ {
+ $app = $event->getApplication();
+
+ if (!$app->isClient('site')) {
+ return;
+ }
+
+ // Only run this specifically for Error pages, as normal pages are handled in onAfterRender
+ if ($app->getDocument() instanceof ErrorDocument) {
+ $this->rewriteUrls($app);
+ }
+ }
+
+ /**
+ * Core logic to rewrite relative URLs in the body buffer
+ *
+ * @param mixed $app The application object
+ *
+ * @return void
+ *
+ * @since 5.4.4
+ */
+ protected function rewriteUrls($app)
+ {
+ // Prevent rewriting from running multiple times
+ if ($this->isRewritten) {
+ return;
+ }
+
+ $this->isRewritten = true;
+
// Replace src links.
$base = Uri::base(true) . '/';
$buffer = $app->getBody();
diff --git a/plugins/system/webauthn/src/PluginTraits/AjaxHandler.php b/plugins/system/webauthn/src/PluginTraits/AjaxHandler.php
index 1d8f34b429d..022dba6374b 100644
--- a/plugins/system/webauthn/src/PluginTraits/AjaxHandler.php
+++ b/plugins/system/webauthn/src/PluginTraits/AjaxHandler.php
@@ -23,6 +23,7 @@
use Joomla\CMS\Event\Result\ResultAwareInterface;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Log\Log;
+use Joomla\CMS\Plugin\Attribute\AllowUnauthorizedAdministratorAccess;
use Joomla\CMS\Uri\Uri;
// phpcs:disable PSR1.Files.SideEffects
@@ -51,6 +52,7 @@ trait AjaxHandler
* @throws \Exception
* @since 4.0.0
*/
+ #[AllowUnauthorizedAdministratorAccess]
public function onAjaxWebauthn(AjaxEvent $event): void
{
$input = $this->getApplication()->getInput();
diff --git a/templates/system/build_incomplete.html b/templates/system/build_incomplete.html
index c4b7a65e032..327f68dc2dc 100644
--- a/templates/system/build_incomplete.html
+++ b/templates/system/build_incomplete.html
@@ -5,7 +5,7 @@
Joomla: Environment Setup Incomplete
-
+
diff --git a/templates/system/fatal-error.html b/templates/system/fatal-error.html
index bea9ea4458e..e55fe497898 100644
--- a/templates/system/fatal-error.html
+++ b/templates/system/fatal-error.html
@@ -5,7 +5,7 @@
An Error Occurred: {{statusText}}
-
+
diff --git a/templates/system/incompatible.html b/templates/system/incompatible.html
index a2e693105fd..113843b4b6b 100644
--- a/templates/system/incompatible.html
+++ b/templates/system/incompatible.html
@@ -5,7 +5,7 @@
Joomla: unsupported PHP version
-
+