Thursday, October 1, 2009

Hacking wmd-editor into using a custom image gallery

Oh man, I feel accomplished. I just finished hacking wmd editor to use a custom image gallery being generated server-side.

If you don't know, WMD editor is a WYSIWYG editor written in Javascript.

By default, when you click on the 'Insert Image' button you get a prompt allowing you to enter a URL.

Insert Image Screen

The functionality I was looking for was instead of showing you a text box where you could paste in the URL, I wanted to see more of a gallery type interface, that showed media that both you and others had uploaded. I also wanted to have a system where multiple files could be uploaded at once, and multiple files could be inserted at once.

There were primarily two challenges in attempting to accomplish that plan:

  • The WMD editor code doesn't really come with documentation. There are a handful of in-line comments and that's all you get. For the most part, I ignored them and read the code instead.
  • The WMD editor code is a little strange in areas.
Modifying WMD Editor
For the most part, I ended up not needing to change really all that much code. WMD editor is odd, yes, but workable.

The first task was to replace the default prompt function, with my own....
command.doLinkOrImage = function(chunk, postProcessing, isImage){

// ...

if (isImage) {
// OLD: util.prompt(imageDialogText, imageDefaultText, makeLinkMarkdown);
// WMD_IMAGE_GALLERY_URL loaded from a global settings elsewhere
util.imageGallery(WMD_IMAGE_GALLERY_URL, makeLinkMarkdown);
else {
util.prompt(linkDialogText, linkDefaultText, makeLinkMarkdown);

This was an easy change, and allowed to to write a pretty much drop-in replacement for util.promt().

This particular bit of code is jQuery-specific. It uses a div already existing on the page, #wmd-media-gallery, and applies jQuery UI's $.dialog() method to it, converted it into a popup modal dialog. The contents of the dialog is then loaded by AJAX. The URL that is loads is being specified in a global variable that is passed to it (WMD_IMAGE_GALLERY_URL).

util.imageGallery = function(gallery_url, makeLinkFunction){
gallery = $('#wmd-media-gallery');

if (gallery.html()) {
else {
gallery.css('visibility', 'visible');
gallery.load(gallery_url, function(){
title: 'Media Gallery',
bgiframe: true,
height: 550,
width: 900,
modal: true,
buttons: {
'Insert': function(){
// Enumerate images; insert those checked.
$('#wmd-media-gallery .media-insert').each(function(){
if ($(this).is(':checked')) {
img_path = $(this).attr('rel');
'Cancel': function() {$(this).dialog('close'); }

Pretty simple so far, right?

Well, here's the tricky part. If you notice what happens when the 'Insert' button is clicked, the code will scan the HTML of the dialog, and look for any input:checked element that has class "media-insert". For those elements which are found, it searches for ones which are checked. If a checked item is found, it will grab the Image URL out of the rel="" attribute, and pass that back to WMD editor for insertion into the edit box.

Ah, but not so fast. The problem comes in that WMD editor was not originally written to insert multiple images in such a way. With the stock code, what happens is it will inset one image inside another, thus only rendering 1 image properly, and leaving a mish-mash of code around it.

It should render this:
![alt text][1]
![alt text][2]

[1]: /some/url.jpg
[2]: /some/image.jpg
What it was rendering was this:
![alt text![alt text][1]][1]
The particular code in question lies int he command.addLinkDef() function. What needs to happen is that before that function processes the 'chunk', it must first clear the settings from the previous image out of it.

var getLink = function(wholeMatch, link, id, end){
// ...

// This goes after the getLink function

if (chunk.after.substring(0,2) == "][") {
chunk.before += chunk.selection + chunk.after.substring(0,2);
chunk.after = chunk.after.substring(2);
var linkEnd = chunk.after.indexOf(']');

chunk.before += chunk.after.substring(0, linkEnd);
chunk.selection = "";
chunk.after = chunk.after.substring(linkEnd + 1);

// ...and before the chunk.before [...] code

chunk.before = chunk.before.replace(regex, getLink);

And there you have it, you can now run custom image galleries from WMD editor. I'll leave it up to your imagination as to what you can do with that, but here's what mine ended up looking like:

Editor Window


Inserted Image

If you noticed, the django-uploadify app is being used in the gallery (hence why I began working on it).


  © Blogger template 'Minimalist G' by 2008

Back to TOP