Index: CHANGELOG.txt
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/img_assist/CHANGELOG.txt,v
retrieving revision 1.23.2.36.2.12
diff -u -p -r1.23.2.36.2.12 CHANGELOG.txt
--- CHANGELOG.txt	27 Oct 2008 19:15:35 -0000	1.23.2.36.2.12
+++ CHANGELOG.txt	26 Dec 2008 17:29:51 -0000
@@ -6,6 +6,7 @@ Img_Assist x.x-x.x, xxxx-xx-xx
 
 Img_Assist 5.x-2.x, xxxx-xx-xx
 ------------------------------
+#245799 by sun: Added support for TinyMCE 3; dropped support for TinyMCE 2.
 #326640 by Anselm Heaton, sun: Fixed wysiwyg_editor renamed to wysiwyg module.
 #308005 by sun: Moved includes into /includes.
 #295946 by smk-ka: Fixed module settings cannot be saved without Token module.
Index: img_assist.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/img_assist/img_assist.module,v
retrieving revision 1.68.2.50.2.12
diff -u -p -r1.68.2.50.2.12 img_assist.module
--- img_assist.module	27 Oct 2008 19:15:35 -0000	1.68.2.50.2.12
+++ img_assist.module	26 Dec 2008 17:41:46 -0000
@@ -521,26 +521,21 @@ function img_assist_cache_clear() {
  * @todo Remove hard-coded TinyMCE integration.
  */
 function img_assist_loader() {
+  $path = drupal_get_path('module', 'img_assist');
   $editor = arg(2) ? arg(2) : 'textarea';
-  
+
+  drupal_add_js($path .'/img_assist.js');
+  if ($editor == 'tinymce') {
+    $tinymce_path = drupal_get_path('module', 'wysiwyg');
+    drupal_add_js($tinymce_path .'/tinymce/jscripts/tiny_mce/tiny_mce_popup.js');
+  }
+  drupal_add_js($path .'/img_assist_'. $editor .'.js');
+
   $output  = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN">'."\n";
   $output .= "<html>\n";
   $output .= "<head>\n";
   $output .= '<title>'. t('Add image') ."</title>\n";
-  $output .= "\n<script type=\"text/javascript\"><!--\n";
-  $output .= '  var BASE_URL = "'. base_path() .'";'. "\n";
-  $output .= "--></script>\n";
-  
-  $path = drupal_get_path('module', 'img_assist');
-  $output .= '<script type="text/javascript" src="'. base_path() . $path .'/img_assist.js"></script>'."\n";
-  if ($editor == 'tinymce') {
-    $tinymce_path = drupal_get_path('module', 'wysiwyg');
-    $tinymce_js = base_path() . $tinymce_path .'/tinymce/jscripts/tiny_mce/tiny_mce_popup.js';
-    $output .= '<script type="text/javascript" src="'. $tinymce_js .'"></script>' . "\n";
-  }
-  $editor_js = base_path() . $path .'/img_assist_'. $editor .'.js';
-  $output .= '<script type="text/javascript" src="'. $editor_js .'"></script>' . "\n";
-  
+  $output .= drupal_get_js();
   $output .= "</head>\n\n";
   
   $output .= '<frameset rows="38, *" onload="initLoader()" frameborder="0" border="0" framespacing="0">' . "\n";
@@ -550,12 +545,14 @@ function img_assist_loader() {
   
   $output .= "</html>\n";
   echo $output;
+  exit;
 }
 
 function img_assist_header($mode) {
   // Mode may be 'uploading', 'properties' or 'browse'.
   $output = drupal_get_form('img_assist_header_form', $mode);
   echo theme('img_assist_page', $output, array('id' => 'img_assist_header', 'onload' => 'parent.initHeader();', 'class' => 'img_assist'));
+  exit;
 }
 
 function img_assist_header_form($mode) {
@@ -692,6 +689,7 @@ function img_assist_upload() {
     }
   }
   echo theme('img_assist_page', $output, array('id' => 'img_assist_upload', 'class' => 'img_assist'));
+  exit;
 }
 
 /**
@@ -788,6 +786,7 @@ function img_assist_thumbs() {
     $output = t('The image module must be enabled to use Image assist.');
   }
   echo theme('img_assist_page', $output, array('id' => 'img_assist_thumbs', 'onload' => 'parent.initThumbs();', 'class' => 'img_assist'));
+  exit;
 }
 
 /**
@@ -806,6 +805,7 @@ function img_assist_properties() {
   }
   
   echo theme('img_assist_page', $output, array('id' => 'img_assist_properties', 'onload' => 'parent.initProperties();', 'class' => 'img_assist'));
+  exit;
 }
 
 /**
@@ -1466,6 +1466,7 @@ function img_assist_popup() {
   $attributes = array('id' => 'img_assist_popup');
   
   echo theme('img_assist_popup', $content, $attributes);
+  exit;
 }
 
 /**
@@ -1794,7 +1795,7 @@ function theme_img_assist_page($content,
   $output .= drupal_get_js();
   $output .= "\n<script type=\"text/javascript\"><!-- \n";
   $output .= "  if (parent.tinyMCE) {\n";
-  $output .= "    document.write('<link href=\"' + parent.tinyMCE.getParam(\"popups_css\") + '\" rel=\"stylesheet\" type=\"text/css\">');\n";
+  $output .= "    document.write('<link href=\"' + parent.tinyMCEPopup.getParam(\"popups_css\") + '\" rel=\"stylesheet\" type=\"text/css\">');\n";
   $output .= "  } else {\n";
   foreach (drupal_add_css() as $media => $type) {
     $paths = array_merge($type['module'], $type['theme']);
@@ -1831,17 +1832,20 @@ function theme_img_assist_page($content,
 /**
  * Implementation of hook_wysiwyg_plugin().
  */
-function img_assist_wysiwyg_plugin($editor) {
+function img_assist_wysiwyg_plugin($editor, $version) {
   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|style]'),
-        ),
-      );
+      if ($version > 3) {
+        return array(
+          'img_assist' => array(
+            'path' => drupal_get_path('module', 'img_assist') .'/drupalimage/editor_plugin.js',
+            'buttons' => array('img_assist' => 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|style]'),
+          ),
+        );
+      }
+      break;
   }
 }
 
