DNN Blogs

Written for the Community, by the Community

Adding Custom Styles to CKEditorProvider

Written By Steve Krantzman
2020-12-11

Adding custom styles to, or replacing styles in the CKEditor “Styles” dropdown should be relatively easy. Well at least that is what we thought. Yet, recently Mark Anderson, Jeremey Farrance, Mark Buelsing, and myself had to put our collective heads together to figure out how to do just that. Although it took us the good part of a day, we triumphed and thought we should share the specifics with you. This relatively simple task turned out to be the impetus of this series.

To Add Inline Styles or Not to Add Inline Styles… That is the Question. 

Ever since Håkon Wium Lie proposed Cascading Style Sheets in 1994, as a way to separate Markup form Styling, the debate whether or not to use inline styling on web pages continues to rage on to this day. I think most of us would agree that if a website consists of only a page or two, inline styling is fine, there may even be a slight performance boost not having to load a separate CSS file. However as a site grows in size, CSS classes are the only way to go for manageability. That logic works well for traditional websites, but can fall apart when working with content management systems (CMSs) such as DNN. One of the primary benefits of a CMS was to allow non-technical staff to manage content on a website via a rich text WSISYG editor, such as CKEditor. The drawback however is that most WYSIWYG editors apply styling as inline styles, and CKEditor is no exception.

Many (including me until recently) fall into the trap of “Does it really matter if WYSIWYG editors rely heavily on inline styling, as long as it enables content editors to do their job?” Well, that answer depends on the size of the site and what the site is being used for.  Just like above, if the site is a small site then it probably does not matter. However if the site is a large site that belongs to a mid size or large company then yes, it will most likely matter.  Many mid to large sized companies spend thousands of dollars with design and branding agencies to come up with the company’s logo, colors, fonts, etc. that are used throughout all of their marketing materials, including their website. In turn they tend to have strict guidelines that need to be adhered to regarding the use of those styles, and it is our job as developers to help them maintain those standards.

In my previous post on the CKEditor Provider, I showed you how to add a company’s color scheme to both the Font Color and Background Color dropdown lists through the ColorButton_Colors property of the CKEditor.

image

This helps the content editor to quickly select those colors, but does not prevent them from selecting any other color they want via the “More Colors…” link in the list. To help our customer maintain their styling guidelines, we could prevent content editors from selecting colors that are not part of the company color scheme, by unchecking the box next to the ColorButton_EnableMore property.

image

So now we have restricted content editors to only selecting company approved colors from the CKEditor’s color options buttons.

image

There remains the issue that these colors are still applied inline. What happens when the company decides to change or modify one or more of the colors in the color scheme? You guessed it, someone now has to go through every page on the website looking for where that color is used in HTML modules, and change those instances of the old color(s) to the new color(s)… What a PITA! I bet CSS classes are looking mighty good right now, well at least that is what DNN Community member Mark Anderson thought.

The CKEditor Styles Dropdown Customization Problem

Mark (being the bright intuitive guy he is) wanted to stop page editors from using inline styles by removing the font, font size, font color, and background color buttons from the CKEditor toolbars. In addition he needed to remove all of the predefined styles from the Styles dropdown list, as many of them are applied inline as well. To still give his content editors styling control, he wanted to add some custom styles to the CKEditor Styles dropdown that utilize classes instead of inline styling.

Although the CKEditor Ecosystem Documents such as this one https://ckeditor.com/docs/ckeditor4/latest/features/styles.html provided some insight, they are CKEditor specific, and reference changing CKEditor's styles.js file. In a DNN instance that file resides here:

DNNRoot/Providers/HTMLEditorProvidors/DNNConnect.CKE/js/ckeditor/4.5.3

Yet modifying this file appears to have no effect on the Styles dropdown list in CKEditorProvider.

The Styles Solution

Style Definitions

Style definitions is a JavaScript array, which traditionally for CKEditor, is registered in the styles.js file I mentioned above, and is called using the CKEditor.stylesSet.add function. Below are excerpts from the default styles.js file.

CKEDITOR.stylesSet.add( 'default', [
  /* Block Styles */
  { name: 'Italic Title', element: 'h2', styles: { 'font-style': 'italic' } },
  { name: 'Subtitle', element: 'h3', styles: { 'color': '#aaa', 'font-style': 'italic' } },
  ...
  /* Inline Styles */
  { name: 'Marker', element: 'span', attributes: { 'class': 'marker' } },
  { name: 'Big', element: 'big' },
  ...
  /* Object Styles */
  {name: 'Styled image (left)', element: 'img', attributes: { 'class': 'left' } },
  {name: 'Styled image (right)', element: 'img', attributes: { 'class': 'right' } },
      ...
] );

The style definition array itself is composed of style rules, with each rule defining the name, element, and styles or attributes used by the rule. The style rules are further grouped by style types within the array, which are denoted by a comment with the style type’s name.  The three styles types are:

  • Block styles (applied to text blocks e.g. address, div,h1-h6, div, p, pre)
  • Object styles (applied to non-textual objects e.g. a, hr, img, li, ol, table, ul,  etc.)
  • Inline styles (applied to selected text)

Lets use Mark’s strategy to customize our Styles dropdown list

  1. Create your desired CSS Classes for styling components on your page. There is nothing new here if you are familiar with CSS, so just make sure the classes you would like to use for your style definitions are included in your site theme’s CSS file. You could place them in another file such as portal.css, but for them to show up correctly in the editor window, we will place them in the same folder we pointed to in the previous blog. For our example lets create a couple of classes. A fun styled div with padding, and a Call-to-Action button style.
     
    .orange-creamsicle {
      color: #fff;
      background-color: #ffa500;
      padding: 15px;
      font-weight: 700;
      font-size: 1.25rem;
      border-radius: 25px;
      text-align: center;
    }
    
    .btn-cta {
      background-color: #951596;
      border-color: #951596;
      color: #fff;
      text-transform: uppercase;
      border-radius: 7px;
      padding: 1rem 1.5rem;
      font-weight: 700;
      font-size: 1rem;
    }
    Go ahead and copy and paste these styles into your site theme’s CSS file if you would like to follow along.

  2. Create your style definition stylesSet. As an example, Mark wants his content editors to be able to apply button styling to an anchor tag. So he would create this style rule:
     
    { name : 'CTA Button a', element : 'a', attributes : { 'class' : btn-cta' } }
    Since a stylesSet is an array that is comprised of style rule(s) Mark’s stylesSet would look like this which utilizes our classes from above:
     
    [
      /* Block Styles */
      {name : 'Orange div', element : 'div', attributes : { 'class' : 'orange-creamsicle' } },
      /* Object Styles */
      {name : 'CTA Button a', element : 'a', attributes : { 'class' : 'btn-cta' } }
      /* Inline Styles */  
    ]
  3. Because CKEditor Provider ignores the style.js file, we need to add our stylesSet without the CKEditor.stylesSet.add function. Copy your newly created/edited stylesSet to the stylesSet property on the Editor Config tab of the CKEditor Provider Settings dialog box, and save your changes.

    image 


That’s it, your done making your first edit of the style definitions for the Styles dropdown list. Your new styles should now be available for use. There is one key aspect of the Styles dropdown list you should be aware of if you have not used it much.  The styles in the list are dynamically populated depending on what you have selected in the editor window.

As you can see from this fist screenshot, I have the top “Click Me!” entry selected. Because this text is surrounded by <p> tags (block element) I only have Block Styles to choose from.


image


In this second screenshot, the lower “Click Me!” is surrounded by both <p> tags (block element), and <a> tags (object element), so we have both Object Styles and Block Styles in the list.

image

As a last point of interest, the block styles we create for the Styles dropdown list are also available to us when we use the Create Div Container button on the toolbar.

image

And the final result of applying both of our new styles

image
 

Not so Inline, Inline Styles

You may have noticed that we did not create any Inline Styles in our example. Why should we, isn’t the whole purpose of this exercise to get away from inline styles?  In the traditional sense yes, but we can still use a few inline styles to our advantage. In this blog and the previous blog, there is a company color scheme that I have been using as an example. Those colors are defined using SASS variables, so that if the color scheme for the company changes, I only have to change the color defined by variable and the whole site is updated.

If you want your content editors to still have access to those colors for highlighting text, we can achieve this with Inline Styles. Simply create a few classes, such as text-primary, text-secondary, text-tertiary, etc. that utilize your color scheme variables for their color property.  Then update your style definitions so you have something like this:

[
  /* Block Styles */
  {name : 'Orange div', element : 'div', attributes : { 'class' : 'orange-creamsicle' } },
  /* Object Styles */
  {name : 'CTA Button a', element : 'a', attributes : { 'class' : 'btn-cta' } },
  /* Inline Styles */ 
  {name : 'Primary Text', element : 'span', attributes : { 'class' : 'text-primary' } },
  {name : 'Secondary Text', element : 'span', attributes : { 'class' : 'text-secondary' } },
  {name : 'Tertiary Text', element : 'span', attributes : { 'class' : 'text-tertiary' } },
  {name : 'Quaternary Text', element : 'span', attributes : { 'class' : 'text-quaternary' } },
  {name : 'Accent Text', element : 'span', attributes : { 'class' : 'text-accent' } }
]

Notice that for the Inline Styles, we are still using classes within the attributes property.  In this way, if we update one or more colors of the color scheme in our CSS file, those changes will be propagated throughout our site, including the HTML module.

Here is the updated Styles dropdown list reflecting our new Inline Styles,

image

and here I have applied these new Inline Styles to text in our orange creamsicle div.

image
 

Wrap Up

Hopefully I have cleared up some of the mystery of how to update CKEditor’s Styles dropdown list in DNN, and why doing so could make your DNN site more manageable.

There is a certain degree of quirkiness involved with the DNNCKEditor Provider. Some of that has to do with the way the CKEditor is wrapped up as a provider, and some of it may be attributed to a very outdated version of CKEditor. As I have mentioned in the past DNNCKEditor Provider uses CKEditor v4.5.3, released Aug. 19, 2015. Since then there have been 34 updates to CKEditor 4, with four of those updates containing security fixes.

We as a community should probably look at updating the CKEditor Provider, or at the very least, install a newer version of CKEditor for our sites.  But alas, that is a discussion for another time.

Thanks for reading!

Total: 4 Comment(s)
Great info, thank you! Wondering how to add custom fonts to CKEditor? I can add names through the config options & they show in the dropdown list but can't get them to load and display properly. Would like to know how to do this using fonts.google.com as well as locally saved fonts.
Friday, January 15, 2021 ·

Error: Object reference not set to an instance of an object.

In: at DotNetNuke.Modules.Blog.Templating.LazyLoadingUser.GetProperty(String strPropertyName, String strFormat, CultureInfo formatProvider, UserInfo AccessingUser, Scope AccessLevel, Boolean& PropertyNotFound) at DotNetNuke.Modules.Blog.Templating.BaseCustomTokenReplace.replacedTokenValue(String strObjectName, String strPropertyName, String strFormat) at DotNetNuke.Modules.Blog.Templating.BaseTokenReplace.ReplaceTokenMatch(Match m) at System.Text.RegularExpressions.RegexReplacement.Replace(MatchEvaluator evaluator, Regex regex, String input, Int32 count, Int32 startat) at System.Text.RegularExpressions.Regex.Replace(String input, MatchEvaluator evaluator, Int32 count, Int32 startat) at System.Text.RegularExpressions.Regex.Replace(String input, MatchEvaluator evaluator) at DotNetNuke.Modules.Blog.Templating.BaseTokenReplace.ReplaceTokens(String strSourceText) at DotNetNuke.Modules.Blog.Templating.GenericTokenReplace.ReplaceTokens(String strSourceText) at DotNetNuke.Modules.Blog.Templating.Template.ReplaceContents()

Thanks Steve! I was able to add custom styles via the CK Editor "Custom Editor Options". One way I use it to allow content authors to apply a span.phonenumber on a string of numbers, then on page load my skin converts the span into a clickable phone link.
Thursday, July 22, 2021 ·

Error: Object reference not set to an instance of an object.

In: at DotNetNuke.Modules.Blog.Templating.LazyLoadingUser.GetProperty(String strPropertyName, String strFormat, CultureInfo formatProvider, UserInfo AccessingUser, Scope AccessLevel, Boolean& PropertyNotFound) at DotNetNuke.Modules.Blog.Templating.BaseCustomTokenReplace.replacedTokenValue(String strObjectName, String strPropertyName, String strFormat) at DotNetNuke.Modules.Blog.Templating.BaseTokenReplace.ReplaceTokenMatch(Match m) at System.Text.RegularExpressions.RegexReplacement.Replace(MatchEvaluator evaluator, Regex regex, String input, Int32 count, Int32 startat) at System.Text.RegularExpressions.Regex.Replace(String input, MatchEvaluator evaluator, Int32 count, Int32 startat) at System.Text.RegularExpressions.Regex.Replace(String input, MatchEvaluator evaluator) at DotNetNuke.Modules.Blog.Templating.BaseTokenReplace.ReplaceTokens(String strSourceText) at DotNetNuke.Modules.Blog.Templating.GenericTokenReplace.ReplaceTokens(String strSourceText) at DotNetNuke.Modules.Blog.Templating.Template.ReplaceContents()

Would you like to help us?

Awesome! Simply post in the forums using the link below and we'll get you started.

Get Involved