Drupal/Editable Blocks

From ThinkyWiki

Jump to: navigation, search

Contents

Making Drupal Simpler

Although the codebase is a bit of a mess (and its edit functions are incompatible with Safari and Chrome) the Gravity Switch CMS does one very nice trick, which is to allow pages to be built inline. The layout of regions is predetermined by templates, but the contents of those regions is editable. In fact each region can contain any number of editable blocks. And those blocks, like Drupal blocks, can be static content, PHP code, or other kinds of blocks - such as calendars - supplied by CMS extensions.

WYSIWYG Editing

WYSIWYGs are very fussy creations. It took some time to get YUI editor to start behaving on my home test site. It now seems stable enough but there are display problems. On the Veterans site I tried WYSIWYG API, first with TinyMCE and YUI, then with FCKEditor. WYSIWYG API support for FCKEditor is minimal (I hope to fix that), however the FCKEditor is supported by the FCK Module which is very solid and configurable. All the WYSIWYGs I tested have hooks for inserting your own CSS and for customizing features. They all make it pretty easy.

  • TinyMCE is very nice and integrates really well with WYSIWYG API. With TinyMCE 2 the interface of WYSIWYG API showed all the button graphics, but not so with TinyMCE 3, which was disappointing. I found it to be very solid, but I ran into some snags with file uploads and decided to try other options. I haven't been back yet, but I might try again soon with other image browsers.
  • YUI feels kind of massive. (Look how many .js files it includes!) However it's very pretty and it seems to integrate perfectly with WYSIWYG API. It works really well in Firefox. It has the best image dialog of the bunch. However, overall it feels a little rusty. The default interface is kind of big and fluffy.
  • FCKEditor is a perfect medium. With all its buttons enabled it looks like Microsoft Word - almost exactly. It integrates with a host of image browsers,

Image Uploaders

I tested several image uploaders and managers, all using FCKEditor as the test-bed because it has the easiest configuration (it just recognizes them). What I hoped to find was something ultimately simple, with just an upload button, alt tag and title input fields, and an alignment popup. What I found was a mixed bag, but nothing that impressed me enough to convert me to image managers. I'll say more about that in a minute.

The built-in uploader has no automated tracking of images. FCKEditor is a "dumb editor" and doesn't pay attention to img tags especially. If you delete an image from the content it still remains on disk.

Image managers exist to fill the gaps left by WYSIWYG editors, namely that they don't track the media embedded in them. The paradigm is to treat them as links to external objects and let the web designer manage assets like a big library. They provide a graphical way to sift through images for the thing you want to insert. But they suck. Images can be freely rearranged in folders, but links don't get updated in the content. An editor can easily delete images by mistake without any way to undo. Links broken in this way aren't detected as they happen, only later by chance.

To sum up, online image managers suck for managing content, especially as sites grow. Moreover, they put all the pressure on the user to track images and other media. The power of the system to associate content goes completely unused.

One possible solution is to use the Image Assist plugin. When you upload an image with Image Assist it becomes an Image node. This at least places images on the same level as other content. Since files are managed as nodes they don't move on disk. However, Image Assist comes with several negatives as well:

  • Images end up being intermixed with content
  • The only meta data available is image title and time of upload
  • The editor still doesn't know if deleting an image breaks links in content

Test Cases

  • The minimal FCKEditor image selector has 4 tabs (you can turn at least one of them - Advanced). The interface is simple but it could be prettier. It works just fine.
  • IMCE is an image browser and file manager that I kind of liked. I found some compatibility issues.
  • Image Assist - This completely replaces the Image button in FCKEditor. (I removed the button manually by editing its .js config file.) It manages images as nodes, so that you can track and delete them like other content. Image nodes can also be used in galleries, categorized or tagged, and incorporated into RSS feeds, etc. The problem with this - as I recall [edit later] - is it had some buttons that didn't actually apply when inserting, and no real image management. It can insert captions, but the markup is minimal, and might need work to accommodate all the browsers.
  • http://drupalmodules.com/module/image-browser - This one looks really promising. I'll give it a try ASAP. Like Image Assist it makes images into nodes. But it may have other features that actually make it worthwhile for certain use cases.

The short long story is that we have a lot to choose from. The ones we like best we can adapt to our own style and needs.

The main anomaly in my tests was YUI. It performed pretty well on Firefox but wouldn't work properly with Safari despite lots of tweaking. It's a little eccentric, but it provides a nice set of tools and surprise keyboard shortcuts like command-shift-[ ] and | for text alignment.

Transparent Image Management

The solution gsCMS employs (?) is the best I can imagine, though I'd like to see it improved even more. (For example, caching reduced images.) As I understand it when an image tag is inserted into any content this is noted in the database. Changes to content are tracked so that whenever an image tag goes away the corresponding image file gets deleted too. This makes all such images completely hidden from the rest of the system, which reduces complexity. The image only goes away when the content changes. If revisions are in use, it should only go away when all revisions that include it are removed.

If this is what gsCMS does, then kudos! That's what I want to implement for the corresponding stuff in Drupal. It may seem like a horrendous job to track images in this way, but actually the problem is trivial. Drupal provides hooks so your module can take action whenever a form is submitted. So we can easily put the tracking code in this hook. The hook looks at the SRC attribute of any <img> tags it finds. It compares these to a stored list. If a new image appears it's stored. If one goes away it's deleted. If revisions are in use all revisions are tested before deletion.

