Working with Terrible Code, Part One: Writing a CKEditor plugin

Understanding Terrible Code, Part One:

Writing a CKEditor Plugin

Exposition: Why should you care about a random text editor?

Modding CKEditor is a well-designed exercise in self-flagellation.

CKEditor is a text editor plugin that works with rich text (bold, italics, tables, links, etc.). If you’ve ever used Gmail or Hotmail, you’ve used something similar. ¬†CKEditor is relatively easy to use, powerful and has lots of features, and it’s used everywhere. But while the code is well written and well documented, at a macro level there are terrible design things going on, and if you want to modify¬†it, you’ll be glad you never did end up getting that gun license after all…

Since I’ve been wrestling with it for quite a while now, I wanted to share my thoughts:

  • In case you happen to be forced to alter CKEditor as well. Hopefully this will be a useful breadcrumb trail.
  • To convince myself I’m not faking it. CKEditor has well written source, in the sense of comments and indents and other things they do well, so someone could argue “maybe they’re doing it well and you just don’t get it.”
    This is a perfectly valid counterargument. The best way to figure out if I’m faking it is to actually try and explain why it’s bad, and see if this post turns into “CKEditor is an architectural marvel” in the process.
  • Complaining is whining unless you can explain why, and how to make things better.
  • I need to understand this stuff myself, and nothing helps with understanding like trying to explain.
  • Because I’ve been staring at this for days and need to say something.

Act One: Parallel Universe APIs

Half of CKEditor code essentially replicates JavaScript DOM APIs and jQuery. Let’s use the most radical example of CKEditor manipulation – the dialog architecture.

CKEditor dialogs are used for special properties. If you want to add a link, you would create a dialog to set the URL.

What language do you think dialogs would be designed in? Presumably a language that is used to lay things out in a web browser. Hmmm…what language do we use for that…HT nope, you’re right, it’s JavaScript:

The new dialog system in CKEditor is to be written from scratch. One of the key things in CKEditor is that it doesn’t rely on HTML pages to run. Everything is created on the fly in JavaScript. In this way, we avoid limitations about cross domain serving of the editor code, like CDN solutions, and enhance the editor performance.

http://docs.cksource.com/FCKeditor_3.x/Design_and_Architecture/Dialog_System#Dialog_Definition

We’ll get back to the benefits CKEditor claims later, but let’s think about this. You’re laying out a mini-web page. You’re a web developer and probably lay out web pages all the time. You read A List Apart obsessively; you understand the difference between content (HTML), presentation (CSS), and behavior (JavaScript), and the benefits of separating them.

And then you see this:

(This is actual dialog code that CKEditor uses to show a link dialog.)

Is that HTML? Yup – it looks like a <select> – there’s a list of options (items), and an id, and even a label.
Is that JavaScript? Yup – it’s got an onChange, a setup, and a commit, whatever that is.

This confuzzlement is compounded by the fact that there are about 1000 (literally, see for yourself) lines of this JavaScript/HTML hybrid. If you separated this into HTML and JavaScript, it would be easy to read, not indented six ten tabs in, and it wouldn’t take you an hour of sorting to figure out what a dialog that’s basically a handful of selects and some text fields is doing.

By the way, there’s CSS too:

1
2
3
        var basicCss =
            'background:url(' + CKEDITOR.getUrl( this.path + 'images/anchor.gif' ) + ') no-repeat ' + side + ' center;' +
            'border:1px dotted #00f;';
		var basicCss =
			'background:url(' + CKEDITOR.getUrl( this.path + 'images/anchor.gif' ) + ') no-repeat ' + side + ' center;' +
			'border:1px dotted #00f;';

Let’s establish some of the downsides of this mixed-content architecture:

  • Wading a thousand four-hundred line morass of mixed behavior and content every time you want to change things
  • No way to test the layout of your dialog without loading all of CKEditor (as opposed to HTML, which can be tested by anyone with a web browser)
  • You have to relearn all your HTML/JavaScript/CSS ninja skills in a weird JS hybrid
  • Oh and if you miss a brace, it’s not like missing an angle bracket – everything dies. JS is brittle. Did I mention you have to reload all of CKEditor to test your fixes?

So how about the benefits? The CKEditor docs claim that you can do cross domain* loading (for content delivery networks, etc.). While there are plenty of things wrong with the solution, the CDN problem is serious and it would be irresponsible to ignore it. Is there another way we can allow CDN loading without replacing all of our HTML with JavaScript?

One option: Write HTML for the dialogs, but convert it into escaped JavaScript internally. Escaped HTML is ugly, but if we compile it, we needn’t use it except in production.

Another option: Don’t use a 1-1 HTML counterpart, but use a simplified meta-language.

This rant is just barely getting started. Every time I work on CKEditor I’ll make sure to add more.

Leave a Reply

Your email address will not be published. Required fields are marked *