Index: img_assist_tinymce.js
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/img_assist/img_assist_tinymce.js,v
retrieving revision 1.1.4.6
diff -u -p -r1.1.4.6 img_assist_tinymce.js
--- img_assist_tinymce.js	30 Sep 2007 23:05:20 -0000	1.1.4.6
+++ img_assist_tinymce.js	26 Dec 2008 17:43:52 -0000
@@ -18,20 +18,15 @@
 // get variables that were passed to this window from the tinyMCE editor
 var nid, captionTitle, captionDesc, link, url, align, width, height;
 
-function preinit() {
-  tinyMCE.setWindowArg('mce_windowresize', false);
-  tinyMCE.setWindowArg('mce_replacevariables', false);
-}
-
 function initLoader() {
-  nid          =      tinyMCE.getWindowArg('nid');
-  captionTitle = '' + tinyMCE.getWindowArg('captionTitle');
-  captionDesc  = '' + tinyMCE.getWindowArg('captionDesc');
-  link         = '' + tinyMCE.getWindowArg('link');
-  url          = '' + tinyMCE.getWindowArg('url');
-  align        = '' + tinyMCE.getWindowArg('align');
-  width        = '' + tinyMCE.getWindowArg('width');
-  height       = '' + tinyMCE.getWindowArg('height');
+  nid          =      tinyMCEPopup.getWindowArg('nid');
+  captionTitle = '' + tinyMCEPopup.getWindowArg('captionTitle');
+  captionDesc  = '' + tinyMCEPopup.getWindowArg('captionDesc');
+  link         = '' + tinyMCEPopup.getWindowArg('link');
+  url          = '' + tinyMCEPopup.getWindowArg('url');
+  align        = '' + tinyMCEPopup.getWindowArg('align');
+  width        = '' + tinyMCEPopup.getWindowArg('width');
+  height       = '' + tinyMCEPopup.getWindowArg('height');
 
   if (nid > 0) {
     frames['img_assist_main'].window.location.href = BASE_URL + 'index.php?q=img_assist/properties/' + nid + '/update';
@@ -98,6 +93,7 @@ function getFilterTag(formObj) {
   align        = formObj['edit-align'].value;
   width        = formObj['edit-width'].value;
   height       = formObj['edit-height'].value;
+  var size     = formObj['edit-size-label'].value;
   
   // Create the image placeholder tag
   // @see TinyMCE_drupalimage_cleanup() in drupalimage plugin.
@@ -107,7 +103,7 @@ function getFilterTag(formObj) {
     miscAttribs += '|url=' + url;
   }
   miscAttribs = encodeURIComponent(miscAttribs);
-  var content = '<img src="' + (tinyMCE.getParam("theme_href") + "/images/spacer.gif") + '"'
+  var content = '<img src="' + (tinyMCE.getParam("theme_href") + '/image/view/' + nid) + '"'
               + ' width="' + width + '" height="' + height + '" align="' + align + '"'
               + ' alt="' + miscAttribs + '" title="' + miscAttribs + '"'
               + ' name="mceItemDrupalImage" class="mceItemDrupalImage" />';
@@ -117,8 +113,7 @@ function getFilterTag(formObj) {
 
 function insertToEditor(content) {
   // Insert the image
-  tinyMCE.execCommand("mceInsertContent", true, content);
-  tinyMCE.selectedInstance.repaint();
+  tinyMCEPopup.editor.execCommand('mceInsertContent', false, content);
   
   // Close the dialog
   tinyMCEPopup.close();
@@ -130,5 +125,3 @@ function cancelAction() {
   tinyMCEPopup.close();
 }
 
-// While loading
-preinit();
Index: drupalimage/README.txt
===================================================================
RCS file: drupalimage/README.txt
diff -N drupalimage/README.txt
--- drupalimage/README.txt	21 Sep 2007 01:37:57 -0000	1.1.4.2
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,14 +0,0 @@
-$Id: README.txt,v 1.1.4.2 2007/09/21 01:37:57 sun Exp $
-
-drupalimage plugin for TinyMCE
-------------------------------
-
-This plugin integrates the Drupal img_assist module with TinyMCE allowing
-you to upload, browse and insert images into your post. Please read the
-img_assist documentation for details.
-
-
-Original plugin written by TinyMCE.module developers
-Completely rewritten for Drupal 4.7 by BenShell (based on the TinyMCE Flash
-plugin).
-
Index: drupalimage/drupalimage.css
===================================================================
RCS file: drupalimage/drupalimage.css
diff -N drupalimage/drupalimage.css
--- drupalimage/drupalimage.css	18 Jul 2008 00:14:51 -0000	1.1.4.1.2.1
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,10 +0,0 @@
-/* $Id: drupalimage.css,v 1.1.4.1.2.1 2008/07/18 00:14:51 sun Exp $ */
-
-.mceItemDrupalImage {
-	border: 1px dotted #cc0000;
-	background-image: url('images/drupalimage.gif');
-	background-position: center;
-	background-repeat: no-repeat;
-	background-color: #ffffcc;
-}
-
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.2.2
diff -u -p -r1.1.4.4.2.2 editor_plugin.js
--- drupalimage/editor_plugin.js	18 Jul 2008 00:14:51 -0000	1.1.4.4.2.2
+++ drupalimage/editor_plugin.js	26 Dec 2008 17:44:37 -0000
@@ -1,248 +1,130 @@
 // $Id: editor_plugin.js,v 1.1.4.4.2.2 2008/07/18 00:14:51 sun Exp $
 
-// Import plugin language.
-tinyMCE.importPluginLanguagePack('drupalimage', 'en');
-
-var TinyMCE_DrupalImagePlugin = {
-  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'];
+(function() {
+  // Load plugin specific language pack.
+  tinymce.PluginManager.requireLangPack('img_assist');
+
+  tinymce.create('tinymce.plugins.ImageAssistPlugin', {
+    /**
+     * Initialize the plugin, executed after the plugin has been created.
+     *
+     * This call is done before the editor instance has finished it's
+     * initialization so use the onInit event of the editor instance to
+     * intercept that event.
+     *
+     * @param ed
+     *   The tinymce.Editor instance the plugin is initialized in.
+     * @param url
+     *   The absolute URL of the plugin location.
+     */
+    init : function(ed, url) {
+      // Register the ImageAssist execCommand.
+      ed.addCommand('ImageAssist', function() {
+        // captionTitle and captionDesc for backwards compatibility.
+        var data = {nid: '', title: '', captionTitle: '', desc: '', captionDesc: '', link: '', url: '', align: '', width: '', height: '', id: ed.id, action: 'insert'};
+        var node = ed.selection.getNode();
+        if (node.name == 'mceItemDrupalImage') {
+          data.width = node.width;
+          data.height = node.height;
+          data.align = node.align;
+          // Expand inline tag in alt attribute
+          node.alt = decodeURIComponent(node.alt);
+          var chunks = node.alt.split('|');
+          for (var i in chunks) {
+            chunks[i].replace(/([^=]+)=(.*)/g, function(o, property, value) {
+              data[property] = value;
+            });
           }
-          action = 'update';
+          data.captionTitle = data.title;
+          data.captionDesc = data.desc;
+          data.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];
+        ed.windowManager.open({
+          file : Drupal.settings.basePath + 'index.php?q=img_assist/load/tinymce&textarea=' + ed.id,
+          width : 700 + parseInt(ed.getLang('img_assist.delta_width', 0)),
+          height : 500 + parseInt(ed.getLang('img_assist.delta_height', 0)),
+          inline : 1
+        }, data);
+      });
+
+      // Register Image Assist button.
+      ed.addButton('img_assist', {
+        title : 'img_assist.desc',
+        cmd : 'ImageAssist',
+        image : url + '/images/drupalimage.gif'
+      });
+
+      // Load Image Assist's CSS for editor contents on startup.
+      ed.onInit.add(function() {
+        if (!ed.settings.drupalimage_skip_plugin_css) {
+          ed.dom.loadCSS(url + "/css/img_assist.css");
+        }
+      });
+
+      // Replace images with inline tags in editor contents upon data.save.
+      // @todo Escape regular | pipes.
+      ed.onBeforeGetContent.add(function(ed, data) {
+        if (!data.save) {
+          return;
+        }
+        each(ed.dom.select('img', data.content), function(node) {
+          if (node.name != 'mceItemDrupalImage') {
+            return;
+          }
+          var inlineTag = '[img_assist|' + decodeURIComponent(node.alt) + '|align=' + node.align + '|width=' + node.width + '|height=' + node.height + ']';
+          ed.dom.setOuterHTML(node, inlineTag);
+        });
+      });
+
+      // Replace inline tags in data.content with images.
+      ed.onBeforeSetContent.add(function(ed, data) {
+        data.content = data.content.replace(/\[img_assist\|([^\[\]]+)\]/g, function(orig, match) {
+          var node = {}, chunks = match.split('|');
+          for (var i in chunks) {
+            chunks[i].replace(/([^=]+)=(.*)/g, function(o, property, value) {
+              node[property] = value;
+            });
+          }
+          node.name = 'mceItemDrupalImage';
+          node.src = Drupal.settings.basePath + 'index.php?q=image/view/' + node.nid;
+          node.alt = 'nid=' + node.nid + '|title=' + node.title + '|desc=' + node.desc;
+          if (node.link.indexOf(',') != -1) {
+            var link = node.link.split(',', 2);
+            node.alt += '|link=' + link[0] + '|url=' + link[1];
           }
           else {
-            miscAttribs += '|link=' + attribs['link'];
+            node.alt += '|link=' + node.link;
           }
-          if(typeof attribs['url'] != 'undefined') {
-            miscAttribs += '|url=' + attribs['url'];
+          if (typeof node.url != 'undefined') {
+            node.alt += '|url=' + node.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 += '<img src="' + (tinyMCE.getParam('theme_href') + '/images/spacer.gif') + '"';
-          content += ' width="' + attribs['width'] + '" height="' + attribs['height'] + '" align="' + attribs['align'] + '"';
-          content += ' alt="' + miscAttribs + '" title="' + miscAttribs + '" name="mceItemDrupalImage" class="mceItemDrupalImage" />';
-          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('<img', startPos + 1)) != -1) {
-          var endPos = 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: &quot; &amp; &lt; &gt;
-   *
-   * 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=&quot;To be or not to be&quot;|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);
-
+          node.alt = encodeURIComponent(node.alt);
+          return ed.dom.createHTML('img', node);
+        });
+        return;
+      });
+
+      // Add a node change handler, selects the button in the UI when an image is selected.
+      ed.onNodeChange.add(function(ed, command, node) {
+        command.setActive('img_assist', node.nodeName == 'IMG' && ed.dom.getAttrib(node, 'name').indexOf('mceItemDrupalImage') != -1);
+      });
+    },
+
+    /**
+     * Return information about the plugin as a name/value array.
+     */
+    getInfo : function() {
+      return {
+        longname : 'Image Assist',
+        author : 'Daniel F. Kudwien',
+        authorurl : 'http://www.unleashedmind.com',
+        infourl : 'http://drupal.org/project/img_assist',
+        version : "2.0"
+      };
+    }
+  });
+
+  // Register plugin.
+  tinymce.PluginManager.add('img_assist', tinymce.plugins.ImageAssistPlugin);
+})();
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.2.2
diff -u -p -r1.1.4.4.2.2 editor_plugin_src.js
--- drupalimage/editor_plugin_src.js	18 Jul 2008 00:14:51 -0000	1.1.4.4.2.2
+++ drupalimage/editor_plugin_src.js	26 Dec 2008 17:44:52 -0000
@@ -1,248 +1,130 @@
 // $Id: editor_plugin_src.js,v 1.1.4.4.2.2 2008/07/18 00:14:51 sun Exp $
 
-// Import plugin language.
-tinyMCE.importPluginLanguagePack('drupalimage', 'en');
-
-var TinyMCE_DrupalImagePlugin = {
-  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'];
+(function() {
+  // Load plugin specific language pack.
+  tinymce.PluginManager.requireLangPack('img_assist');
+
+  tinymce.create('tinymce.plugins.ImageAssistPlugin', {
+    /**
+     * Initialize the plugin, executed after the plugin has been created.
+     *
+     * This call is done before the editor instance has finished it's
+     * initialization so use the onInit event of the editor instance to
+     * intercept that event.
+     *
+     * @param ed
+     *   The tinymce.Editor instance the plugin is initialized in.
+     * @param url
+     *   The absolute URL of the plugin location.
+     */
+    init : function(ed, url) {
+      // Register the ImageAssist execCommand.
+      ed.addCommand('ImageAssist', function() {
+        // captionTitle and captionDesc for backwards compatibility.
+        var data = {nid: '', title: '', captionTitle: '', desc: '', captionDesc: '', link: '', url: '', align: '', width: '', height: '', id: ed.id, action: 'insert'};
+        var node = ed.selection.getNode();
+        if (node.name == 'mceItemDrupalImage') {
+          data.width = node.width;
+          data.height = node.height;
+          data.align = node.align;
+          // Expand inline tag in alt attribute
+          node.alt = decodeURIComponent(node.alt);
+          var chunks = node.alt.split('|');
+          for (var i in chunks) {
+            chunks[i].replace(/([^=]+)=(.*)/g, function(o, property, value) {
+              data[property] = value;
+            });
           }
-          action = 'update';
+          data.captionTitle = data.title;
+          data.captionDesc = data.desc;
+          data.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];
+        ed.windowManager.open({
+          file : Drupal.settings.basePath + 'index.php?q=img_assist/load/tinymce&textarea=' + ed.id,
+          width : 700 + parseInt(ed.getLang('img_assist.delta_width', 0)),
+          height : 500 + parseInt(ed.getLang('img_assist.delta_height', 0)),
+          inline : 1
+        }, data);
+      });
+
+      // Register Image Assist button.
+      ed.addButton('img_assist', {
+        title : 'img_assist.desc',
+        cmd : 'ImageAssist',
+        image : url + '/images/drupalimage.gif'
+      });
+
+      // Load Image Assist's CSS for editor contents on startup.
+      ed.onInit.add(function() {
+        if (!ed.settings.drupalimage_skip_plugin_css) {
+          ed.dom.loadCSS(url + "/css/img_assist.css");
+        }
+      });
+
+      // Replace images with inline tags in editor contents upon data.save.
+      // @todo Escape regular | pipes.
+      ed.onBeforeGetContent.add(function(ed, data) {
+        if (!data.save) {
+          return;
+        }
+        each(ed.dom.select('img', data.content), function(node) {
+          if (node.name != 'mceItemDrupalImage') {
+            return;
+          }
+          var inlineTag = '[img_assist|' + decodeURIComponent(node.alt) + '|align=' + node.align + '|width=' + node.width + '|height=' + node.height + ']';
+          ed.dom.setOuterHTML(node, inlineTag);
+        });
+      });
+
+      // Replace inline tags in data.content with images.
+      ed.onBeforeSetContent.add(function(ed, data) {
+        data.content = data.content.replace(/\[img_assist\|([^\[\]]+)\]/g, function(orig, match) {
+          var node = {}, chunks = match.split('|');
+          for (var i in chunks) {
+            chunks[i].replace(/([^=]+)=(.*)/g, function(o, property, value) {
+              node[property] = value;
+            });
+          }
+          node.name = 'mceItemDrupalImage';
+          node.src = Drupal.settings.basePath + 'index.php?q=image/view/' + node.nid;
+          node.alt = 'nid=' + node.nid + '|title=' + node.title + '|desc=' + node.desc;
+          if (node.link.indexOf(',') != -1) {
+            var link = node.link.split(',', 2);
+            node.alt += '|link=' + link[0] + '|url=' + link[1];
           }
           else {
-            miscAttribs += '|link=' + attribs['link'];
+            node.alt += '|link=' + node.link;
           }
-          if(typeof attribs['url'] != 'undefined') {
-            miscAttribs += '|url=' + attribs['url'];
+          if (typeof node.url != 'undefined') {
+            node.alt += '|url=' + node.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 += '<img src="' + (tinyMCE.getParam('theme_href') + '/images/spacer.gif') + '"';
-          content += ' width="' + attribs['width'] + '" height="' + attribs['height'] + '" align="' + attribs['align'] + '"';
-          content += ' alt="' + miscAttribs + '" title="' + miscAttribs + '" name="mceItemDrupalImage" class="mceItemDrupalImage" />';
-          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('<img', startPos + 1)) != -1) {
-          var endPos = 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: &quot; &amp; &lt; &gt;
-   *
-   * 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=&quot;To be or not to be&quot;|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);
-
+          node.alt = encodeURIComponent(node.alt);
+          return ed.dom.createHTML('img', node);
+        });
+        return;
+      });
+
+      // Add a node change handler, selects the button in the UI when an image is selected.
+      ed.onNodeChange.add(function(ed, command, node) {
+        command.setActive('img_assist', node.nodeName == 'IMG' && ed.dom.getAttrib(node, 'name').indexOf('mceItemDrupalImage') != -1);
+      });
+    },
+
+    /**
+     * Return information about the plugin as a name/value array.
+     */
+    getInfo : function() {
+      return {
+        longname : 'Image Assist',
+        author : 'Daniel F. Kudwien',
+        authorurl : 'http://www.unleashedmind.com',
+        infourl : 'http://drupal.org/project/img_assist',
+        version : "2.0"
+      };
+    }
+  });
+
+  // Register plugin.
+  tinymce.PluginManager.add('img_assist', tinymce.plugins.ImageAssistPlugin);
+})();
Index: drupalimage/css/img_assist.css
===================================================================
RCS file: drupalimage/css/img_assist.css
diff -N drupalimage/css/img_assist.css
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ drupalimage/css/img_assist.css	25 Dec 2008 19:15:08 -0000
@@ -0,0 +1,10 @@
+/* $Id: img_assist.css,v 1.1.2.2 2008/12/25 19:15:08 sun Exp $ */
+
+.mceItemDrupalImage {
+  border: 1px dotted #cc0000;
+  background-image: url('images/drupalimage.gif');
+  background-position: center;
+  background-repeat: no-repeat;
+  background-color: #ffffcc;
+}
+
Index: drupalimage/images/readme.txt
===================================================================
RCS file: drupalimage/images/readme.txt
diff -N drupalimage/images/readme.txt
--- drupalimage/images/readme.txt	15 Mar 2006 23:10:27 -0000	1.1
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,2 +0,0 @@
-The camera icon (camera.png) was taken from the 'slick' icon pack for KDE.  
-As they are included in Debian, I'm assuming that they are compatible with the GPL.
Index: drupalimage/langs/de.js
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/img_assist/drupalimage/langs/de.js,v
retrieving revision 1.1.2.1
diff -u -p -r1.1.2.1 de.js
--- drupalimage/langs/de.js	13 Feb 2008 02:18:40 -0000	1.1.2.1
+++ drupalimage/langs/de.js	26 Dec 2008 17:29:30 -0000
@@ -1,6 +1,3 @@
-// German language variables
-
-tinyMCE.addToLang('drupalimage', {
-  title: 'Bild einfügen',
-  desc: 'Ein vorhandenes Bild einfügen oder ein neues hochladen'
+tinyMCE.addI18n('de.img_assist', {
+  desc: 'Bild einfügen oder aktualisieren.'
 });
Index: drupalimage/langs/en.js
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/img_assist/drupalimage/langs/en.js,v
retrieving revision 1.1.4.2
diff -u -p -r1.1.4.2 en.js
--- drupalimage/langs/en.js	21 Sep 2007 01:37:57 -0000	1.1.4.2
+++ drupalimage/langs/en.js	26 Dec 2008 17:29:30 -0000
@@ -1,6 +1,3 @@
-// English language variables
-
-tinyMCE.addToLang('drupalimage', {
-  title: 'Drupal image',
-  desc: 'Add an existing Drupal image or upload a new one.'
+tinyMCE.addI18n('en.img_assist', {
+  desc : 'Insert or update an embedded image.'
 });
