2

I am using Drupal 10, CKEditor5, and a text format that has a good number of options in the toolbar including the source editing plugin. I have a custom module that defines a custom permission that I would like to use to show/hide (not disable completely) the source editing button.

What I've tried so far:

my_module.permissions.yml

'show source button':
  title: 'Display Source button in CKEditor'
  description: 'Display the Source button in CKEditor.'

my_module.module

// first try
function my_module_ckeditor5_plugin_info_alter(array &$plugin_definitions) : void {
  $currentUser = \Drupal::currentUser();

  if (!$currentUser->hasPermission('show source button')) {
    if (array_key_exists('ckeditor5_sourceEditing', $plugin_definitions)) {
      unset($plugin_definitions['ckeditor5_sourceEditing']);
    }
  }
}

// second try
function my_module_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
  $currentUser = \Drupal::currentUser();

  if (!$currentUser->hasPermission('show source button')) {
    $form['#attached']['library'][] = 'ckeditor_source_button/ckeditor_source_button';
  }
}

my_module.js

((Drupal) => {

  Drupal.behaviors.ckeditorSourceButtonBehavior = {
    attach: (context, settings) => {
      context.querySelectorAll('.ck-source-editing-button').forEach((element) => {
        element.classList.add('visually-hidden');
      });
    }
  }

})(Drupal);

Problems I've encountered with my methods:

  1. When using the hook_ckeditor5_plugin_info_alter, one problem is that unsetting the sourceEditing plugin completely removes the functionality and causes issues with html tags
  2. When using the hook_ckeditor5_plugin_info_alter, the second problem is that the current user is being cached and users that should be able to see the source button are not able to.
  3. When using hook_form_alter, I'm still having the cache issue happening as I said above but also that the query for '.ck-source-editing-button' is null every time and so is a query for '.ck-editor'.

I've tried adding cache contexts (ex. $form['#cache']['contexts'][] = 'session';) of session, user, or user.permissions to the my_module_form_alter but none of them seem to make a difference. Just for clarity, I've added these individually, never tried a combo of any of them

5
  • 1
    Normally you'd define a separate text format without the button, and make the one with the button available to roles with the appropriate permission - is there a reason you can't approach it that way here?
    – Clive
    Dec 14, 2023 at 22:02
  • I could, just didn't want to have to make another text format with the exact same options besides this one if I didn't have to go that route.
    – Jordan
    Dec 14, 2023 at 22:47
  • Makes sense. The plugin alter hook approach wouldn't work, but the form alter one seems like it should. Might be that you need to listen for ckeditor events before adding the classes. I've done something similar in the past I'll try to dig it out and put an answer in
    – Clive
    Dec 14, 2023 at 23:39
  • I'll have to do some research on that. If you can find it that would be great, thanks!
    – Jordan
    Dec 15, 2023 at 0:10
  • Turned into a bit of a rabbit hole, I must have been thinking of something else with what I'd done before. Hopefully the answer has enough to get you on the right track
    – Clive
    Dec 15, 2023 at 1:07

2 Answers 2

1

The simplest way to solve the problem would be to add one text format with the button, and one without, and assign those formats to roles with the appropriate permissions. It means two text formats to maintain, but no code to change.

The problem with the plugin_info_alter approach is it's not subject to cache contexts (or to be totally accurate it possibly is, or can be made to be, but in a way that's complicated to implement and/or undesirable from a performance perspective); whatever user's request caused that info to be built is the permission that will be used for the condition, not the current user when the info is loaded from cache and used in a particular form.

The JS approach won't work either, because the CKEditor instances aren't (guaranteed to be) created when your behavior first executes. There's a core issue to trigger an event when editors are ready, but the latest patch doesn't apply to 10.1.7, so that might be a pain to work with.

If your sole aim is to hide that button, it might just be best to replace the JS in your library with a CSS file containing a simple rule:

.ck-source-editing-button { display: none; }

(might need tweaking for specificity)

You should also add the cache context you mentioned in the form alter:

$form['#cache']['contexts'][] = 'user.permissions';

As the editors are part of the page markup, that should be enough to achieve the desired effect.

1
  • Thank you, this works as expected now! I don't know why I didn't think about just using a css file with the correct selector and set the display to none rather than trying to use javascript.
    – Jordan
    Dec 15, 2023 at 15:47
0

thank you for the proposed solutions !

i tested the last solution proposed, i just added !important to css file like this

  .ck-source-editing-button {
    display: none !important;
  }

and in .module

$currentUser = \Drupal::currentUser();
  if (!$currentUser->hasPermission('show source button')) {
    $form['#attached']['library'][] = 'ba_core/ckeditor_source_button';
  }

and it works ! no cache problems

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.