Manage CSS and Javascript from the Admin UI

Posted by Jim Gay on Tuesday, August 03, 2010 | |

Yesterday I committed a new core extension to Radiant: Sheets

With this new feature you can manage stylesheets and javascripts from the admin interface, but before I get into the details of it you should be aware that if you don’t want this feature, you can simply prevent it from being loaded with:

config.extensions -= [:sheets]

What is Sheets?

Sheets is a way to manage stylesheets and scripts from your existing page tree. With Sheets, you’ll create new types of pages: JavascriptPage and StylesheetPage.

Pages of these types are Sheets.

The basic features:

Differences with other solutions and the benefit of using Sheets

Some standard site templates provided by Radiant include stylesheet content in a typical page. This requires a custom layout merely to set the content type, and displays content unintended for editing by typical users. This makes for a cluttered page index view and cluttered layout index view.

A popular solution to these problems is the SNS extension . SNS separates the editing interfaces for these types of content, but the problem is that it makes too much of a separation. With SNS, stylesheet and javascript content is stored in a separate table and is generated by models completely unrelated to the Page model. This means that other extensions are required to do extra work to provide features and Radius tags to SNS content, and as a result many extensions do not do this work. This situation makes for a confusing introduction to Radiant for new users and developers alike.

You can get around this SNS limitation by using the SNS Page Hook extension but even this solution will lead to unpredictable results because it merely copies modules from the Page model to the TextAsset model and tricks the included methods into believing they are operating on a Page. But this is not a good long-term solution.

Sheets keeps this content in the same location as all other content: Pages. Doing it this way allows any chosen URL or Page slug to be protected properly with newly created pages. Even more importantly, this allows user and developer expectations about the behavior of Radius tags to make sense. With Sheets, extensions which add Radius tags to the Page model add them to stylesheets and javascripts too; there is no extra work to be done.

Not only does it do all this, but the standard Page model provides a headers method which Sheets overrides to alter the mime-type for the returned content. Sheets uses the built-in ways to serve content, rather than generating yet another way to serve content like SNS.

Extra features

By default Sheets has a SassFilter for text and since Radiant depends on (and includes) Sass, you’ll always have that available. But the SassFilter is just a regular TextFilter like the ones used on pages so I had to do some work to ensure that you wouldn’t be able to filter your typical Page content with Sass.

The SheetsExtension has 2 accessors: stylesheet_filters and javascript_filters.

You may manipulate the contents of these variables with your added text filters. You could write an extension to provide a Less filter:

SheetsExtension.stylesheet_filters << LessFilter

In the future, it will probably be a good idea to move these accessors off of the SheetsExtension itself and onto the ApplicationController so that you don’t need to worry about extension load order to add a text filter.

Currently, there is no interface element to alter the path from where your site will pull content. CSS is pulled from /css and Javascripts are pulled from /js. SNS was standardizing this approach because changing this setting required running rake tasks and not merely changing a simple setting. With Sheets, the path is determined by a page slug so in the future we’ll have a way to change that location to /whatever-you-want (but if you really want to do it now just jump in the console find the css or js pages and change their slugs).

I will be providing the ability to migrate your content from SNS to the page tree in some way (be it in the Sheets extension itself, in SNS, or some other migrator extension).

I still need to write some specs and cucumber features but I wanted to get this out in the wild to get feedback, so please leave your complaints or praise here.

Reasons for the change from SNS

Aside from the reasons I’ve listed above I could only see more difficulty down the road in getting TextAssets to behave the way you’d expect. I’ve been committing a lot of changes to SNS and recently wrote the SNS Page Hook extension to deal with these problems.

In previous versions of SNS and Radiant, the SNS approach made sense. It setup a separate ResponseCache to serve stylesheet content and javascript content from separate locations. And it completely separated those TextAssets from your page tree which makes a lot of sense for users, but developers who have worked with SNS have expected to be able to use any radius tag in the system and they couldn’t.

If you’re a user of SNS, I really think you’ll like the change to Sheets.