diff --git a/CHANGELOG.md b/CHANGELOG.md index e7085914..95e068c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ ## Unreleased - CKEditor fields no longer have extra bottom padding, and the CKEditor logo is now displayed over the bottom border. ([#252](https://github.com/craftcms/ckeditor/pull/252)) +- Added the ability to show the “Source” button for specific user groups. ([#318](https://github.com/craftcms/ckeditor/pull/318)) +- Added `craft\ckeditor\Field::$sourceEditingGroups`. +- Deprecated `craft\ckeditor\Field::$enableSourceEditingForNonAdmins`. ## 3.10.0 - 2024-10-19 diff --git a/src/Field.php b/src/Field.php index 2f16a63e..b837a708 100644 --- a/src/Field.php +++ b/src/Field.php @@ -16,6 +16,7 @@ use craft\elements\Asset; use craft\elements\Category; use craft\elements\Entry; +use craft\elements\User; use craft\errors\InvalidHtmlTagException; use craft\helpers\ArrayHelper; use craft\helpers\Html; @@ -141,10 +142,10 @@ public static function textPartLanguage(): array public ?string $defaultTransform = null; /** - * @var bool Whether to enable source editing for non-admin users. - * @since 3.3.0 + * @var string|string[]|null User groups whose members should be able to see the “Source” button + * @since 3.11.0 */ - public bool $enableSourceEditingForNonAdmins = false; + public string|array|null $sourceEditingGroups = ['__ADMINS__']; /** * @var bool Whether to show volumes the user doesn’t have permission to view. @@ -171,6 +172,13 @@ public function __construct($config = []) $config['removeNbsp'], ); + if (isset($config['enableSourceEditingForNonAdmins'])) { + $config['sourceEditingGroups'] = $config['enableSourceEditingForNonAdmins'] ? '*' : ['__ADMINS__']; + unset($config['enableSourceEditingForNonAdmins']); + } elseif (array_key_exists('sourceEditingGroups', $config) && empty($config['sourceEditingGroups'])) { + $config['sourceEditingGroups'] = null; + } + parent::__construct($config); } @@ -234,6 +242,22 @@ public function getSettingsHtml(): ?string { $view = Craft::$app->getView(); + $userGroupOptions = [ + [ + 'label' => Craft::t('app', 'Admins'), + 'value' => '__ADMINS__', + ], + ]; + + foreach (Craft::$app->getUserGroups()->getAllGroups() as $group) { + if ($group->can('accessCp')) { + $userGroupOptions[] = [ + 'label' => $group->name, + 'value' => $group->uid, + ]; + } + } + $volumeOptions = []; foreach (Craft::$app->getVolumes()->getAllVolumes() as $volume) { if ($volume->getFs()->hasUrls) { @@ -254,6 +278,7 @@ public function getSettingsHtml(): ?string return $view->renderTemplate('ckeditor/_field-settings.twig', [ 'field' => $this, + 'userGroupOptions' => $userGroupOptions, 'purifierConfigOptions' => $this->configOptions('htmlpurifier'), 'volumeOptions' => $volumeOptions, 'transformOptions' => $transformOptions, @@ -303,7 +328,7 @@ protected function inputHtml(mixed $value, ElementInterface $element = null): st // Toolbar cleanup $toolbar = array_merge($ckeConfig->toolbar); - if (!$this->enableSourceEditingForNonAdmins && !Craft::$app->getUser()->getIsAdmin()) { + if (!$this->isSourceEditingAllowed(Craft::$app->getUser()->getIdentity())) { ArrayHelper::removeValue($toolbar, 'sourceEditing'); } @@ -549,6 +574,32 @@ protected function prepValueForInput($value, ?ElementInterface $element): string return parent::prepValueForInput($value, $element); } + /** + * Returns if user belongs to a group whose members are allowed to edit source even if they're not admins + * @param User $user + * @return bool + */ + private function isSourceEditingAllowed(User $user): bool + { + if ($this->sourceEditingGroups === '*') { + return true; + } + + $sourceEditingGroups = array_flip($this->sourceEditingGroups); + + if ($user->admin && isset($sourceEditingGroups['__ADMINS__'])) { + return true; + } + + foreach ($user->getGroups() as $group) { + if (isset($sourceEditingGroups[$group->uid])) { + return true; + } + } + + return false; + } + /** * @inheritdoc */ @@ -1037,4 +1088,20 @@ private function _describedBy(View $view): string return ''; } + + /** + * @deprecated in 3.11.0 + */ + public function getEnableSourceEditingForNonAdmins(): bool + { + return $this->sourceEditingGroups === '*'; + } + + /** + * @deprecated in 3.11.0 + */ + public function setEnableSourceEditingForNonAdmins(bool $value): void + { + $this->sourceEditingGroups = $value ? '*' : ['__ADMINS__']; + } } diff --git a/src/templates/_field-settings.twig b/src/templates/_field-settings.twig index 9beafe74..e89ae0a9 100644 --- a/src/templates/_field-settings.twig +++ b/src/templates/_field-settings.twig @@ -55,12 +55,18 @@ on: field.showWordCount }) }} -{{ forms.lightswitchField({ - id: 'enable-source-editing-for-non-admins', - name: 'enableSourceEditingForNonAdmins', - label: 'Show the “Source” button for non-admin users?'|t('ckeditor'), - on: field.enableSourceEditingForNonAdmins, -}) }} +{% if userGroupOptions|length %} +
+ {{ forms.checkboxSelectField({ + id: 'sourceEditingGroups', + name: 'sourceEditingGroups', + label: 'Who should see the “Source” button?'|t('ckeditor'), + options: userGroupOptions, + values: field.sourceEditingGroups, + showAllOption: true, + }) }} +
+{% endif %}
diff --git a/src/translations/en/ckeditor.php b/src/translations/en/ckeditor.php index fe78e957..fadc9891 100644 --- a/src/translations/en/ckeditor.php +++ b/src/translations/en/ckeditor.php @@ -32,7 +32,6 @@ 'No transform' => 'No transform', 'Purify HTML' => 'Purify HTML', 'Removes any potentially-malicious code on save, by running the submitted data through {link}.' => 'Removes any potentially-malicious code on save, by running the submitted data through {link}.', - 'Show the “Source” button for non-admin users?' => 'Show the “Source” button for non-admin users?', 'Show word count' => 'Show word count', 'Site: {name}' => 'Site: {name}', 'The default transform that should be applied when inserting an image.' => 'The default transform that should be applied when inserting an image.', @@ -40,6 +39,7 @@ 'The type of column this field should get in the database.' => 'The type of column this field should get in the database.', 'Toolbar' => 'Toolbar', 'View available settings' => 'View available settings', + 'Who should see the “Source” button?' => 'Who should see the “Source” button?', 'Word Limit' => 'Word Limit', 'You can save custom {name} configs as {ext} files in {path}.' => 'You can save custom {name} configs as {ext} files in {path}.', 'Your JavaScript config contains functions. If you switch to JSON, they will be lost. Would you like to continue?',