jQuery isn’t going anywhere. It’s the most widely used JavaScript-library, it has a huge community, and offers a plethora of plugins. With its wide-spread acceptance, it’s not surprising when CMS developers (Tridionauts and the like) get prototypes using different jQuery plugins like modal windows or carousels. What is surprising, however, is how often these jQuery plugins don’t transition well into a CMS. It then becomes commonplace that content authors get frustrated with the CMS and its developers for the inflexibility of a plugin. Let’s talk about how to fix that.
First, a use case
Let’s start with a real-live scenario that I’ve dealt with: modal windows. A modal window is a fun little box that draws on the page, grays out the background, and annoys the user by being a barrier to content…kind of like a flash intro. So the client presents you with these requirements:
- ability to create modal windows on a page
- Ability to edit height and width
- Ability to control position
- Ability to control whether there is a title
Let’s also say that you’ve been given visual mockups, but not a static HTML prototype. You have the freedom to pick and edit whichever plugin you like.
A Typical Implementation of a jQuery Widget
Following modal windows as the use-case, the first step might be to check with your good buddy Google and see what plugins are available. After you’ve picked your plugin, you’ll have a few steps to implement the jQuery plugin through a CMS (such as Tridion):
- Upload the minified version of the plugin’s JavaScript; e.g.:someModal.min.js
- Upload the minified version of the plugin’s CSS; e.g.:someModal.min.css
- Upload the plugins assets; e.g.: someModal__closebutton.png
- Edit a global JavaScript file to fire the plugin
Step four is the kicker: A typical modal window would get fired in some sort of $(document).ready()
event in a JavaScript file that’s loaded after the jQuery library loads, like so:
$(document).ready(function(e){ $('.someElement').someModal(); });
This is great, so long as there isn’t a business need for variations on this modal window. But if such a business need were to exist…well that’s the point of this post.
The first option is to hard-code the solution into the JavaScript file applied to the website. Further changes are delivered by a developer with JavaScript experience. Content authors are unlikely to write LinkedIn recommendations with this approach.
JavaScript file
$(document).ready(function(e){ $('.someElement').someModal({height: 400}); $('.someOtherElement').someModal({height: 500}); $('.oneMoreElement').someModal({height: 500, width: 500}); });
The second option is to hard-code the solution in some “code component” on the page. This requires that jQuery be loaded in the <head>
, so that the in-body script executes after jQuery has loaded. CMS developers are likely to offer this solution, and content authors who are familiar with writing code are likely to negotiate down to this. A content author might endorse a skill for us on LinkedIn, but there’s no guarantees it won’t be sarcastic in nature.
Code Component
A third option, is to take content from a component in the CMS (in Tridion this is a schema) and generate parameters which are sent into the jQuery method. This still requires jQuery being placed in the <head>
. CMS developers are unlikely to offer this solution while content authors are most likely to dedicate blogs to our ingenuity (that’s how it plays out in my fantasy, anyway).
Razor Template
The problem
There are several objections that a client might have with the traditional solutions for jQuery widgets:
- Hard-coding in the website’s JS file makes it difficult for content authors to manage
- Many enterprise CMS have change control requirements that may prevent a rapid change to a JavaScript file
- A code component option forces a content author to learn code
- creating an option to inject code into a page without restriction can lead to rapid degradation of the user experience
- Large companies may have a strict “division of labor” policy that prevents content authors from writing JavaScript
The real problem
It’s not really the jQuery or JavaScript that’s the problem. The real issue is that we’re confusing the business needs. A client needs to have a certain amount of controls over user interactions, and our solution is to give them control over the code. This is the flaw:
Content-author-managed user-interactions are content. The code that produces those interactions is not.
The Solution
Now that we’ve correctly identified the problem, we can explore a solution that has worked successfully in the last few projects I’ve had.
Disregard tradition
The traditional way to send parameters and configurations to a jQuery plugin is through the method:
$('.someElement').someModal({ top: '100px', dimensions: { height: '200px', width: '300px'; }, closeButton: true, title: "Hey there, I'm someModal", overlay: .5, src: '#someOtherElement' })
This is how the vast majority of jQuery plugins work, and there is nothing wrong with this approach, so long as the ones using it can write JavaScript.
Store jQuery parameters in the HTML
The solution is in the data-*
attribute. Though popular guys like John Resig tout this as an HTML5 feature, putting a data-attribute
on an element has been supported since IE5.5.
So what does this look like? Well, like a whole bunch of attributes in the HTML:
We could have one attribute with some well formatted JSON in it:
Click Me
Or we could have multiple attributes:
Click Me
The jQuery that then runs off of a single selector—the attribute that contains your parameters:
$('[data-modal]').someModal();
Modify the plugin
Within the plugin itself, it might need some minor modifications so that it can accept one, or many, attributes from the HTML. Many jQuery plugins use the options
variable as the object for the parameters which are passed into it:
//first, grab the data-modal attribute using the .data() method var metadata = !$(this).data('modal') ? options : $(this).data('modal'); //next, we create a set of all attributes on this element var attrs = document.getElementById($(this).attr('id')).attributes, l = attrs.length, attr, elName; //then, we loop through all of these attributes for (i = 0; i < l; i++) { attr = attrs.item(i); //finally, we add these attributes to our metadata variable, if they match the modal if (attr.nodeName.match('data-modal-')) { elName = attr.nodeName.replace('data-modal-', ''); metadata[elName] = attr.nodeValue; } }
Build a CMS solution
For Tridion, this is an especially easy solution now. It's common place for Tridion template developers to control attributes of an element with a good schema+TBB combination. Building on the previous HTML and jQuery examples, each attribute could be its own field in the schema, and then the job of the razor template becomes a collection of ternary operators:
Click Me
The solution is ultimately a three-part plan:
- Put
data-
attributes in the HTML - Modify the jQuery plugin to accept attributes
- If necessary, create a supporting schema and TBB to make all options content-manageable
The Big Idea
jQuery plugins aren't often written with a CMS in mind. Because of this fault in the jQuery community, CMS developers (including Tridion devs), mistakenly pass this fault onto the content authors with either few limitations, or unnecessary training. Instead, we should modify those jQuery plugins to accept parameters from HTML. Allowing jQuery plugins to be managed from HTML extends us the ability to further configure them from well-formed schemas and component templates.