How to prevent pasting of images (with a "data:image" URI scheme) into TinyMCE text fields

Let's first take a look at what I'm talking about. Smile Firefox (starting with version 4) supports copy+paste of images into HTML textfields using the data URI scheme. This is nice for embedding small images into your HTML document.

An image using the data URI scheme looks like this:
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot">

However if you've a content management system that already supports insertion of images (via upload/attachments), then you won't want to have embedded images (of possibly very large size ... think of several megabytes per image). Text or HTML content should not be mixed with base64 encoded strings, otherwise it might seriously slow down things (search, indexing, whatever, backups and recoveries) if this image insertion method gets popular among your users (or visitors).

This stackoverflow question already contains a hint to the solution, but it's not worked out yet. I'm using Drupal with the Wysiwyg module and TinyMCE, so the following solution is meant for these.

Create a module (or modify an existing one) and add the following hook implemenation to it:
function mymodule_wysiwyg_editor_settings_alter(&$settings, $context) {
        if ($context["profile"]->editor == "tinymce") {
                if (preg_match("@^(.*,)?paste(,.*)?$@", $settings["plugins"]) == 0) {
                        if ($settings["plugins"]) {
                                $settings["plugins"] .= ",paste";
                        } else {
                                $settings["plugins"] = "paste";
                        }
                }
                $settings["paste_auto_cleanup_on_paste"] = true;
                        drupal_add_js('jQuery.extend(true, Drupal.settings, {"wysiwyg": {"configs": {"tinymce": {"format' . $context["profile"]->format . '": {"paste_preprocess": '
                        . 'function(pl, o) { if (/<img.*\ssrc\s*=\s*"data:/i.test(o.content)) { o.content = "<div/>"; alert("Pasting images is prohibited! Upload/attach the image instead."); }; }'
                        . '}}}}});', "inline")
                ;
        }
}

Note: it seams that if a preprocess (or postprocess) handler of the "paste" TinyMCE plugin replaces the content with an empty (or non-HTML) string, something throws an exception and the edit field becomes unusable. Putting an empty div element in the content avoids this and automatic cleanup removes it later anyway. Eventually we get what we wanted: the image paste is prevented.

P.S.: of course the above code can be easily adopted for other CSM systems that use TinyMCE. However if you use a different wysiwyg editor, you should find a plugin (or entry point) that you can use to process paste events.

Syndicate content