The stock image captioning application in Joomla! 1.5, caption.js, modifies the DOM of the page in ways that are not standards-compliant. The application inserts a <div> inside of a <p>, which obviously isn't permitted. This leads to unpredictable page rendering, and outright chokes Konqueror 3.5.10. Also, the existing application doesn't work for images inside of a hyperlink, which is downright silly, IMO.
I have rewritten caption.js to produce a valid structure using nested span tags. This nesting also permits nice styling of captioned image borders.
I have tested this in the current versions of IE, FF, Safari, Konqueror, Opera, and Chrome. I do not have access to any boxes still running IE 6, so I have not tested it on IE 6. I'm not too concerned about supporting IE 6, especially as Microsoft is putting the finishing touches on IE 8. That said, if you have access to IE 6, please let me know if the captioned images look acceptably close to how IE 7 or FF 3 renders them, so I can update this page.
The CSS
To style the captioned image, add these properties to your Joomla! theme's template.css file:
/* * BEGIN Properties for Improved Auto-Captioning script, caption.js */ /* Outermost container holding a captioned image, generated by caption.js */ .captioned_image_container { /* How much space between container & surrounding content? */ margin: 8px 8px 2px 8px; /* How much space on between container & the contained content? */ padding: 0px; display: block; text-align: left; width: auto; border: 1px solid #ccc; } .captioned_image_border { padding: 0px; text-align: left; display: block; } .image_wrapper, .img_caption { } /* Container holding image & maybe a link */ .image_wrapper { display: block; width: auto; } /* Container holding the image's caption */ .img_caption { text-align: center; display: block; padding: 2px; } /* The captioned image itself */ .caption, .caption2 { padding: 3px; } /* * END Properties for Improved Auto-Captioning script, caption.js */
Caption.js
Here is the improved version of caption.js
/** * @version $Id: modal.js 5263 2006-10-02 01:25:24Z webImagery $ * @copyright Copyright (C) 2005 - 2008 Open Source Matters. All rights reserved. * @license GNU/GPL, see LICENSE.php * Joomla! is free software. This version may have been modified pursuant * to the GNU General Public License, and as distributed it includes or * is derivative of works licensed under the GNU General Public License or * other free or open source software licenses. * See COPYRIGHT.php for copyright notices and details. * * Additional Copyright (c) 2008 Mark A. Taff <marktaff@comcast.net> * 20081123 Mark A. Taff: * The existing caption.js handled images within anchor tags inelegantly, * to be very kind. It now handles them better, so the caption text * is no longer a hyperlink, just the image is. * * In some instances, it also made the link take up the entire block, * in some cases making large chunks of the page a single link! * Links should not be so large nor so invisible as to make them easy to * inadvertently click on. ;-) * * Also, this new version spits out a valid DOM based on valid XHTML, so * Konqueror handles it properly. Konqueror 3.5.10 chokes on the old * version due to invalid XHTML (<div> inside of <p>). * * Changes licensed under the GNU/GPL, see LICENSE.php. * * 20090516 Mark A. Taff: * Incorporated changes submitted by Niklas Albin Svensson (Thanks!) on 20090511, * Copyright (c) 2009 In Defence of Marxism <webmaster@marxist.com>. Now we look first for * caption text in the title attribute, then in the alt attribute. This change makes * the script play nicer WYSIWYG editors. * * Also make it respect newlines in the caption, so it works with SlideShowPro Director * more smoothly. For the old behaviour, set `var respectNewLines = false;` in appendCaption(). */ /** * JCaption javascript behavior * * Used for displaying image captions * * @package Joomla * @since 1.5 * @version 1.0-taff-20090516 */ var JCaption = new Class({ initialize: function(selector) { this.selector = selector; var images = $$(selector); images.each(function(image){ this.createCaption(image); }, this); /** @bug: fixed. Force IE 7 to re-layout page after captions are applied. We just * temporarily append an arbitrary string ("forceReflow") to the body tag's * classname. This make IE re-calc relatively & absolutely positioned elements. */ var body = document.getElementsByTagName( "body" )[0]; var bodyClass = body.className; body.className = bodyClass+"forceReflow"; body.className = bodyClass; }, createCaption: function(image) { var parent = image.parentNode; var grandparent = parent.parentNode; // Create new elements... var captioned_image_container = document.createElement("span"); // container to hold captioned_image_border var captioned_image_border = document.createElement("span"); // container to hold image_wrapper var image_wrapper = document.createElement("span"); // container to hold image_caption var image_caption = document.createElement("span"); // container to hold the caption var text = document.createElement("span"); // span tag to hold the caption text var caption = ""; // Get the caption text, check first for title, then for alt if ( image.title != "" ) { caption = image.title; } else if ( image.alt != "") { caption = image.alt; } else { caption = ""; } // ...and assign their CSS classes, as needed captioned_image_container.className = "captioned_image_container"; captioned_image_border.className = "captioned_image_border"; image_wrapper.className = "image_wrapper"; image_caption.className = "image_caption"; // Get spec'd width, alignment & float properties from image var image_width = image.getAttribute("width"); var align = ""; if (image.style.styleFloat) {align = image.style.styleFloat;} // IE else if (image.style.cssFloat) {align = image.style.cssFloat;} // Standards-compliant browsers else if (image.getAttribute("align")) {align = image.getAttribute("align");} // Non-CSS, old HTML else {align = "";} // Is the image within an anchor tag? if (parent.nodeName == "A") { var link = parent; // Insert new span container right before the link grandparent.insertBefore(captioned_image_container, parent); captioned_image_container.appendChild(captioned_image_border); captioned_image_border.appendChild(image_wrapper); // Set alignment/float captioned_image_container.setAttribute("style","float: "+align); captioned_image_container.style.styleFloat = align; // IE // Reparent the link var removedLink = grandparent.removeChild(link); image_wrapper.appendChild(removedLink); // If the caption is set if ( image.title != "" || image.alt != "" ) { // Insert & format new span for caption captioned_image_container.appendChild(text); text.setAttribute("style","display: block"); text.className = this.selector.replace('.', '_'); // Set span class // Insert the caption itself this.appendCaption(caption, text); } } else // Image without a link { // Insert new span container right before the image parent.insertBefore(captioned_image_container, image); captioned_image_container.appendChild(captioned_image_border); captioned_image_border.appendChild(image_wrapper); // Set alignment/float captioned_image_container.setAttribute("style","float: "+align); captioned_image_container.style.styleFloat = align; // IE // Reparent the image var removedImage = parent.removeChild(image); image_wrapper.appendChild(removedImage); // If the caption is set if ( image.title != "" || image.alt != "" ) { // Insert & format new span for caption captioned_image_container.insertBefore(text, null) text.setAttribute("style","display: block"); text.className = this.selector.replace('.', '_'); // Set span class // Insert the caption itself this.appendCaption(caption, text); } } // End if (parent.nodeName=="A") ... else // Set widths/heights as needed for the various containers image_wrapper.style.width = image.offsetWidth+"px"; image_wrapper.style.height = image.offsetHeight+"px"; captioned_image_border.style.width = image_wrapper.offsetWidth+"px"; captioned_image_container.style.width = captioned_image_border.offsetWidth+"px"; }, // End method createCaption(element) // Inserts a caption, respecting newlines appendCaption: function(caption, text) { // Set to false ignore newlines in caption text var respectNewLines = true; if (respectNewLines) { var captionLines = caption.split("\n"); for(i=0; i < captionLines.length; ++i) { line = document.createTextNode(captionLines[i]); br = document.createElement("br"); text.appendChild(line); text.appendChild(br); } } else { text.appendChild(caption); } } }); document.caption = null window.addEvent('load', function() { var caption = new JCaption('img.caption') document.caption = caption });
Download & Install
I strongly suggest that you rename the existing caption.js (to caption.js.bak, for example) rather than overwriting or deleteing it. That way, you can always easily reinstall the original should you need to. Download caption.js. Once you have the original archived, simply upload the new version. Don't forget to add the new CSS properties to your template.css file.






















