From c6fe479cc45f4abaceb1e5a591c1dff0a1f5f7eb Mon Sep 17 00:00:00 2001 From: Ivan Bochkarev Date: Thu, 20 Aug 2026 10:24:31 +0600 Subject: [PATCH 1/2] fix(acl): clarify Resource permissions and quiet class_map UI (#14479) Hide Resource Type combo without class_map (keep class_key as hidden). Align en permission descriptions with soft-delete, publish-only, edit_locked vs steal_locks, and view_document vs Get/GetList. --- .../Controllers/ResourceAccessPolicyTest.php | 93 +++++++++++++++++++ core/lexicon/en/permissions.inc.php | 30 +++--- .../widgets/resource/modx.panel.resource.js | 30 ++++-- .../widgets/resource/modx.tree.resource.js | 34 ++++--- .../widgets/resource/modx.window.resource.js | 37 ++++---- 5 files changed, 168 insertions(+), 56 deletions(-) create mode 100644 _build/test/Tests/Controllers/ResourceAccessPolicyTest.php diff --git a/_build/test/Tests/Controllers/ResourceAccessPolicyTest.php b/_build/test/Tests/Controllers/ResourceAccessPolicyTest.php new file mode 100644 index 00000000000..c4eb4737c23 --- /dev/null +++ b/_build/test/Tests/Controllers/ResourceAccessPolicyTest.php @@ -0,0 +1,93 @@ +assertStringContainsString( + "\$_lang['perm.publish_document_desc'] = 'To publish any Resource. Unpublishing uses unpublish_document.';", + $contents + ); + $this->assertStringNotContainsString( + 'To publish or unpublish any Resource.', + $contents + ); + } + + public function testEditLockedLexiconDescribesElementsNotResources() + { + $lexiconFile = MODX_CORE_PATH . 'lexicon/en/permissions.inc.php'; + $contents = file_get_contents($lexiconFile); + $this->assertStringContainsString('edit Elements that have the Locked checkbox', $contents); + $this->assertStringContainsString('Does not apply to Resource session locks', $contents); + } + + public function testDeleteDocumentLexiconDescribesSoftDelete() + { + $lexiconFile = MODX_CORE_PATH . 'lexicon/en/permissions.inc.php'; + $contents = file_get_contents($lexiconFile); + $this->assertStringContainsString('soft-delete any Resource', $contents); + $this->assertStringContainsString('requires purge_deleted', $contents); + } + + public function testViewDocumentLexiconDistinguishesFromGetList() + { + $lexiconFile = MODX_CORE_PATH . 'lexicon/en/permissions.inc.php'; + $contents = file_get_contents($lexiconFile); + $this->assertStringContainsString('Resource/Get and GetList use the generic view permission', $contents); + } + + /** + * @dataProvider providerClassMapGatedFiles + */ + public function testClassKeyFieldIsGatedOnClassMap(string $relativePath) + { + $file = MODX_MANAGER_PATH . $relativePath; + $this->assertFileExists($file); + $contents = file_get_contents($file); + $this->assertMatchesRegularExpression( + '/MODx\.perm\.class_map\s*\n?\s*\?\s*\{[\s\S]*?modx-combo-class-derivatives[\s\S]*?:\s*\{[\s\S]*?xtype:\s*[\'"]hidden[\'"]/', + $contents, + $relativePath . ' must choose combo vs hidden from MODx.perm.class_map' + ); + } + + public function providerClassMapGatedFiles(): array + { + return [ + ['assets/modext/widgets/resource/modx.panel.resource.js'], + ['assets/modext/widgets/resource/modx.window.resource.js'], + ['assets/modext/widgets/resource/modx.tree.resource.js'], + ]; + } + + public function testQuickCreateHasSingleClassKeyField() + { + $file = MODX_MANAGER_PATH . 'assets/modext/widgets/resource/modx.tree.resource.js'; + $contents = file_get_contents($file); + $fnStart = strpos($contents, 'MODx.getQuickCreateResourceSettingsFields'); + $this->assertNotFalse($fnStart); + $fnEnd = strpos($contents, 'MODx.getQRSettings', $fnStart); + $this->assertNotFalse($fnEnd); + $chunk = substr($contents, $fnStart, $fnEnd - $fnStart); + $this->assertStringContainsString('MODx.perm.class_map', $chunk); + $this->assertStringNotContainsString( + 'id: `modx-${id}-class_key`', + $chunk, + 'Pre-existing duplicate hidden class_key field must stay removed' + ); + $this->assertStringContainsString('id: `modx-${id}-class-key`', $chunk); + } +} diff --git a/core/lexicon/en/permissions.inc.php b/core/lexicon/en/permissions.inc.php index 43d2ae252d5..a0b01f52401 100644 --- a/core/lexicon/en/permissions.inc.php +++ b/core/lexicon/en/permissions.inc.php @@ -13,7 +13,7 @@ $_lang['perm.change_password_desc'] = 'User can change their user password.'; $_lang['perm.change_profile_desc'] = 'User can change their profile.'; $_lang['perm.charsets_desc'] = 'To view a list of charsets.'; -$_lang['perm.class_map_desc'] = 'To view a list of classes in the Class Map.'; +$_lang['perm.class_map_desc'] = 'To view class lists used by Class Map selectors, including the Resource Type combo on Resource create/edit forms.'; $_lang['perm.components_desc'] = 'To view the Extras menu.'; $_lang['perm.content_types_desc'] = 'The Content Types page.'; $_lang['perm.copy_desc'] = 'The ability to copy an object.'; @@ -28,10 +28,10 @@ $_lang['perm.delete_category_desc'] = 'To delete or remove any Categories.'; $_lang['perm.delete_chunk_desc'] = 'To delete or remove any Chunks.'; $_lang['perm.delete_context_desc'] = 'To delete or remove any Contexts.'; -$_lang['perm.delete_document_desc'] = 'To delete or remove any Resource.'; -$_lang['perm.delete_weblink_desc'] = 'To delete or remove any weblink, also requires delete_document permission.'; -$_lang['perm.delete_symlink_desc'] = 'To delete or remove any symlink, also requires delete_document permission.'; -$_lang['perm.delete_static_resource_desc'] = 'To delete or remove any static resource, also requires delete_document permission.'; +$_lang['perm.delete_document_desc'] = 'To soft-delete any Resource (mark as deleted). Permanent removal from the database requires purge_deleted.'; +$_lang['perm.delete_weblink_desc'] = 'To soft-delete any weblink; also requires delete_document.'; +$_lang['perm.delete_symlink_desc'] = 'To soft-delete any symlink; also requires delete_document.'; +$_lang['perm.delete_static_resource_desc'] = 'To soft-delete any static resource; also requires delete_document.'; $_lang['perm.delete_eventlog_desc'] = 'To empty the Event Log.'; $_lang['perm.delete_plugin_desc'] = 'To delete or remove any Plugins.'; $_lang['perm.delete_propertyset_desc'] = 'To delete or remove any Property Sets.'; @@ -52,7 +52,7 @@ $_lang['perm.edit_weblink_desc'] = 'To edit weblinks, also requires edit_document permission.'; $_lang['perm.edit_symlink_desc'] = 'To edit symlinks, also requires edit_document permission.'; $_lang['perm.edit_static_resource_desc'] = 'To edit static resources, also requires edit_document permission.'; -$_lang['perm.edit_locked_desc'] = 'Allows a user to override a lock and edit a locked Resource.'; +$_lang['perm.edit_locked_desc'] = 'To edit Elements that have the Locked checkbox set. Does not apply to Resource session locks; those use steal_locks and the Resource object policy steal_lock.'; $_lang['perm.edit_plugin_desc'] = 'To edit any Plugins. WARNING: combined with save_plugin permission, grants ability to execute arbitrary server-side code.'; $_lang['perm.edit_propertyset_desc'] = 'To edit any Property Sets.'; $_lang['perm.edit_role_desc'] = 'To edit any Roles.'; @@ -101,18 +101,18 @@ $_lang['perm.new_category_desc'] = 'To create a new Category.'; $_lang['perm.new_chunk_desc'] = 'To create a new Chunk.'; $_lang['perm.new_context_desc'] = 'To create a new Context.'; -$_lang['perm.new_document_desc'] = 'To create a new Resource.'; +$_lang['perm.new_document_desc'] = 'To create a new Resource (Document). Opening Create Resource requires this key; derivative types also need their type key.'; $_lang['perm.new_document_in_root_desc'] = 'To be able to create a Resource at the root level.'; $_lang['perm.new_plugin_desc'] = 'To create a new Plugin.'; $_lang['perm.new_propertyset_desc'] = 'To create a new Property Set.'; $_lang['perm.new_role_desc'] = 'To create a new Role.'; $_lang['perm.new_snippet_desc'] = 'To create a new Snippet.'; -$_lang['perm.new_static_resource_desc'] = 'To create a new Static Resource.'; -$_lang['perm.new_symlink_desc'] = 'To create a new SymLink.'; +$_lang['perm.new_static_resource_desc'] = 'To create a new Static Resource. Also requires new_document. Enforced on create and when changing Resource Type.'; +$_lang['perm.new_symlink_desc'] = 'To create a new SymLink. Also requires new_document. Enforced on create and when changing Resource Type.'; $_lang['perm.new_template_desc'] = 'To create a new Template.'; $_lang['perm.new_tv_desc'] = 'To create a new TV.'; $_lang['perm.new_user_desc'] = 'To create a new User.'; -$_lang['perm.new_weblink_desc'] = 'To create a new WebLink.'; +$_lang['perm.new_weblink_desc'] = 'To create a new WebLink. Also requires new_document. Enforced on create and when changing Resource Type.'; $_lang['perm.packages_desc'] = 'To use any Transport Packages in the Package Management system.'; $_lang['perm.policy_delete_desc'] = 'To delete an Access Policy.'; $_lang['perm.policy_edit_desc'] = 'To edit an Access Policy. WARNING: combined with policy_save permission, grants ability to escalate privileges, including security-related permissions.'; @@ -127,8 +127,8 @@ $_lang['perm.property_sets_desc'] = 'To view and edit Properties and Property Sets.'; $_lang['perm.providers_desc'] = 'To view and edit Providers across the site.'; $_lang['perm.publish_desc'] = 'Basic "publish" access on any object.'; -$_lang['perm.publish_document_desc'] = 'To publish or unpublish any Resource.'; -$_lang['perm.purge_deleted_desc'] = 'To empty the Recycle Bin.'; +$_lang['perm.publish_document_desc'] = 'To publish any Resource. Unpublishing uses unpublish_document.'; +$_lang['perm.purge_deleted_desc'] = 'To permanently remove soft-deleted Resources from the Recycle Bin.'; $_lang['perm.remove_desc'] = 'Basic permission to delete any object.'; $_lang['perm.remove_locks_desc'] = 'To delete all existing Locks throughout the site.'; $_lang['perm.resourcegroup_delete_desc'] = 'To delete a Resource Group.'; @@ -163,8 +163,8 @@ $_lang['perm.source_save_desc'] = 'To create or save a Media Source.'; $_lang['perm.source_view_desc'] = 'To view and list Media Sources.'; $_lang['perm.sources_desc'] = 'To manage Media Sources and Media Source Types.'; -$_lang['perm.steal_lock_desc'] = 'To "steal", or delete, a lock from a Resource.'; -$_lang['perm.steal_locks_desc'] = 'To "steal" locks, overriding a current lock on a Resource.'; +$_lang['perm.steal_lock_desc'] = 'Resource object policy: allow stealing the session lock on that Resource. Also requires the manager permission steal_locks.'; +$_lang['perm.steal_locks_desc'] = 'Manager permission to steal Resource session locks (another user has the Resource open). Also requires the Resource object policy steal_lock on that Resource.'; $_lang['perm.tree_show_resource_ids_desc'] = 'Show the IDs in the Resource tree.'; $_lang['perm.tree_show_element_ids_desc'] = 'Show the IDs in the Elements tree.'; $_lang['perm.undelete_desc'] = 'Basic permission to "undelete" any object.'; @@ -183,7 +183,7 @@ $_lang['perm.view_category_desc'] = 'To view any Categories.'; $_lang['perm.view_chunk_desc'] = 'To view any Chunks.'; $_lang['perm.view_context_desc'] = 'To view any Contexts.'; -$_lang['perm.view_document_desc'] = 'To view any Resources.'; +$_lang['perm.view_document_desc'] = 'To open Resource Data and related Manager views (resource/data, site_schedule, tree preview). Resource/Get and GetList use the generic view permission and Resource object policies, not this key.'; $_lang['perm.view_element_desc'] = 'To get a list of Elements or Element classes.'; $_lang['perm.view_eventlog_desc'] = 'To view the Event Log.'; $_lang['perm.view_offline_desc'] = 'To be able to view the site when it is in offline status.'; diff --git a/manager/assets/modext/widgets/resource/modx.panel.resource.js b/manager/assets/modext/widgets/resource/modx.panel.resource.js index 5db4e4d82e0..8737650ad12 100644 --- a/manager/assets/modext/widgets/resource/modx.panel.resource.js +++ b/manager/assets/modext/widgets/resource/modx.panel.resource.js @@ -929,16 +929,26 @@ Ext.extend(MODx.panel.Resource, MODx.FormPanel, { }, getSettingLeftFields: function(config) { - return [{ - xtype: 'modx-combo-class-derivatives', - fieldLabel: _('resource_type'), - description: '[[*class_key]]
', - name: 'class_key', - hiddenName: 'class_key', - id: 'modx-resource-class-key', - allowBlank: false, - value: config.record.class_key || 'MODX\\Revolution\\modDocument' - }, { + const classKey = config.record.class_key || 'MODX\\Revolution\\modDocument', + classKeyField = MODx.perm.class_map + ? { + xtype: 'modx-combo-class-derivatives', + fieldLabel: _('resource_type'), + description: '[[*class_key]]
', + name: 'class_key', + hiddenName: 'class_key', + id: 'modx-resource-class-key', + allowBlank: false, + value: classKey + } + : { + xtype: 'hidden', + name: 'class_key', + id: 'modx-resource-class-key', + value: classKey + }; + + return [classKeyField, { xtype: 'modx-combo-content-type', fieldLabel: _('resource_content_type'), description: `[[*content_type]]
${_('resource_content_type_help')}`, diff --git a/manager/assets/modext/widgets/resource/modx.tree.resource.js b/manager/assets/modext/widgets/resource/modx.tree.resource.js index a1f2265859d..9f7e5bb7e84 100644 --- a/manager/assets/modext/widgets/resource/modx.tree.resource.js +++ b/manager/assets/modext/widgets/resource/modx.tree.resource.js @@ -1290,11 +1290,6 @@ MODx.getQuickCreateResourceSettingsFields = function(id, parentData) { name: 'context_key', id: `modx-${id}-context_key`, value: parentData.context_key - }, { - xtype: 'hidden', - name: 'class_key', - id: `modx-${id}-class_key`, - value: parentData.class_key }, { xtype: 'hidden', name: 'publishedon', @@ -1311,16 +1306,25 @@ MODx.getQuickCreateResourceSettingsFields = function(id, parentData) { parentcmp: `modx-${id}-parent`, contextcmp: `modx-${id}-context_key`, currentid: parentData.id || 0 - }, { - xtype: 'modx-combo-class-derivatives', - fieldLabel: _('resource_type'), - description: '[[*class_key]]
', - name: 'class_key', - hiddenName: 'class_key', - id: `modx-${id}-class-key`, - anchor: '100%', - value: parentData.class_key !== undefined ? parentData.class_key : 'MODX\\Revolution\\modDocument' - }, { + }, ( + MODx.perm.class_map + ? { + xtype: 'modx-combo-class-derivatives', + fieldLabel: _('resource_type'), + description: '[[*class_key]]
', + name: 'class_key', + hiddenName: 'class_key', + id: `modx-${id}-class-key`, + anchor: '100%', + value: parentData.class_key !== undefined ? parentData.class_key : 'MODX\\Revolution\\modDocument' + } + : { + xtype: 'hidden', + name: 'class_key', + id: `modx-${id}-class-key`, + value: parentData.class_key !== undefined ? parentData.class_key : 'MODX\\Revolution\\modDocument' + } + ), { xtype: 'modx-combo-content-type', fieldLabel: _('resource_content_type'), description: `[[*content_type]]
${_('resource_content_type_help')}`, diff --git a/manager/assets/modext/widgets/resource/modx.window.resource.js b/manager/assets/modext/widgets/resource/modx.window.resource.js index bbafe856cfc..1c075688db5 100644 --- a/manager/assets/modext/widgets/resource/modx.window.resource.js +++ b/manager/assets/modext/widgets/resource/modx.window.resource.js @@ -3,20 +3,28 @@ MODx.window.CreateResource = function(config = {}) { const id = this.ident, requireAlias = parseInt(MODx.config.friendly_urls, 10) && !parseInt(MODx.config.automatic_alias, 10), aliasLength = parseInt(MODx.config.friendly_alias_max_length, 10) || 0, + classKey = config.record.class_key || 'MODX\\Revolution\\modDocument', + classKeyField = MODx.perm.class_map + ? { + xtype: 'modx-combo-class-derivatives', + fieldLabel: _('resource_type'), + description: MODx.expandHelp ? '' : _('resource_type_help'), + name: 'class_key', + hiddenName: 'class_key', + anchor: '100%', + allowBlank: false, + value: classKey + } + : { + xtype: 'hidden', + name: 'class_key', + value: classKey + }, resourceDetail = [ { columnWidth: requireAlias ? 0.33 : 0.5, items: [ - { - xtype: 'modx-combo-class-derivatives', - fieldLabel: _('resource_type'), - description: MODx.expandHelp ? '' : _('resource_type_help'), - name: 'class_key', - hiddenName: 'class_key', - anchor: '100%', - allowBlank: false, - value: config.record.class_key || 'MODX\\Revolution\\modDocument' - } + classKeyField ] }, { columnWidth: requireAlias ? 0.33 : 0.5, @@ -35,8 +43,7 @@ MODx.window.CreateResource = function(config = {}) { } ] } - ] - ; + ]; if (requireAlias) { resourceDetail.push({ columnWidth: 0.34, @@ -220,8 +227,7 @@ Ext.extend(MODx.combo.TemplatePicker, Ext.Panel, { loadItems: function(store, data) { const { value } = this, - items = [] - ; + items = []; let category = ''; Ext.each(data, function(record) { @@ -260,8 +266,7 @@ Ext.extend(MODx.combo.TemplatePicker, Ext.Panel, { fn: function(cmp) { const pickerValue = cmp.getValue(), - record = pickerValue?.record - ; + record = pickerValue?.record; if (record) { this.fireEvent('select', record); } From 70bdbfa0c15c41b4870a062f11935639c45073d5 Mon Sep 17 00:00:00 2001 From: Ivan Bochkarev Date: Thu, 20 Aug 2026 10:26:19 +0600 Subject: [PATCH 2/2] fix(acl): address #14479 review findings on class_map and lexicon Collapse Resource Type field to a single conditional xtype, clarify view_document vs Get/GetList policies, and note class_map is not a create-type gate. --- .../Controllers/ResourceAccessPolicyTest.php | 31 +++++++++++++------ core/lexicon/en/permissions.inc.php | 4 +-- .../widgets/resource/modx.panel.resource.js | 30 +++++++----------- .../widgets/resource/modx.tree.resource.js | 29 ++++++----------- .../widgets/resource/modx.window.resource.js | 27 ++++++---------- 5 files changed, 55 insertions(+), 66 deletions(-) diff --git a/_build/test/Tests/Controllers/ResourceAccessPolicyTest.php b/_build/test/Tests/Controllers/ResourceAccessPolicyTest.php index c4eb4737c23..d24501ab67e 100644 --- a/_build/test/Tests/Controllers/ResourceAccessPolicyTest.php +++ b/_build/test/Tests/Controllers/ResourceAccessPolicyTest.php @@ -42,13 +42,6 @@ public function testDeleteDocumentLexiconDescribesSoftDelete() $this->assertStringContainsString('requires purge_deleted', $contents); } - public function testViewDocumentLexiconDistinguishesFromGetList() - { - $lexiconFile = MODX_CORE_PATH . 'lexicon/en/permissions.inc.php'; - $contents = file_get_contents($lexiconFile); - $this->assertStringContainsString('Resource/Get and GetList use the generic view permission', $contents); - } - /** * @dataProvider providerClassMapGatedFiles */ @@ -58,9 +51,9 @@ public function testClassKeyFieldIsGatedOnClassMap(string $relativePath) $this->assertFileExists($file); $contents = file_get_contents($file); $this->assertMatchesRegularExpression( - '/MODx\.perm\.class_map\s*\n?\s*\?\s*\{[\s\S]*?modx-combo-class-derivatives[\s\S]*?:\s*\{[\s\S]*?xtype:\s*[\'"]hidden[\'"]/', + "/xtype:\\s*MODx\\.perm\\.class_map\\s*\\?\\s*'modx-combo-class-derivatives'\\s*:\\s*'hidden'/", $contents, - $relativePath . ' must choose combo vs hidden from MODx.perm.class_map' + $relativePath . ' must toggle Resource Type combo vs hidden via MODx.perm.class_map' ); } @@ -73,6 +66,21 @@ public function providerClassMapGatedFiles(): array ]; } + public function testViewDocumentLexiconDistinguishesFromGetList() + { + $lexiconFile = MODX_CORE_PATH . 'lexicon/en/permissions.inc.php'; + $contents = file_get_contents($lexiconFile); + $this->assertStringContainsString('Resource/Get uses the generic view permission', $contents); + $this->assertStringContainsString('per-row object list', $contents); + } + + public function testClassMapLexiconIsNotCreateTypeGate() + { + $lexiconFile = MODX_CORE_PATH . 'lexicon/en/permissions.inc.php'; + $contents = file_get_contents($lexiconFile); + $this->assertStringContainsString('Does not grant creating or changing Resource types', $contents); + } + public function testQuickCreateHasSingleClassKeyField() { $file = MODX_MANAGER_PATH . 'assets/modext/widgets/resource/modx.tree.resource.js'; @@ -89,5 +97,10 @@ public function testQuickCreateHasSingleClassKeyField() 'Pre-existing duplicate hidden class_key field must stay removed' ); $this->assertStringContainsString('id: `modx-${id}-class-key`', $chunk); + $this->assertSame( + 1, + substr_count($chunk, "name: 'class_key'"), + 'Quick create settings must define class_key once' + ); } } diff --git a/core/lexicon/en/permissions.inc.php b/core/lexicon/en/permissions.inc.php index a0b01f52401..bad04e3c5c5 100644 --- a/core/lexicon/en/permissions.inc.php +++ b/core/lexicon/en/permissions.inc.php @@ -13,7 +13,7 @@ $_lang['perm.change_password_desc'] = 'User can change their user password.'; $_lang['perm.change_profile_desc'] = 'User can change their profile.'; $_lang['perm.charsets_desc'] = 'To view a list of charsets.'; -$_lang['perm.class_map_desc'] = 'To view class lists used by Class Map selectors, including the Resource Type combo on Resource create/edit forms.'; +$_lang['perm.class_map_desc'] = 'To view class lists used by Class Map selectors, including the Resource Type combo. Does not grant creating or changing Resource types; those still need new_document and the matching type key (new_weblink, new_symlink, new_static_resource).'; $_lang['perm.components_desc'] = 'To view the Extras menu.'; $_lang['perm.content_types_desc'] = 'The Content Types page.'; $_lang['perm.copy_desc'] = 'The ability to copy an object.'; @@ -183,7 +183,7 @@ $_lang['perm.view_category_desc'] = 'To view any Categories.'; $_lang['perm.view_chunk_desc'] = 'To view any Chunks.'; $_lang['perm.view_context_desc'] = 'To view any Contexts.'; -$_lang['perm.view_document_desc'] = 'To open Resource Data and related Manager views (resource/data, site_schedule, tree preview). Resource/Get and GetList use the generic view permission and Resource object policies, not this key.'; +$_lang['perm.view_document_desc'] = 'To open Resource Data and related Manager views (resource/data, site_schedule, tree preview). Resource/Get uses the generic view permission (and object view). Resource/GetList uses view plus per-row object list. Neither uses this key.'; $_lang['perm.view_element_desc'] = 'To get a list of Elements or Element classes.'; $_lang['perm.view_eventlog_desc'] = 'To view the Event Log.'; $_lang['perm.view_offline_desc'] = 'To be able to view the site when it is in offline status.'; diff --git a/manager/assets/modext/widgets/resource/modx.panel.resource.js b/manager/assets/modext/widgets/resource/modx.panel.resource.js index 8737650ad12..707d38498fe 100644 --- a/manager/assets/modext/widgets/resource/modx.panel.resource.js +++ b/manager/assets/modext/widgets/resource/modx.panel.resource.js @@ -929,26 +929,18 @@ Ext.extend(MODx.panel.Resource, MODx.FormPanel, { }, getSettingLeftFields: function(config) { - const classKey = config.record.class_key || 'MODX\\Revolution\\modDocument', - classKeyField = MODx.perm.class_map - ? { - xtype: 'modx-combo-class-derivatives', - fieldLabel: _('resource_type'), - description: '[[*class_key]]
', - name: 'class_key', - hiddenName: 'class_key', - id: 'modx-resource-class-key', - allowBlank: false, - value: classKey - } - : { - xtype: 'hidden', - name: 'class_key', - id: 'modx-resource-class-key', - value: classKey - }; + const classKey = config.record.class_key || 'MODX\\Revolution\\modDocument'; - return [classKeyField, { + return [{ + xtype: MODx.perm.class_map ? 'modx-combo-class-derivatives' : 'hidden', + fieldLabel: _('resource_type'), + description: '[[*class_key]]
', + name: 'class_key', + hiddenName: 'class_key', + id: 'modx-resource-class-key', + allowBlank: false, + value: classKey + }, { xtype: 'modx-combo-content-type', fieldLabel: _('resource_content_type'), description: `[[*content_type]]
${_('resource_content_type_help')}`, diff --git a/manager/assets/modext/widgets/resource/modx.tree.resource.js b/manager/assets/modext/widgets/resource/modx.tree.resource.js index 9f7e5bb7e84..f1f4eebce6b 100644 --- a/manager/assets/modext/widgets/resource/modx.tree.resource.js +++ b/manager/assets/modext/widgets/resource/modx.tree.resource.js @@ -1306,25 +1306,16 @@ MODx.getQuickCreateResourceSettingsFields = function(id, parentData) { parentcmp: `modx-${id}-parent`, contextcmp: `modx-${id}-context_key`, currentid: parentData.id || 0 - }, ( - MODx.perm.class_map - ? { - xtype: 'modx-combo-class-derivatives', - fieldLabel: _('resource_type'), - description: '[[*class_key]]
', - name: 'class_key', - hiddenName: 'class_key', - id: `modx-${id}-class-key`, - anchor: '100%', - value: parentData.class_key !== undefined ? parentData.class_key : 'MODX\\Revolution\\modDocument' - } - : { - xtype: 'hidden', - name: 'class_key', - id: `modx-${id}-class-key`, - value: parentData.class_key !== undefined ? parentData.class_key : 'MODX\\Revolution\\modDocument' - } - ), { + }, { + xtype: MODx.perm.class_map ? 'modx-combo-class-derivatives' : 'hidden', + fieldLabel: _('resource_type'), + description: '[[*class_key]]
', + name: 'class_key', + hiddenName: 'class_key', + id: `modx-${id}-class-key`, + anchor: '100%', + value: parentData.class_key !== undefined ? parentData.class_key : 'MODX\\Revolution\\modDocument' + }, { xtype: 'modx-combo-content-type', fieldLabel: _('resource_content_type'), description: `[[*content_type]]
${_('resource_content_type_help')}`, diff --git a/manager/assets/modext/widgets/resource/modx.window.resource.js b/manager/assets/modext/widgets/resource/modx.window.resource.js index 1c075688db5..8a484b47f03 100644 --- a/manager/assets/modext/widgets/resource/modx.window.resource.js +++ b/manager/assets/modext/widgets/resource/modx.window.resource.js @@ -4,27 +4,20 @@ MODx.window.CreateResource = function(config = {}) { requireAlias = parseInt(MODx.config.friendly_urls, 10) && !parseInt(MODx.config.automatic_alias, 10), aliasLength = parseInt(MODx.config.friendly_alias_max_length, 10) || 0, classKey = config.record.class_key || 'MODX\\Revolution\\modDocument', - classKeyField = MODx.perm.class_map - ? { - xtype: 'modx-combo-class-derivatives', - fieldLabel: _('resource_type'), - description: MODx.expandHelp ? '' : _('resource_type_help'), - name: 'class_key', - hiddenName: 'class_key', - anchor: '100%', - allowBlank: false, - value: classKey - } - : { - xtype: 'hidden', - name: 'class_key', - value: classKey - }, resourceDetail = [ { columnWidth: requireAlias ? 0.33 : 0.5, items: [ - classKeyField + { + xtype: MODx.perm.class_map ? 'modx-combo-class-derivatives' : 'hidden', + fieldLabel: _('resource_type'), + description: MODx.expandHelp ? '' : _('resource_type_help'), + name: 'class_key', + hiddenName: 'class_key', + anchor: '100%', + allowBlank: false, + value: classKey + } ] }, { columnWidth: requireAlias ? 0.33 : 0.5,