From 8b578243e8c0b09d026a40ac6a2f6ac17fcc4f5e Mon Sep 17 00:00:00 2001
From: Jared Hancock <jared@osticket.com>
Date: Tue, 28 Apr 2015 22:12:30 -0500
Subject: [PATCH] redactor: Fix image paste+upload in Chrome

---
 include/ajax.draft.php |  4 +++
 js/redactor-plugins.js | 73 +++++++++++++++++++++++++++++++-----------
 2 files changed, 59 insertions(+), 18 deletions(-)

diff --git a/include/ajax.draft.php b/include/ajax.draft.php
index e963605ad..5f36b4704 100644
--- a/include/ajax.draft.php
+++ b/include/ajax.draft.php
@@ -94,6 +94,10 @@ class DraftAjaxAPI extends AjaxController {
                     ))
                 );
 
+            // Paste uploads in Chrome will have a name of 'blob'
+            if ($file[0]['name'] == 'blob')
+                $file[0]['name'] = 'screenshot-'.Misc::randcode(4);
+
             if (isset($file[0]['tmp_name'])) {
               $ids = $draft->attachments->upload($file);
             }
diff --git a/js/redactor-plugins.js b/js/redactor-plugins.js
index 6aaeea3bd..19544786b 100644
--- a/js/redactor-plugins.js
+++ b/js/redactor-plugins.js
@@ -790,16 +790,35 @@ RedactorPlugins.imagepaste = function() {
           return true;
 
       this.$editor.on('paste.imagepaste', $.proxy(this.imagepaste.buildEventPaste, this));
+
+      // Capture the selection position every so often as Redactor seems to
+      // drop it when attempting an image paste before `paste` browser event
+      // fires
+      var that = this,
+          plugin = this.imagepaste;
+      setInterval(function() {
+        if (plugin.inpaste)
+          return;
+        plugin.offset = that.caret.getOffset() || plugin.offset;
+      }, 300);
     },
+    offset: 0,
+    inpaste: false,
     buildEventPaste: function(e)
     {
       var event = e.originalEvent || e,
           fileUpload = false,
           files = [],
           i, file,
-          cd = event.clipboardData;
+          plugin = this.imagepaste,
+          cd = event.clipboardData,
+          self = this, node,
+          bail = function() {
+            plugin.inpaste = false;
+          };
+      plugin.inpaste = true;
 
-      if (typeof(cd) === 'undefined') return;
+      if (typeof(cd) === 'undefined') return bail();
 
       if (cd.items && cd.items.length)
       {
@@ -824,23 +843,41 @@ RedactorPlugins.imagepaste = function() {
           }
         }
       }
-      var self = this, node;
-      this.opts.imageUploadCallback = function(image, json) {
-        // Redactor just has a bloody hard time inserting for some dumb
-        // reason.
-      };
 
-      if (files.length) {
-        // clipboard upload
-        var I = setInterval(function() {
-          if (!self.focus.isFocused())
-            return;
-          clearInterval(I);
-          self.clean.singleLine = false;
-          for (i = 0, k = files.length; i < k; i++)
-            self.upload.directUpload(files[i], e);
-        }, 5);
-      }
+      if (!files.length)
+        return bail();
+
+      // Clipboard upload
+
+      setTimeout(function() {
+        // We need to allow the paste operation to settle, so we can set
+        // self.clean.singleLine and not have to cleared by some other running
+        // code
+
+        var oldIUC = self.opts.imageUploadCallback;
+        self.opts.imageUploadCallback = function(image, json) {
+          self.$editor.find('.-image-upload-placeholder').remove();
+          self.opts.imageUploadCallback = oldIUC;
+          // Add a zero-width space so that the caret:getOffset will find
+          // locations after pictures if only <br> tags exist otherwise. In
+          // other words, ensure there is at least one character after the
+          // image for text character counting. Additionally, Redactor will
+          // strip the zero-width space when saving
+          $(document.createTextNode("\u200b")).insertAfter($(image));
+          bail();
+        };
+
+        // Place the cursor back in the box!
+        self.caret.setOffset(plugin.offset);
+
+        // Add cool wait cursor
+        self.insert.htmlWithoutClean('<span class="-image-upload-placeholder icon-stack"><i class="icon-circle icon-stack-base"></i><i class="icon-picture icon-light icon-spin"></i></span>');
+
+        // Upload clipboard files
+        self.clean.singleLine = false;
+        for (i = 0, k = files.length; i < k; i++)
+          self.upload.directUpload(files[i], e);
+      }, 1);
     }
   };
 };
-- 
GitLab