Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Programatically add classes and attributes to CKEditor #365

Open
felixlberg opened this issue Jun 10, 2021 · 1 comment
Open

Programatically add classes and attributes to CKEditor #365

felixlberg opened this issue Jun 10, 2021 · 1 comment

Comments

@felixlberg
Copy link

The problem to solve

It can happen that you want to add attributes or classes to all elements of your specific type in the CKEditor.

Styles are not always the right way to do this, because they are often forgotten, the list of styles gets bigger and bigger or the classes and attributes are technical so that the user doesn't understand their meaning.

As a developer, you want a way to control this. This possibility exists and is very easy to implement in the CKEditor that Apostrophe uses.

Proposed solution

As described in the Global CKEditor configuration section of the documentation, you can easily modify or extend the CKEditor.

In my case I had to add rel="noopener noreferer" to external links because otherwise you get in google lighthouse deductions for "Best Pratice".

I came up with the following solution:

// lib/modules/apostrophe-areas/public/js/user.js

apos.define('apostrophe-areas', {
  construct: function(self, options) {
    // Use the super pattern - don't forget to call the original method
    var superEnableCkeditor = self.enableCkeditor;
    self.enableCkeditor = function() {
      superEnableCkeditor();
      // Now do as we please

      CKEDITOR.on('instanceReady', function(ev) {
        var editor = ev.editor;
        editor.dataProcessor.htmlFilter.addRules({
          elements : {

            // Add attributes to a
            a : function( element ) {

              // Add accent-color class to all links
              if ( !element.attributes.class ){
                element.attributes.class = 'accent-color';
              }

              // Add _blank and noopener and noreferrer to external links
              if ( !element.attributes.rel ){

                // Get content's a href values
                var url = element.attributes.href;

                // Extract host names from URLs (IE safe)
                var parser = document.createElement('a');
                parser.href = url;

                // Set additional attributes
                var hostname = parser.hostname;
                if ( hostname !== window.location.host) {
                    element.attributes.rel = 'noopener noreferrer';
                    element.attributes.target = '_blank';
                }
              }
            }
          }
        });
      })
    };
  }
});

In this example you can see how a class accent-color is added to all a elements and the attributes rel="noopener noreferrer" and target="_blank" to all external links.

Of course i had to allow the additional attribute rel with the allowedAttributes method:

// lib/modules/apostrophe-rich-text-widgets/index.js

// Changing the allowed HTML tags in rich text widgets
module.exports = {
  sanitizeHtml: {
    allowedTags: [
      'h2', 'h3', 'h4', 'p', 'a', 'ul', 'ol', 'li', 'strong', 'em', 'blockquote', 'iframe'
    ],
    allowedAttributes: {
      '*': ['style', 'class'],
      a: [ 'style', 'name', 'href', 'target', 'rel', 'class' ]
    },
    allowedSchemes: ['http', 'https', 'ftp', 'mailto', 'tel']
  }
};

In this way the developer gets multiple possibilities to add certain things to certain elements and can limit the styles added to apostrophe-rich-text to the classes and elements a user should select and understands.

I think this should be added to the documentation as I imagine other developers have faced this dilemma as well.

@abea
Copy link
Contributor

abea commented Jun 25, 2021

That's an interesting strategy. We'd certainly welcome a contributed "how-to" page for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants