Index: INSTALL.txt =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/img_assist/INSTALL.txt,v retrieving revision 1.14.2.9 diff -u -p -r1.14.2.9 INSTALL.txt --- INSTALL.txt 6 Apr 2008 16:45:05 -0000 1.14.2.9 +++ INSTALL.txt 29 Jun 2008 22:27:45 -0000 @@ -6,7 +6,7 @@ * Image module -* TinyMCE module (optional) +* Wysiwyg Editor module (optional) -- PRE-REQUISITES -- @@ -59,32 +59,7 @@ want your users to be able to easily choose images from their galleries, select for example "Acidfree albums" as the vocabulary to use for Image assist. - --- TINYMCE PLUGIN INSTALLATION -- - -If you use the TinyMCE WYSIWYG editor, you need to install a plugin for Image -Assist. - -* Move or copy the folder 'drupalimage' in the img_assist directory to - - [sites/all/]modules/tinymce/tinymce/jscripts/tiny_mce/plugins/ - - Edit the file plugin_reg.php in the tinymce directory. It's located in: - - [sites/all/]modules/tinymce/plugin_reg.php - - Add the following lines anywhere above the 'return' statement (without the - tags): - - $plugins['drupalimage'] = array(); - $plugins['drupalimage']['theme_advanced_buttons1'] = array('drupalimage'); - $plugins['drupalimage']['extended_valid_elements'] = array('img[class|src|border=0|alt|title|width|height|align|name]'); - - - Next, go to - - Administer > Site configuration > TinyMCE - - and enable the drupalimage plugin in your TinyMCE profile. +* If Wysiwyg Editor module is installed, you need to edit your Wysiwyg profile + configuration and enable the plugin for Image Assist. Index: img_assist.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/img_assist/img_assist.module,v retrieving revision 1.68.2.49 diff -u -p -r1.68.2.49 img_assist.module --- img_assist.module 6 Apr 2008 17:46:15 -0000 1.68.2.49 +++ img_assist.module 29 Jun 2008 22:35:28 -0000 @@ -132,8 +132,12 @@ function img_assist_elements() { * Add image link underneath textareas. */ function img_assist_textarea($element) { + // FAPI #wysiwyg support. + if (isset($element['#wysiwyg']) && $element['#wysiwyg']) { + return $element; + } $link = variable_get('img_assist_link', 'icon'); - if (($link == 'icon') || ($link == 'text')) { + if ($link == 'icon' || $link == 'text') { if (_img_assist_textarea_match($element['#id']) && _img_assist_page_match() && !strstr($_GET['q'], 'img_assist')) { if (user_access('access img_assist')) { $output = theme('img_assist_textarea_link', $element, $link); @@ -486,7 +490,7 @@ function img_assist_loader() { $path = drupal_get_path('module', 'img_assist'); $output .= ''."\n"; if ($editor == 'tinymce') { - $tinymce_path = drupal_get_path('module', 'tinymce'); + $tinymce_path = drupal_get_path('module', 'wysiwyg_editor'); $tinymce_js = base_path() . $tinymce_path .'/tinymce/jscripts/tiny_mce/tiny_mce_popup.js'; $output .= '' . "\n"; } @@ -1761,6 +1765,23 @@ function theme_img_assist_page($content, */ /** + * Implementation of hook_wysiwyg_plugin(). + */ +function img_assist_wysiwyg_plugin($editor) { + switch ($editor) { + case 'tinymce': + return array( + 'drupalimage' => array( + 'path' => drupal_get_path('module', 'img_assist') .'/drupalimage', + 'buttons' => array('drupalimage' => t('Image Assist')), + 'url' => 'http://drupal.org/project/img_assist', + 'extended_valid_elements' => array('img[class|src|border=0|alt|title|width|height|align|name]'), + ), + ); + } +} + +/** * @defgroup img_assist_legacy Image Assist Legacy functions * @{ * Used for backwards compatibility with original img_assist module. Index: drupalimage/drupalimage.css =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/img_assist/drupalimage/drupalimage.css,v retrieving revision 1.1.4.1 diff -u -p -r1.1.4.1 drupalimage.css --- drupalimage/drupalimage.css 9 Apr 2007 22:57:22 -0000 1.1.4.1 +++ drupalimage/drupalimage.css 23 Jun 2008 22:35:10 -0000 @@ -1,4 +1,5 @@ /* $Id: drupalimage.css,v 1.1.4.1 2007/04/09 22:57:22 darrenoh Exp $ */ + .mceItemDrupalImage { border: 1px dotted #cc0000; background-image: url('images/drupalimage.gif'); Index: drupalimage/editor_plugin.js =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/img_assist/drupalimage/editor_plugin.js,v retrieving revision 1.1.4.4 diff -u -p -r1.1.4.4 editor_plugin.js --- drupalimage/editor_plugin.js 30 Sep 2007 23:05:20 -0000 1.1.4.4 +++ drupalimage/editor_plugin.js 23 Jun 2008 22:11:13 -0000 @@ -1,260 +1,248 @@ -// $Id: editor_plugin.js,v 1.1.4.4 2007/09/30 23:05:20 sun Exp $ -/* Import plugin specific language pack */ +// $Id: editor_plugin_src.js,v 1.1.4.4 2007/09/30 23:05:20 sun Exp $ + +// Import plugin language. tinyMCE.importPluginLanguagePack('drupalimage', 'en'); var TinyMCE_DrupalImagePlugin = { - getInfo : function() { - return { - longname : 'DrupalImage', - author : 'Benjamin Shell', - authorurl : 'http://www.benjaminshell.com', - infourl : 'http://drupal.org/project/img_assist', - version : tinyMCE.majorVersion +'.'+ tinyMCE.minorVersion - }; - }, - - initInstance : function(inst) { - if (!tinyMCE.settings['drupalimage_skip_plugin_css']) - tinyMCE.importCSS(inst.getDoc(), tinyMCE.baseURL + '/plugins/drupalimage/drupalimage.css'); - }, - - getControlHTML : function(cn) { - switch (cn) { - case 'drupalimage': - return tinyMCE.getButtonHTML(cn, 'lang_drupalimage_desc', '{$pluginurl}/images/drupalimage.gif', 'mceDrupalImage'); - } - - return ''; - }, - - execCommand : function(editor_id, element, command, user_interface, value) { - // Handle commands - switch (command) { - case 'mceDrupalImage': - var name = ''; - var nid = '', alt = '', captionTitle = '', captionDesc = '', link = '', url = '', align = '', width = '', height = ''; - var action = 'insert'; - var template = new Array(); - var inst = tinyMCE.getInstanceById(editor_id); - var focusElm = inst.getFocusElement(); - - template['file'] = BASE_URL + 'index.php?q=img_assist/load/tinymce'; - template['width'] = 600; - template['height'] = 350; - template['html'] = false; - - // Is selection a image - if (focusElm != null && focusElm.nodeName.toLowerCase() == 'img') { - name = tinyMCE.getAttrib(focusElm, 'class'); - - if (name.indexOf('mceItemDrupalImage') == -1) - // Not a DrupalImage - return true; - - // Get the rest of the DrupalImage attributes - align = tinyMCE.getAttrib(focusElm, 'align'); - width = tinyMCE.getAttrib(focusElm, 'width'); - height = tinyMCE.getAttrib(focusElm, 'height'); - // using 'title' because this doesn't seem to work with 'alt' - alt = decodeURIComponent(tinyMCE.getAttrib(focusElm, 'title')); - // parse the deliminated attributes in the alt tag - var miscAttribs = TinyMCE_DrupalImagePlugin._parsePipeAttributes(alt); - nid = miscAttribs['nid']; - captionTitle = miscAttribs['title']; - captionDesc = miscAttribs['desc']; - link = miscAttribs['link']; - if(typeof miscAttribs['url'] != 'undefined') { - url = miscAttribs['url']; - } - - action = 'update'; - } - - tinyMCE.openWindow(template, {editor_id: editor_id, nid: nid, captionTitle: captionTitle, captionDesc: captionDesc, link: link, url: url, align: align, width: width, height: height, action: action}); - return true; - } - - // Pass to next handler in chain - return false; - }, - - cleanup : function(type, content) { - switch (type) { - case 'insert_to_editor_dom': - break; - - case 'get_from_editor_dom': - break; - - case 'insert_to_editor': - // called when TinyMCE loads existing data or when updating code using - // Edit HTML Source plugin. - // Parse all drupalimage filter tags and replace them with image placeholders - var startPos = 0; - var index = 0; - while ((startPos = content.indexOf('[img_assist|', startPos)) != -1) { - // Find end of object - var endPos = content.indexOf(']', startPos); - var attribs = TinyMCE_DrupalImagePlugin._parsePipeAttributes(content.substring(startPos + 12, endPos)); - endPos++; - - // TinyMCE_DrupalImagePlugin._parsePipeAttributes() parses the piped - // string completely, but in this case we want to keep the nid, title, - // and desc in piped format, so we have to rebuild a partial piped string. - // Backwards compatibility: Also parse link/url in the format link=url,foo. - var miscAttribs = 'nid=' + attribs['nid'] + '|title=' + attribs['title'] + '|desc=' + attribs['desc']; - if(attribs['link'].indexOf(',') != -1) { - link = attribs['link'].split(',', 2); - miscAttribs += '|link=' + link[0] + '|url=' + link[1]; - } - else { - miscAttribs += '|link=' + attribs['link']; - } - if(typeof attribs['url'] != 'undefined') { - miscAttribs += '|url=' + attribs['url']; - } - // ordinarily piped strings wouldn't need to have HTML entities - // converted, but we are building an HTML tag that just happens to use - // a piped string as one of its' attribute values. The easiest way to - // take care of HTML entities is with the Javascript escape() function. - // It escapes more than necessary, but that's okay. We'll use unescape() - // to go back when we need to. - miscAttribs = encodeURIComponent(miscAttribs); - - // Insert image - var contentAfter = content.substring(endPos); - content = content.substring(0, startPos); - // Reference: these are the default parameters that are valid for the - // TinyMCE image tags: - // img[class|src|border=0|alt|title|hspace|vspace|width|height|align] - content += ''; - content += contentAfter; - index++; - - startPos++; - } - break; - - case 'get_from_editor': - // Called when TinyMCE exits or when the Edit HTML Source plugin is clicked - // Parse all image placeholders and replace them with drupalimage filter tags - var startPos = -1; - while ((startPos = content.indexOf('', startPos); - var attribs = TinyMCE_DrupalImagePlugin._parseHTMLAttributes(content.substring(startPos + 4, endPos)); - endPos += 2; - - // Is not drupalimage, skip it - if (attribs['name'] != "mceItemDrupalImage") { - continue; - } - - // Insert drupalimage filter code - // At this point all attribute values should have any pipes | or - // closing square brackets ] escaped with backslashes. When this - // filter code is parsed, it will look for the closing bracket to - // find the end and the pipe symbol to explode the rest of the - // attributes. However, since we just parsed from HTML tag, HTML - // entities should be unescaped at this time. - var miscAttribs = decodeURIComponent(attribs['alt']); - - var contentBefore = content.substring(0, startPos); - var contentAfter = content.substring(endPos); - var drupalHTML = ''; - drupalHTML += '[img_assist|' + miscAttribs + '|align=' + attribs['align']; - drupalHTML += '|width=' + attribs['width'] + '|height=' + attribs['height'] + ']'; - content = contentBefore + drupalHTML + contentAfter; - } - break; - } - - // Pass through to next handler in chain - return content; - }, - - handleNodeChange : function(editor_id, node, undo_index, undo_levels, visual_aid, any_selection) { - if (node == null) - return; - - do { - // This code looks at the name of the image to see if the drupalimage - // button should be selected. However, by default 'name' is not accepted - // by TinyMCE as a parameter for the img tag, so it must be added using - // the initialization string. As far as THIS code goes, it could look at - // 'className' instead, therefore avoiding this requirement, however the - // regular image button looks at the 'name' value to see if it starts with - // 'mce_'. If it does, it considers it an internal image and does not - // highlight the regular image button. If 'className' is used here - // instead, BOTH buttons highlight when a drupalimage is selected. - if (node.nodeName == 'IMG' && tinyMCE.getAttrib(node, 'class').indexOf('mceItemDrupalImage') == 0) { - tinyMCE.switchClass(editor_id + '_drupalimage', 'mceButtonSelected'); - return true; - } - } while ((node = node.parentNode)); - - tinyMCE.switchClass(editor_id + '_drupalimage', 'mceButtonNormal'); - - return true; - }, - - // pipes | must be escaped with a backslash like this: \| - // note: values also cannot contain ] because the functions that call - // this function use the ] symbol to find the end of the drupalimage filter code - _parsePipeAttributes : function(attribute_string) { - var attributes = new Array(); - var keyvalue_arr = new Array(); - // if it weren't for the escaping, the regExp string would look like this: - // var regExp = new RegExp('([a-zA-Z]*)=([^\|]*)', 'g'); - var regExp = new RegExp('([a-zA-Z]*)=([^|](?:\\.|[^\\|]*)*)*', 'g'); - var matches = attribute_string.match(regExp); - for (var i = 0; i < matches.length; i++ ) { - keyvalue_arr = matches[i].split('='); - attributes[keyvalue_arr[0]] = keyvalue_arr[1]; - } - return attributes; - }, - - /* - * Parses HTML attributes into a key=>value array. - * Take a look at the example strings and see how standard HTML entities - * within any value, such as the title and desc (which are combined in the - * alt tag as a piped string) need to be converted to: " & < > - * - * Simple example: - * name="mceItemDrupalImage" width="200" height="150" src="/images/spacer.gif" - * alt="nid=123|title=My Photos|desc=" class="mceItemDrupalImage" align="right" - * - * Advanced example: - * name="mceItemDrupalImage" width="200" height="150" src="/images/spacer.gif" - * alt="nid=123|title="To be or not to be"|desc=That is the question." - * class="mceItemDrupalImage" align="right" - * - * Any pipes | or closing brackets would also be a problem, not for this - * parsing function, but when parsing the pipe deliminated string. These - * characters need to be escaped with a backslash. Unlike the quotes, this - * cannot be accomplished automatically within this TinyMCE plugin. Any user - * or Drupal module that inserts drupalimage filter strings in a post, whether - * using TinyMCE or not, must backslash any pipes or closing brackets. - */ - _parseHTMLAttributes : function(attribute_string) { - var attributes = new Array(); - var innerMatches = new Array(); - var regExp = '([a-zA-Z0-9]+)[\s]*=[\s]*"([^"](?:\\.|[^\\"]*)*)"'; - - // doesn't work without global (g) - var outerRegExp = new RegExp(regExp, 'g'); - var outerMatches = attribute_string.match(outerRegExp); - // doesn't work with global (g) - var innerRegExp = new RegExp(regExp); - for (var i = 0; i < outerMatches.length; i++ ) { - innerMatches = innerRegExp.exec(outerMatches[i]); - attributes[innerMatches[1]] = innerMatches[2]; - } - return attributes; - } + getInfo: function() { + return { + longname: 'Image Assist', + author: 'Benjamin Shell', + authorurl: 'http://www.benjaminshell.com', + infourl : 'http://drupal.org/project/img_assist' + }; + }, + + initInstance : function(inst) { + if (!tinyMCE.settings['drupalimage_skip_plugin_css']) + tinyMCE.importCSS(inst.getDoc(), this.baseURL + '/drupalimage.css'); + }, + + getControlHTML: function (control_name) { + switch (control_name) { + case 'drupalimage': + return tinyMCE.getButtonHTML(control_name, 'lang_drupalimage_desc', '{$pluginurl}/images/drupalimage.gif', 'mceDrupalImage'); + } + return ''; + }, + + execCommand: function(editor_id, element, command, user_interface, value) { + switch (command) { + case 'mceDrupalImage': + var name = ''; + var nid = '', alt = '', captionTitle = '', captionDesc = '', link = '', url = '', align = '', width = '', height = ''; + var action = 'insert'; + var template = new Array(); + var inst = tinyMCE.getInstanceById(editor_id); + var focusElm = inst.getFocusElement(); + + template['file'] = BASE_URL + 'index.php?q=img_assist/load/tinymce'; + template['width'] = 600; + template['height'] = 350; + template['html'] = false; + + // Check whether selection is an image and belongs to this plugin. + if (focusElm != null && focusElm.nodeName.toLowerCase() == 'img') { + name = tinyMCE.getAttrib(focusElm, 'class'); + + if (name.indexOf('mceItemDrupalImage') == -1) + return true; + + // Get the rest of the DrupalImage attributes + align = tinyMCE.getAttrib(focusElm, 'align'); + width = tinyMCE.getAttrib(focusElm, 'width'); + height = tinyMCE.getAttrib(focusElm, 'height'); + // using 'title' because this doesn't seem to work with 'alt' + alt = decodeURIComponent(tinyMCE.getAttrib(focusElm, 'title')); + // parse the deliminated attributes in the alt tag + var miscAttribs = TinyMCE_DrupalImagePlugin._parsePipeAttributes(alt); + nid = miscAttribs['nid']; + captionTitle = miscAttribs['title']; + captionDesc = miscAttribs['desc']; + link = miscAttribs['link']; + if(typeof miscAttribs['url'] != 'undefined') { + url = miscAttribs['url']; + } + action = 'update'; + } + + tinyMCE.openWindow(template, {editor_id: editor_id, nid: nid, captionTitle: captionTitle, captionDesc: captionDesc, link: link, url: url, align: align, width: width, height: height, action: action}); + return true; + } + // Pass to next handler in chain. + return false; + }, + + cleanup: function(type, content) { + switch (type) { + case 'insert_to_editor_dom': + break; + + case 'get_from_editor_dom': + break; + + case 'insert_to_editor': + // called when TinyMCE loads existing data or when updating code using + // Edit HTML Source plugin. + // Parse all drupalimage filter tags and replace them with image placeholders + var startPos = 0; + var index = 0; + while ((startPos = content.indexOf('[img_assist|', startPos)) != -1) { + // Find end of object + var endPos = content.indexOf(']', startPos); + var attribs = TinyMCE_DrupalImagePlugin._parsePipeAttributes(content.substring(startPos + 12, endPos)); + endPos++; + + // TinyMCE_DrupalImagePlugin._parsePipeAttributes() parses the piped + // string completely, but in this case we want to keep the nid, title, + // and desc in piped format, so we have to rebuild a partial piped string. + // Backwards compatibility: Also parse link/url in the format link=url,foo. + var miscAttribs = 'nid=' + attribs['nid'] + '|title=' + attribs['title'] + '|desc=' + attribs['desc']; + if(attribs['link'].indexOf(',') != -1) { + link = attribs['link'].split(',', 2); + miscAttribs += '|link=' + link[0] + '|url=' + link[1]; + } + else { + miscAttribs += '|link=' + attribs['link']; + } + if(typeof attribs['url'] != 'undefined') { + miscAttribs += '|url=' + attribs['url']; + } + // ordinarily piped strings wouldn't need to have HTML entities + // converted, but we are building an HTML tag that just happens to use + // a piped string as one of its' attribute values. The easiest way to + // take care of HTML entities is with the Javascript escape() function. + // It escapes more than necessary, but that's okay. We'll use unescape() + // to go back when we need to. + miscAttribs = encodeURIComponent(miscAttribs); + + // Insert image. + var contentAfter = content.substring(endPos); + content = content.substring(0, startPos); + // Reference: these are the default parameters that are valid for the + // TinyMCE image tags: + // img[class|src|border=0|alt|title|hspace|vspace|width|height|align] + content += ''; + content += contentAfter; + index++; + startPos++; + } + break; + + case 'get_from_editor': + // Parse all image placeholders and replace them with drupalimage filter tags + var startPos = -1; + while ((startPos = content.indexOf('', startPos); + var attribs = TinyMCE_DrupalImagePlugin._parseHTMLAttributes(content.substring(startPos + 4, endPos)); + endPos += 2; + if (attribs['name'] != "mceItemDrupalImage") { + continue; + } + + // Insert drupalimage filter code + // At this point all attribute values should have any pipes | or + // closing square brackets ] escaped with backslashes. When this + // filter code is parsed, it will look for the closing bracket to + // find the end and the pipe symbol to explode the rest of the + // attributes. However, since we just parsed from HTML tag, HTML + // entities should be unescaped at this time. + var miscAttribs = decodeURIComponent(attribs['alt']); + + var contentBefore = content.substring(0, startPos); + var contentAfter = content.substring(endPos); + var drupalHTML = ''; + drupalHTML += '[img_assist|' + miscAttribs + '|align=' + attribs['align']; + drupalHTML += '|width=' + attribs['width'] + '|height=' + attribs['height'] + ']'; + content = contentBefore + drupalHTML + contentAfter; + } + break; + } + // Pass through to next handler in chain + return content; + }, + + handleNodeChange: function(editor_id, node, undo_index, undo_levels, visual_aid, any_selection) { + if (node == null) { + return; + } + do { + // This code looks at the name of the image to see if the drupalimage + // button should be selected. However, by default 'name' is not accepted + // by TinyMCE as a parameter for the img tag, so it must be added using + // the initialization string. As far as THIS code goes, it could look at + // 'className' instead, therefore avoiding this requirement, however the + // regular image button looks at the 'name' value to see if it starts with + // 'mce_'. If it does, it considers it an internal image and does not + // highlight the regular image button. If 'className' is used here + // instead, BOTH buttons highlight when a drupalimage is selected. + if (node.nodeName == 'IMG' && tinyMCE.getAttrib(node, 'class').indexOf('mceItemDrupalImage') == 0) { + tinyMCE.switchClass(editor_id + '_drupalimage', 'mceButtonSelected'); + return true; + } + } while ((node = node.parentNode)); + tinyMCE.switchClass(editor_id + '_drupalimage', 'mceButtonNormal'); + return true; + }, + + // pipes | must be escaped with a backslash like this: \| + // note: values also cannot contain ] because the functions that call + // this function use the ] symbol to find the end of the drupalimage filter code + _parsePipeAttributes : function(attribute_string) { + var attributes = new Array(); + var keyvalue_arr = new Array(); + // if it weren't for the escaping, the regExp string would look like this: + // var regExp = new RegExp('([a-zA-Z]*)=([^\|]*)', 'g'); + var regExp = new RegExp('([a-zA-Z]*)=([^|](?:\\.|[^\\|]*)*)*', 'g'); + var matches = attribute_string.match(regExp); + for (var i = 0; i < matches.length; i++ ) { + keyvalue_arr = matches[i].split('='); + attributes[keyvalue_arr[0]] = keyvalue_arr[1]; + } + return attributes; + }, + + /** + * Parses HTML attributes into a key=>value array. + * Take a look at the example strings and see how standard HTML entities + * within any value, such as the title and desc (which are combined in the + * alt tag as a piped string) need to be converted to: " & < > + * + * Simple example: + * name="mceItemDrupalImage" width="200" height="150" src="/images/spacer.gif" + * alt="nid=123|title=My Photos|desc=" class="mceItemDrupalImage" align="right" + * + * Advanced example: + * name="mceItemDrupalImage" width="200" height="150" src="/images/spacer.gif" + * alt="nid=123|title="To be or not to be"|desc=That is the question." + * class="mceItemDrupalImage" align="right" + * + * Any pipes | or closing brackets would also be a problem, not for this + * parsing function, but when parsing the pipe deliminated string. These + * characters need to be escaped with a backslash. Unlike the quotes, this + * cannot be accomplished automatically within this TinyMCE plugin. Any user + * or Drupal module that inserts drupalimage filter strings in a post, whether + * using TinyMCE or not, must backslash any pipes or closing brackets. + */ + _parseHTMLAttributes : function(attribute_string) { + var attributes = new Array(); + var innerMatches = new Array(); + var regExp = '([a-zA-Z0-9]+)[\s]*=[\s]*"([^"](?:\\.|[^\\"]*)*)"'; + + // doesn't work without global (g) + var outerRegExp = new RegExp(regExp, 'g'); + var outerMatches = attribute_string.match(outerRegExp); + // doesn't work with global (g) + var innerRegExp = new RegExp(regExp); + for (var i = 0; i < outerMatches.length; i++ ) { + innerMatches = innerRegExp.exec(outerMatches[i]); + attributes[innerMatches[1]] = innerMatches[2]; + } + return attributes; + } }; -tinyMCE.addPlugin("drupalimage", TinyMCE_DrupalImagePlugin); +tinyMCE.addPlugin('drupalimage', TinyMCE_DrupalImagePlugin); Index: drupalimage/editor_plugin_src.js =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/img_assist/drupalimage/editor_plugin_src.js,v retrieving revision 1.1.4.4 diff -u -p -r1.1.4.4 editor_plugin_src.js --- drupalimage/editor_plugin_src.js 30 Sep 2007 23:05:20 -0000 1.1.4.4 +++ drupalimage/editor_plugin_src.js 23 Jun 2008 22:11:13 -0000 @@ -1,260 +1,248 @@ // $Id: editor_plugin_src.js,v 1.1.4.4 2007/09/30 23:05:20 sun Exp $ -/* Import plugin specific language pack */ + +// Import plugin language. tinyMCE.importPluginLanguagePack('drupalimage', 'en'); var TinyMCE_DrupalImagePlugin = { - getInfo : function() { - return { - longname : 'DrupalImage', - author : 'Benjamin Shell', - authorurl : 'http://www.benjaminshell.com', - infourl : 'http://drupal.org/project/img_assist', - version : tinyMCE.majorVersion +'.'+ tinyMCE.minorVersion - }; - }, - - initInstance : function(inst) { - if (!tinyMCE.settings['drupalimage_skip_plugin_css']) - tinyMCE.importCSS(inst.getDoc(), tinyMCE.baseURL + '/plugins/drupalimage/drupalimage.css'); - }, - - getControlHTML : function(cn) { - switch (cn) { - case 'drupalimage': - return tinyMCE.getButtonHTML(cn, 'lang_drupalimage_desc', '{$pluginurl}/images/drupalimage.gif', 'mceDrupalImage'); - } - - return ''; - }, - - execCommand : function(editor_id, element, command, user_interface, value) { - // Handle commands - switch (command) { - case 'mceDrupalImage': - var name = ''; - var nid = '', alt = '', captionTitle = '', captionDesc = '', link = '', url = '', align = '', width = '', height = ''; - var action = 'insert'; - var template = new Array(); - var inst = tinyMCE.getInstanceById(editor_id); - var focusElm = inst.getFocusElement(); - - template['file'] = BASE_URL + 'index.php?q=img_assist/load/tinymce'; - template['width'] = 600; - template['height'] = 350; - template['html'] = false; - - // Is selection a image - if (focusElm != null && focusElm.nodeName.toLowerCase() == 'img') { - name = tinyMCE.getAttrib(focusElm, 'class'); - - if (name.indexOf('mceItemDrupalImage') == -1) - // Not a DrupalImage - return true; - - // Get the rest of the DrupalImage attributes - align = tinyMCE.getAttrib(focusElm, 'align'); - width = tinyMCE.getAttrib(focusElm, 'width'); - height = tinyMCE.getAttrib(focusElm, 'height'); - // using 'title' because this doesn't seem to work with 'alt' - alt = decodeURIComponent(tinyMCE.getAttrib(focusElm, 'title')); - // parse the deliminated attributes in the alt tag - var miscAttribs = TinyMCE_DrupalImagePlugin._parsePipeAttributes(alt); - nid = miscAttribs['nid']; - captionTitle = miscAttribs['title']; - captionDesc = miscAttribs['desc']; - link = miscAttribs['link']; - if(typeof miscAttribs['url'] != 'undefined') { - url = miscAttribs['url']; - } - - action = 'update'; - } - - tinyMCE.openWindow(template, {editor_id: editor_id, nid: nid, captionTitle: captionTitle, captionDesc: captionDesc, link: link, url: url, align: align, width: width, height: height, action: action}); - return true; - } - - // Pass to next handler in chain - return false; - }, - - cleanup : function(type, content) { - switch (type) { - case 'insert_to_editor_dom': - break; - - case 'get_from_editor_dom': - break; - - case 'insert_to_editor': - // called when TinyMCE loads existing data or when updating code using - // Edit HTML Source plugin. - // Parse all drupalimage filter tags and replace them with image placeholders - var startPos = 0; - var index = 0; - while ((startPos = content.indexOf('[img_assist|', startPos)) != -1) { - // Find end of object - var endPos = content.indexOf(']', startPos); - var attribs = TinyMCE_DrupalImagePlugin._parsePipeAttributes(content.substring(startPos + 12, endPos)); - endPos++; - - // TinyMCE_DrupalImagePlugin._parsePipeAttributes() parses the piped - // string completely, but in this case we want to keep the nid, title, - // and desc in piped format, so we have to rebuild a partial piped string. - // Backwards compatibility: Also parse link/url in the format link=url,foo. - var miscAttribs = 'nid=' + attribs['nid'] + '|title=' + attribs['title'] + '|desc=' + attribs['desc']; - if(attribs['link'].indexOf(',') != -1) { - link = attribs['link'].split(',', 2); - miscAttribs += '|link=' + link[0] + '|url=' + link[1]; - } - else { - miscAttribs += '|link=' + attribs['link']; - } - if(typeof attribs['url'] != 'undefined') { - miscAttribs += '|url=' + attribs['url']; - } - // ordinarily piped strings wouldn't need to have HTML entities - // converted, but we are building an HTML tag that just happens to use - // a piped string as one of its' attribute values. The easiest way to - // take care of HTML entities is with the Javascript escape() function. - // It escapes more than necessary, but that's okay. We'll use unescape() - // to go back when we need to. - miscAttribs = encodeURIComponent(miscAttribs); - - // Insert image - var contentAfter = content.substring(endPos); - content = content.substring(0, startPos); - // Reference: these are the default parameters that are valid for the - // TinyMCE image tags: - // img[class|src|border=0|alt|title|hspace|vspace|width|height|align] - content += ''; - content += contentAfter; - index++; - - startPos++; - } - break; - - case 'get_from_editor': - // Called when TinyMCE exits or when the Edit HTML Source plugin is clicked - // Parse all image placeholders and replace them with drupalimage filter tags - var startPos = -1; - while ((startPos = content.indexOf('', startPos); - var attribs = TinyMCE_DrupalImagePlugin._parseHTMLAttributes(content.substring(startPos + 4, endPos)); - endPos += 2; - - // Is not drupalimage, skip it - if (attribs['name'] != "mceItemDrupalImage") { - continue; - } - - // Insert drupalimage filter code - // At this point all attribute values should have any pipes | or - // closing square brackets ] escaped with backslashes. When this - // filter code is parsed, it will look for the closing bracket to - // find the end and the pipe symbol to explode the rest of the - // attributes. However, since we just parsed from HTML tag, HTML - // entities should be unescaped at this time. - var miscAttribs = decodeURIComponent(attribs['alt']); - - var contentBefore = content.substring(0, startPos); - var contentAfter = content.substring(endPos); - var drupalHTML = ''; - drupalHTML += '[img_assist|' + miscAttribs + '|align=' + attribs['align']; - drupalHTML += '|width=' + attribs['width'] + '|height=' + attribs['height'] + ']'; - content = contentBefore + drupalHTML + contentAfter; - } - break; - } - - // Pass through to next handler in chain - return content; - }, - - handleNodeChange : function(editor_id, node, undo_index, undo_levels, visual_aid, any_selection) { - if (node == null) - return; - - do { - // This code looks at the name of the image to see if the drupalimage - // button should be selected. However, by default 'name' is not accepted - // by TinyMCE as a parameter for the img tag, so it must be added using - // the initialization string. As far as THIS code goes, it could look at - // 'className' instead, therefore avoiding this requirement, however the - // regular image button looks at the 'name' value to see if it starts with - // 'mce_'. If it does, it considers it an internal image and does not - // highlight the regular image button. If 'className' is used here - // instead, BOTH buttons highlight when a drupalimage is selected. - if (node.nodeName == 'IMG' && tinyMCE.getAttrib(node, 'class').indexOf('mceItemDrupalImage') == 0) { - tinyMCE.switchClass(editor_id + '_drupalimage', 'mceButtonSelected'); - return true; - } - } while ((node = node.parentNode)); - - tinyMCE.switchClass(editor_id + '_drupalimage', 'mceButtonNormal'); - - return true; - }, - - // pipes | must be escaped with a backslash like this: \| - // note: values also cannot contain ] because the functions that call - // this function use the ] symbol to find the end of the drupalimage filter code - _parsePipeAttributes : function(attribute_string) { - var attributes = new Array(); - var keyvalue_arr = new Array(); - // if it weren't for the escaping, the regExp string would look like this: - // var regExp = new RegExp('([a-zA-Z]*)=([^\|]*)', 'g'); - var regExp = new RegExp('([a-zA-Z]*)=([^|](?:\\.|[^\\|]*)*)*', 'g'); - var matches = attribute_string.match(regExp); - for (var i = 0; i < matches.length; i++ ) { - keyvalue_arr = matches[i].split('='); - attributes[keyvalue_arr[0]] = keyvalue_arr[1]; - } - return attributes; - }, - - /* - * Parses HTML attributes into a key=>value array. - * Take a look at the example strings and see how standard HTML entities - * within any value, such as the title and desc (which are combined in the - * alt tag as a piped string) need to be converted to: " & < > - * - * Simple example: - * name="mceItemDrupalImage" width="200" height="150" src="/images/spacer.gif" - * alt="nid=123|title=My Photos|desc=" class="mceItemDrupalImage" align="right" - * - * Advanced example: - * name="mceItemDrupalImage" width="200" height="150" src="/images/spacer.gif" - * alt="nid=123|title="To be or not to be"|desc=That is the question." - * class="mceItemDrupalImage" align="right" - * - * Any pipes | or closing brackets would also be a problem, not for this - * parsing function, but when parsing the pipe deliminated string. These - * characters need to be escaped with a backslash. Unlike the quotes, this - * cannot be accomplished automatically within this TinyMCE plugin. Any user - * or Drupal module that inserts drupalimage filter strings in a post, whether - * using TinyMCE or not, must backslash any pipes or closing brackets. - */ - _parseHTMLAttributes : function(attribute_string) { - var attributes = new Array(); - var innerMatches = new Array(); - var regExp = '([a-zA-Z0-9]+)[\s]*=[\s]*"([^"](?:\\.|[^\\"]*)*)"'; - - // doesn't work without global (g) - var outerRegExp = new RegExp(regExp, 'g'); - var outerMatches = attribute_string.match(outerRegExp); - // doesn't work with global (g) - var innerRegExp = new RegExp(regExp); - for (var i = 0; i < outerMatches.length; i++ ) { - innerMatches = innerRegExp.exec(outerMatches[i]); - attributes[innerMatches[1]] = innerMatches[2]; - } - return attributes; - } + getInfo: function() { + return { + longname: 'Image Assist', + author: 'Benjamin Shell', + authorurl: 'http://www.benjaminshell.com', + infourl : 'http://drupal.org/project/img_assist' + }; + }, + + initInstance : function(inst) { + if (!tinyMCE.settings['drupalimage_skip_plugin_css']) + tinyMCE.importCSS(inst.getDoc(), this.baseURL + '/drupalimage.css'); + }, + + getControlHTML: function (control_name) { + switch (control_name) { + case 'drupalimage': + return tinyMCE.getButtonHTML(control_name, 'lang_drupalimage_desc', '{$pluginurl}/images/drupalimage.gif', 'mceDrupalImage'); + } + return ''; + }, + + execCommand: function(editor_id, element, command, user_interface, value) { + switch (command) { + case 'mceDrupalImage': + var name = ''; + var nid = '', alt = '', captionTitle = '', captionDesc = '', link = '', url = '', align = '', width = '', height = ''; + var action = 'insert'; + var template = new Array(); + var inst = tinyMCE.getInstanceById(editor_id); + var focusElm = inst.getFocusElement(); + + template['file'] = BASE_URL + 'index.php?q=img_assist/load/tinymce'; + template['width'] = 600; + template['height'] = 350; + template['html'] = false; + + // Check whether selection is an image and belongs to this plugin. + if (focusElm != null && focusElm.nodeName.toLowerCase() == 'img') { + name = tinyMCE.getAttrib(focusElm, 'class'); + + if (name.indexOf('mceItemDrupalImage') == -1) + return true; + + // Get the rest of the DrupalImage attributes + align = tinyMCE.getAttrib(focusElm, 'align'); + width = tinyMCE.getAttrib(focusElm, 'width'); + height = tinyMCE.getAttrib(focusElm, 'height'); + // using 'title' because this doesn't seem to work with 'alt' + alt = decodeURIComponent(tinyMCE.getAttrib(focusElm, 'title')); + // parse the deliminated attributes in the alt tag + var miscAttribs = TinyMCE_DrupalImagePlugin._parsePipeAttributes(alt); + nid = miscAttribs['nid']; + captionTitle = miscAttribs['title']; + captionDesc = miscAttribs['desc']; + link = miscAttribs['link']; + if(typeof miscAttribs['url'] != 'undefined') { + url = miscAttribs['url']; + } + action = 'update'; + } + + tinyMCE.openWindow(template, {editor_id: editor_id, nid: nid, captionTitle: captionTitle, captionDesc: captionDesc, link: link, url: url, align: align, width: width, height: height, action: action}); + return true; + } + // Pass to next handler in chain. + return false; + }, + + cleanup: function(type, content) { + switch (type) { + case 'insert_to_editor_dom': + break; + + case 'get_from_editor_dom': + break; + + case 'insert_to_editor': + // called when TinyMCE loads existing data or when updating code using + // Edit HTML Source plugin. + // Parse all drupalimage filter tags and replace them with image placeholders + var startPos = 0; + var index = 0; + while ((startPos = content.indexOf('[img_assist|', startPos)) != -1) { + // Find end of object + var endPos = content.indexOf(']', startPos); + var attribs = TinyMCE_DrupalImagePlugin._parsePipeAttributes(content.substring(startPos + 12, endPos)); + endPos++; + + // TinyMCE_DrupalImagePlugin._parsePipeAttributes() parses the piped + // string completely, but in this case we want to keep the nid, title, + // and desc in piped format, so we have to rebuild a partial piped string. + // Backwards compatibility: Also parse link/url in the format link=url,foo. + var miscAttribs = 'nid=' + attribs['nid'] + '|title=' + attribs['title'] + '|desc=' + attribs['desc']; + if(attribs['link'].indexOf(',') != -1) { + link = attribs['link'].split(',', 2); + miscAttribs += '|link=' + link[0] + '|url=' + link[1]; + } + else { + miscAttribs += '|link=' + attribs['link']; + } + if(typeof attribs['url'] != 'undefined') { + miscAttribs += '|url=' + attribs['url']; + } + // ordinarily piped strings wouldn't need to have HTML entities + // converted, but we are building an HTML tag that just happens to use + // a piped string as one of its' attribute values. The easiest way to + // take care of HTML entities is with the Javascript escape() function. + // It escapes more than necessary, but that's okay. We'll use unescape() + // to go back when we need to. + miscAttribs = encodeURIComponent(miscAttribs); + + // Insert image. + var contentAfter = content.substring(endPos); + content = content.substring(0, startPos); + // Reference: these are the default parameters that are valid for the + // TinyMCE image tags: + // img[class|src|border=0|alt|title|hspace|vspace|width|height|align] + content += ''; + content += contentAfter; + index++; + startPos++; + } + break; + + case 'get_from_editor': + // Parse all image placeholders and replace them with drupalimage filter tags + var startPos = -1; + while ((startPos = content.indexOf('', startPos); + var attribs = TinyMCE_DrupalImagePlugin._parseHTMLAttributes(content.substring(startPos + 4, endPos)); + endPos += 2; + if (attribs['name'] != "mceItemDrupalImage") { + continue; + } + + // Insert drupalimage filter code + // At this point all attribute values should have any pipes | or + // closing square brackets ] escaped with backslashes. When this + // filter code is parsed, it will look for the closing bracket to + // find the end and the pipe symbol to explode the rest of the + // attributes. However, since we just parsed from HTML tag, HTML + // entities should be unescaped at this time. + var miscAttribs = decodeURIComponent(attribs['alt']); + + var contentBefore = content.substring(0, startPos); + var contentAfter = content.substring(endPos); + var drupalHTML = ''; + drupalHTML += '[img_assist|' + miscAttribs + '|align=' + attribs['align']; + drupalHTML += '|width=' + attribs['width'] + '|height=' + attribs['height'] + ']'; + content = contentBefore + drupalHTML + contentAfter; + } + break; + } + // Pass through to next handler in chain + return content; + }, + + handleNodeChange: function(editor_id, node, undo_index, undo_levels, visual_aid, any_selection) { + if (node == null) { + return; + } + do { + // This code looks at the name of the image to see if the drupalimage + // button should be selected. However, by default 'name' is not accepted + // by TinyMCE as a parameter for the img tag, so it must be added using + // the initialization string. As far as THIS code goes, it could look at + // 'className' instead, therefore avoiding this requirement, however the + // regular image button looks at the 'name' value to see if it starts with + // 'mce_'. If it does, it considers it an internal image and does not + // highlight the regular image button. If 'className' is used here + // instead, BOTH buttons highlight when a drupalimage is selected. + if (node.nodeName == 'IMG' && tinyMCE.getAttrib(node, 'class').indexOf('mceItemDrupalImage') == 0) { + tinyMCE.switchClass(editor_id + '_drupalimage', 'mceButtonSelected'); + return true; + } + } while ((node = node.parentNode)); + tinyMCE.switchClass(editor_id + '_drupalimage', 'mceButtonNormal'); + return true; + }, + + // pipes | must be escaped with a backslash like this: \| + // note: values also cannot contain ] because the functions that call + // this function use the ] symbol to find the end of the drupalimage filter code + _parsePipeAttributes : function(attribute_string) { + var attributes = new Array(); + var keyvalue_arr = new Array(); + // if it weren't for the escaping, the regExp string would look like this: + // var regExp = new RegExp('([a-zA-Z]*)=([^\|]*)', 'g'); + var regExp = new RegExp('([a-zA-Z]*)=([^|](?:\\.|[^\\|]*)*)*', 'g'); + var matches = attribute_string.match(regExp); + for (var i = 0; i < matches.length; i++ ) { + keyvalue_arr = matches[i].split('='); + attributes[keyvalue_arr[0]] = keyvalue_arr[1]; + } + return attributes; + }, + + /** + * Parses HTML attributes into a key=>value array. + * Take a look at the example strings and see how standard HTML entities + * within any value, such as the title and desc (which are combined in the + * alt tag as a piped string) need to be converted to: " & < > + * + * Simple example: + * name="mceItemDrupalImage" width="200" height="150" src="/images/spacer.gif" + * alt="nid=123|title=My Photos|desc=" class="mceItemDrupalImage" align="right" + * + * Advanced example: + * name="mceItemDrupalImage" width="200" height="150" src="/images/spacer.gif" + * alt="nid=123|title="To be or not to be"|desc=That is the question." + * class="mceItemDrupalImage" align="right" + * + * Any pipes | or closing brackets would also be a problem, not for this + * parsing function, but when parsing the pipe deliminated string. These + * characters need to be escaped with a backslash. Unlike the quotes, this + * cannot be accomplished automatically within this TinyMCE plugin. Any user + * or Drupal module that inserts drupalimage filter strings in a post, whether + * using TinyMCE or not, must backslash any pipes or closing brackets. + */ + _parseHTMLAttributes : function(attribute_string) { + var attributes = new Array(); + var innerMatches = new Array(); + var regExp = '([a-zA-Z0-9]+)[\s]*=[\s]*"([^"](?:\\.|[^\\"]*)*)"'; + + // doesn't work without global (g) + var outerRegExp = new RegExp(regExp, 'g'); + var outerMatches = attribute_string.match(outerRegExp); + // doesn't work with global (g) + var innerRegExp = new RegExp(regExp); + for (var i = 0; i < outerMatches.length; i++ ) { + innerMatches = innerRegExp.exec(outerMatches[i]); + attributes[innerMatches[1]] = innerMatches[2]; + } + return attributes; + } }; -tinyMCE.addPlugin("drupalimage", TinyMCE_DrupalImagePlugin); +tinyMCE.addPlugin('drupalimage', TinyMCE_DrupalImagePlugin);