It may be useful in some cases to track embedded images, and this is very easy to accomplish with a custom admin page. And the data could be used for other purposes like tracking a user's upload quota or computing the storage size for all articles in a given section. Images from recent articles could be displayed in blocks for a nice graphical touch.

Summing Up

As I tested these modules and plugins in Drupal I was pleased at how quickly I could switch from one to another without fear of breaking anything. This struck me more than once as I realized I'd completely switched to a new WYSIWYG editor and was zipping along reordering its buttons after only a few minutes.

Inline Editing

We want to make the editors inline, if possible. I'm investigating this possibility, most certainly possible with some clever tweaks. First I need to find a more general solution, putting up a content box for page sections, and mess with AJAX some just to be clever about it.

Arbitrary Content

The Gravity Switch CMS has a paradigm wherein you add content to pages arbitrarily. The idea works like this. You first create a page. The page has various settings which determine its path in the menus, its title, its template, and some of its behavior. But the content of the page is not determined at this stage. Instead you get a blank page with a set of content areas, and you can keep adding content of different kinds to each area, within certain limitations. For example, you can't add a news list to a very narrow column. The high-level concept of content is that it falls in a certain page region, in a certain order, and the content for one page doesn't appear on another. In other words, the page key is a content index.

How is this adaptable to Drupal, which seems to have a whole different paradigm for content management? To determine this, we must try to map gsCMS content to Drupal content and see if the difference is fundamental, or if Drupal can be polymorphic.

First, I have to talk through it! In Drupal you have the concept of a page, which is generally an isolated view of some individual content, or often a view of some kind which fills the content area with an overview or list of content items. In Drupal terms, modules can provide page content any way they see fit. So one approach you can imagine is to provide an interface for building a page that would direct the creation of various kinds of content, or overviews, and then provide a page path handler to iterate through the various items and render them into the page. But then we forget about the other regions of the page, which in Drupal are provided by Blocks. And come to think of it, Drupal does in fact have a facility for rendering a list of items into a page region - again it's the Block engine.

As it turns out, it's entirely possible to guide the behavior of the back-end block forms and other elements. In the VHAF site I insert an EDIT link into a sidebar block on the home page, and after the block is edited it redirects back to the page. This is not inline (which is overrated) but it begins to show what is possible. Drupal also has a simple hook to create a block. This can easily be customized through a module so that its visible location is pre-set, including both the path filter and the region name.

If needed, an intermediate path can be used which converts the block's page, region, and delta into a particular block id to edit. This can be done using the existing url alias system.

The only thing left to do is to provide regions where blocks can go in the main content area. Then everything is done as blocks, and just using the existing block system you can add piles of content to any page region. On larger sites, the number of blocks would become quickly unwieldy to manage from the Blocks interface, so it would become necessary to provide all the content editing controls on each page, in context, which is what GS CMS does well. If overview lists are needed, those can be implemented easily as well.

This kind of content management sounds fine with static content blocks and PHP blocks, but what about more complex things like News and Event lists? These GS CMS entities are the same concept as Drupal Views. So it makes sense that the Views API provides the answer. To start with, create a set of basic view blocks, one for each content type. These will be used as templates for new blocks. Now when the admin wants to add a new event list to the page, you present the form which clones the view and allows some basic customization. When the view is created, the block starts out invisible and unassigned. So as an additional step the view's block would have to enabled and set to appear in the proper place.

The last thing needed to make this more like GS CMS is to change the way pages are defined. Either make the Body always blank for the "Page" content type or call it a static heading - a safe piece of content that no admin can remove without having page editing permission. Another possibility is to use the page's Body field as a place to provide a page summary, a feature of GS CMS that's used for SEO, RSS, and META tags.

What about other kinds of custom blocks? Does every new piece of content require the addition of yet another block to the back-end interface? In fact, no. Perhaps none of these things do. Instead you have smart blocks that use custom parameters associated with a given path. These are used to produce content of the desired type. So for example, you have a single "event list" block that displays an event list view, passing it parameters. When that type of block is added to your page, you simply add another instance of the block to a list. It's an interesting possibility, to invoke blocks programmatically, but doable.

Another crazy possibility is to implement everything as nodes and just let every page region be a view that displays these nodes. How do the nodes work? For basic content they work like normal nodes, but for an event list the node actually wraps a view. It has a set of custom parameters which can be added with good old CCK, but the underlying display logic actually invokes a base view, again passing it parameters which are derived from the node form. The node-to-view connection happens at some point in the theming process, of all places. The node needs to invoke a view and get it to do all its fetching, hooking, etc, and finally get it totally themed.

So what about these views - one per page region and that many per page? That could also get unwieldy. Can views be synthesized? At the lowest level you could just build it all in PHP straight to the database. But that's not why we use Drupal. I don't think it needs to get lower than the node level, because at center the most atomic thing being displayed is a node. One or more in a given region, and that's all. A news or event list presents a special challenge, because it's nice to be able to use existing apparatus to show them. These are things keyed by date, limited in number, perhaps having a pager, and are perfect for views...

All this bears some experimentation!

UPDATE: See the Panels module for a decent - but perhaps not client-friendly - interface. http://drupal.org/project/panels

Personal tools