diff --git a/README.txt b/README.txt
index fc963d7..302d7da 100644
--- a/README.txt
+++ b/README.txt
@@ -23,7 +23,7 @@ While entering content, choose an input format that utilizes the caption filter.
In a plain textarea, the entered code should look like this:
A simple caption:
-[caption]This is an image caption[/caption]
+[caption caption="This is an image caption"][/caption]
Aligned Caption (can be left, center or right):
-[caption align=right]This is a right aligned caption[/caption]
+[caption caption="This is a right aligned caption" align="right"][/caption]
diff --git a/caption-filter.css b/caption-filter.css
index 4fc991a..0b4a9ca 100644
--- a/caption-filter.css
+++ b/caption-filter.css
@@ -18,7 +18,7 @@ div.caption-inner {
width: auto;
}
-div.caption p {
+div.caption p.caption-text {
margin: .25em 0;
}
diff --git a/caption_filter.module b/caption_filter.module
index 783bf8e..45c984e 100644
--- a/caption_filter.module
+++ b/caption_filter.module
@@ -40,12 +40,12 @@ function caption_filter_tips($filter, $format, $long = FALSE) {
You may wrap images or embeds with a caption using the code [caption]IMAGE caption[/caption].
Examples:
-
Single Image: [caption]This is a caption[/caption]
-
Align the video: [caption align=right]This is another caption[/caption]
+
Single Image: [caption caption="This is a caption"][/caption]
+
Align the video: [caption caption="This is another caption" align="right"][/caption]
');
}
else {
- return check_plain(t('Captions may be specified with [caption]Image caption[/caption]. Items can be aligned with [caption align=left].'));
+ return check_plain(t('Captions may be specified with [caption caption="Image caption"][/caption]. Items can be aligned with [caption align="left"].'));
}
}
@@ -68,12 +68,33 @@ function caption_filter_process_filter($text, $filter) {
* HTML output.
*/
function _caption_filter_replace($matches) {
- $caption_attributes = _caption_filter_tag_attributes($matches[2]);
+ $caption_attributes_filtered = str_replace('\"', '"', $matches[2]);
+ $caption_attributes = _caption_filter_tag_attributes($caption_attributes_filtered);
$item = $matches[3];
$width = _caption_filter_get_width($item);
$align = isset($caption_attributes['align']) ? $caption_attributes['align'] : 'center';
- $caption = isset($caption_attributes['caption']) ? $caption_attributes['caption'] : '';
+
+ // Determine the caption value from the formal attributes of [caption]
+ $caption = (isset($caption_attributes['caption'])) ? $caption_attributes['caption'] : '';
+
+ // Legacy fallback - If there is no formal attribute, try to infer from the HTML
+ // and then assign the caption to $caption and the $item to the remainder
+ if (empty($caption)) {
+ if (preg_match('/(.*)/i', $item, $legacy_img) && !empty($legacy_img[1])) {
+ $caption = $legacy_img[1];
+ } else if (preg_match('/(.*)/i', $item, $legacy_iframe) && !empty($legacy_iframe[1])) {
+ $caption = $legacy_iframe[1];
+ } else if (preg_match('/(.*)/i', $item, $legacy_embed) && !empty($legacy_embed[1])) {
+ $caption = $legacy_embed[1];
+ } else if (preg_match('/(.*)/i', $item, $legacy_obejct) && !empty($legacy_obejct[1])) {
+ $caption = $legacy_obejct[1];
+ }
+ }
+
+ // Determine the content value. This is any HTML content that is inside the [caption] that isn't
+ // part of the actual caption text
+ $content = str_replace($caption, '', $item);
// Remove "align" from the start of the alignment if needed. WordPress
// commonly uses align="alignright" for example.
@@ -81,7 +102,13 @@ function _caption_filter_replace($matches) {
$align = substr($align, 5);
}
- return '
'. $item . $caption .'
';
+ // If we have a caption, output markup to wrap the caption in a specific tag and class
+ if (!empty($caption)) {
+ return '
'. $content . '
' . $caption .'
';
+ }
+ else {
+ return '
'. $content . '
';
+ }
}
/**
@@ -338,3 +365,88 @@ function caption_filter_field_widget_caption_validate($element, &$form_state) {
form_error($element, t('The Title field must be enabled to use it as a caption.'));
}
}
+
+/**
+ * Implements hook_menu().
+ */
+function caption_filter_menu() {
+ // Dialog callback for the TinyMCE button.
+ $items['caption_filter/tinymce'] = array(
+ 'title' => 'Image caption',
+ 'page callback' => 'caption_filter_tinymce_button',
+ 'access arguments' => array('access content'),
+ 'type' => MENU_CALLBACK,
+ );
+ return $items;
+}
+
+/**
+ * Menu page callback; the TinyMCE button dialog.
+ */
+function caption_filter_tinymce_button() {
+ // Suppress the admin menu in the popup.
+ module_invoke('admin_menu', 'suppress');
+ if (module_exists('wysiwyg') && $editor = wysiwyg_get_editor('tinymce')) {
+ drupal_add_js($editor['library path'] . '/tiny_mce_popup.js');
+ }
+ drupal_add_js(drupal_get_path('module', 'caption_filter') . '/js/caption-filter-tinymce-button.js');
+ drupal_add_js(drupal_get_path('module', 'caption_filter') . '/js/caption-filter.js');
+
+ $form = drupal_get_form('caption_filter_tinymce_button_form');
+ $output = theme('caption_filter_tinymce_button', array('form' => $form));
+
+ // Write directly to the window and quit rather than returning so the modal
+ // doesn't get themed as a Drupal page.
+ echo $output;
+ exit;
+}
+
+/**
+ * Form builder; the TinyMCE button dialog.
+ */
+function caption_filter_tinymce_button_form() {
+ $form['#action'] = '#';
+ $form['#attributes'] = array('onsubmit' => 'CaptionFilterButton.insert(); return false;');
+ $form['caption'] = array(
+ '#title' => t('Caption'),
+ '#type' => 'textarea',
+ '#rows' => 4,
+ '#default_value' => '',
+ '#attributes' => array('class' => array('field', 'mceFocus')),
+ );
+ $form['align'] = array(
+ '#title' => t('Float'),
+ '#type' => 'select',
+ '#options' => array(
+ 0 => t('None'),
+ 'left' => t('Left'),
+ 'right' => t('Right'),
+ ),
+ '#default_value' => 0,
+ '#attributes' => array('class' => array('field')),
+ );
+ $form['actions'] = array(
+ '#type' => 'container',
+ '#attributes' => array('class' => array('mceActionPanel')),
+ );
+ $form['actions']['insert'] = array(
+ '#markup' => '',
+ );
+ $form['actions']['cancel'] = array(
+ '#markup' => '',
+ );
+ return $form;
+}
+
+/**
+ * Implements hook_theme().
+ */
+function caption_filter_theme($existing, $type, $theme, $path) {
+ return array(
+ 'caption_filter_tinymce_button' => array(
+ 'variables' => array('form' => array()),
+ 'path' => drupal_get_path('module', 'caption_filter') . '/js',
+ 'template' => 'caption-filter-tinymce-button',
+ ),
+ );
+}
diff --git a/js/caption-filter-tinymce-button.js b/js/caption-filter-tinymce-button.js
new file mode 100644
index 0000000..2e32490
--- /dev/null
+++ b/js/caption-filter-tinymce-button.js
@@ -0,0 +1,95 @@
+/**
+ * @file
+ * Functionality for implementing the caption filter button in tinyMCE.
+ */
+var CaptionFilterButton = {
+ init : function() {
+ var ed = tinyMCEPopup.editor;
+ var node = ed.selection.getNode();
+ var p = ed.dom.getParents(node, 'DIV');
+ var f = document.forms[0];
+
+ // Only pre-populate values if we're inside an existing caption.
+ if (p[0] && ed.dom.hasClass(p[0], 'caption-inner')
+ && p[2] && ed.dom.hasClass(p[2], 'caption')) {
+ // Parse the entire caption block to get the original [caption] tag.
+ var tag = Drupal.captionFilter.toTag(p[2].outerHTML);
+
+ // Filter the tag elements to have " elements
+ tag = tag.replace(/\\"/g, '"');
+
+ // Extract the caption from the [caption] attribute first, caption-text class second, raw text third.
+ // fails default to the HTML.
+ var caption_attribute = tag.match(/^\[caption.*caption=\"([^"]*)\".*\].*\[\/caption\]$/);
+ var caption_wrapper = tag.match(/^\[caption.*\]\
(.*)<\/p>\[\/caption\]$/);
+ var caption_html = tag.match(/^\[caption.*\]\(.*)\[\/caption\]$/);
+ if (caption_attribute && caption_attribute[1]) {
+ f.caption.value = caption_attribute[1];
+ }
+ else if (caption_wrapper && caption_wrapper[1]) {
+ f.caption.value = caption_wrapper[1];
+ }
+ else if (caption_html && caption_html[1]) {
+ f.caption.value = caption_html[1];
+ }
+
+ // Filter the caption value to replace double quotes
+ f.caption.value = f.caption.value.replace(/\"/g, '"');
+
+ // Extract the alignment.
+ var align = tag.match(/^\[caption.*align=\"([^"]*)\".*\].*\[\/caption\]$/);
+ if (align && align[1]) {
+ f.align.value = align[1];
+ }
+ }
+ },
+
+ insert : function() {
+ var ed = tinyMCEPopup.editor;
+ var node = ed.selection.getNode();
+ var p = ed.dom.getParents(node, 'DIV');
+ var align = document.forms[0].align.value;
+ var caption = document.forms[0].caption.value;
+ var image;
+ var tag;
+ var replace = false;
+ // If we're inside an existing caption...
+ if (p[0] && ed.dom.hasClass(p[0], 'caption-inner')
+ && p[2] && ed.dom.hasClass(p[2], 'caption')) {
+ replace = true;
+ // Recall the original [caption] tag.
+ tag = Drupal.captionFilter.toTag(p[2].outerHTML);
+ // Select the outer DIV so we can replace the entire thing.
+ ed.selection.select(p[2]);
+ // If we're in an existing caption, parse it from the [caption] tag.
+ var parse = tag.match(/^\[caption.*\](\)(.*)\[\/caption\]$/);
+ if (parse[1]) {
+ image = parse[1];
+ }
+ }
+ // Get the image HTML.
+ else if (node.nodeName === 'IMG') {
+ // If we're on the image, just use it.
+ image = node.outerHTML;
+ }
+ var newtag = '[caption';
+ if (align == 'right' || align == 'left') {
+ newtag += ' align="' + align + '"';
+ }
+ if (caption) {
+ newtag += ' caption="' + caption.replace(/"/g, '\\"') + '"';
+ }
+ newtag += ']' + image + '[/caption]';
+
+ // Create the new [caption] tag.
+ if (replace === true){
+ ed.dom.remove(p[2], false);
+ ed.execCommand('mceReplaceContent', false, newtag);
+ } else {
+ ed.execCommand('mceReplaceContent', false, newtag);
+ }
+ tinyMCEPopup.close();
+ }
+};
+
+tinyMCEPopup.onInit.add(CaptionFilterButton.init, CaptionFilterButton);
diff --git a/js/caption-filter-tinymce-button.tpl.php b/js/caption-filter-tinymce-button.tpl.php
new file mode 100644
index 0000000..7241414
--- /dev/null
+++ b/js/caption-filter-tinymce-button.tpl.php
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/js/caption-filter-tinymce.js b/js/caption-filter-tinymce.js
index 8e26f7b..d266c09 100644
--- a/js/caption-filter-tinymce.js
+++ b/js/caption-filter-tinymce.js
@@ -9,12 +9,48 @@
* @see http://core.svn.wordpress.org/branches/3.2/wp-admin/js/editor.dev.js
*/
(function() {
+ // Load the plugin-specific language pack.
+ tinymce.PluginManager.requireLangPack('captionfilter');
+
tinymce.create('tinymce.plugins.CaptionFilter', {
init : function(ed, url) {
var t = this;
t.url = url;
+ // Register the command.
+ ed.addCommand('CaptionFilter', function() {
+ ed.windowManager.open({
+ file : Drupal.settings.basePath + 'index.php?q=caption_filter/tinymce',
+ width : 400 + parseInt(ed.getLang('captionfilter.delta_width', 0)),
+ height : 200 + parseInt(ed.getLang('captionfilter.delta_height', 0)),
+ inline : 1
+ }, {
+ plugin_url : url
+ });
+ });
+
+ // Register the button.
+ ed.addButton('captionfilter', {
+ title : 'captionfilter.desc',
+ cmd : 'CaptionFilter',
+ image : url + '/caption-filter.gif'
+ });
+
+ // Add a handler to activate/deactivate the button.
+ ed.onNodeChange.add(function(ed, command, node) {
+ var p = ed.dom.getParent(node, 'DIV');
+ var selection = ed.selection.getContent();
+
+ // Enable if an image is selected, or if inside an existing caption.
+ command.setDisabled('captionfilter',
+ !(node.nodeName === 'IMG' && selection) &&
+ !(p && ed.dom.hasClass(p, 'caption-inner'))
+ );
+ // Light up the button if inside an existing caption.
+ command.setActive('captionfilter', p && ed.dom.hasClass(p, 'caption-inner'));
+ });
+
function _do_filter(ed, o) {
o.content = Drupal.captionFilter.toHTML(o.content, 'tinymce');
};
@@ -30,10 +66,6 @@
// Resize the caption wrapper when the image is soft-resized by the user.
ed.onMouseUp.add(function(ed, e) {
- // Webkit (Safari/Chrome) and Opera currently don't have resize handles.
- if (tinymce.isWebKit || tinymce.isOpera)
- return;
-
var img = ed.selection.getNode();
if (img.nodeName == 'IMG') {
window.setTimeout(function(){
@@ -107,7 +139,7 @@
align = cmd.substr(7).toLowerCase();
wrapperClass = 'caption-' + align;
ed.dom.addClass(captionWrapper, wrapperClass);
-
+
if (align == 'center')
ed.dom.addClass(captionWrapper, 'mceIEcenter');
else
diff --git a/js/caption-filter.gif b/js/caption-filter.gif
new file mode 100644
index 0000000000000000000000000000000000000000..9bcffe66b0a0907efebcc88618b487bb8ec8a63e
GIT binary patch
literal 122
zcmZ?wbhEHb6k!lyIK;*P1Pu)h2M!!Ke*E~shu=Sa`t%