define([
  'summernote/base/core/list',
  'summernote/base/core/dom',
  'summernote/base/core/key',
  'summernote/base/core/agent'
], function (list, dom, key, agent) {
  var Clipboard = function (context) {
    var self = this;

    var $editable = context.layoutInfo.editable;
    var $paste;

    this.initialize = function () {
      // [workaround] getting image from clipboard
      //  - IE11 and Firefox: CTRL+v hook
      //  - Webkit: event.clipboardData
      if ((agent.isMSIE && agent.browserVersion > 10) || agent.isFF) {
        $paste = $('<div />').attr('contenteditable', true).css({
          position : 'absolute',
          left : -100000,
          opacity : 0
        });

        $editable.on('keydown', function (e) {
          if (e.ctrlKey && e.keyCode === key.code.V) {
            context.invoke('editor.saveRange');
            $paste.focus();

            setTimeout(function () {
              self.pasteByHook();
            }, 0);
          }
        });

        $editable.before($paste);
      } else {
        $editable.on('paste', this.pasteByEvent);
      }
    };

    this.pasteByHook = function () {
      var node = $paste[0].firstChild;

      if (dom.isImg(node)) {
        var dataURI = node.src;
        var decodedData = atob(dataURI.split(',')[1]);
        var array = new Uint8Array(decodedData.length);
        for (var i = 0; i < decodedData.length; i++) {
          array[i] = decodedData.charCodeAt(i);
        }

        var blob = new Blob([array], { type : 'image/png' });
        blob.name = 'clipboard.png';

        context.invoke('editor.restoreRange');
        context.invoke('editor.focus');
        context.invoke('imageDialog.insertImages', [blob]);
      } else {
        var pasteContent = $('<div />').html($paste.html()).html();
        context.invoke('editor.restoreRange');
        context.invoke('editor.focus');

        if (pasteContent) {
          context.invoke('editor.pasteHTML', pasteContent);
        }
      }

      $paste.empty();
    };

    /**
     * paste by clipboard event
     *
     * @param {Event} event
     */
    this.pasteByEvent = function (event) {
      var clipboardData = event.originalEvent.clipboardData;
      if (clipboardData && clipboardData.items && clipboardData.items.length) {
        var item = list.head(clipboardData.items);
        if (item.kind === 'file' && item.type.indexOf('image/') !== -1) {
          context.invoke('imageDialog.insertImages', [item.getAsFile()]);
        }
        context.invoke('editor.afterCommand');
      }
    };
  };

  return Clipboard;
});

@@ -276,22 +276,512 @@
 le;%0A
+%0A
     
-var $paste
+this.events = %7B%0A      'summernote.keydown': function (we, e) %7B%0A        if (self.needKeydownHook()) %7B%0A          if ((e.ctrlKey %7C%7C e.metaKey) && e.keyCode === key.code.V) %7B%0A            context.invoke('editor.saveRange');%0A            self.$paste.focus();%0A%0A            setTimeout(function () %7B%0A              self.pasteByHook();%0A            %7D, 0);%0A          %7D%0A        %7D%0A      %7D%0A    %7D;%0A%0A    this.needKeydownHook = function () %7B%0A      return (agent.isMSIE && agent.browserVersion %3E 10) %7C%7C agent.isFF;%0A    %7D
 ;%0A%0A 
@@ -962,65 +962,30 @@
 if (
-(agent.isMSIE && agent.browserVersion %3E 10) %7C%7C agent.isFF
+this.needKeydownHook()
 ) %7B%0A
@@ -988,24 +988,29 @@
 ) %7B%0A        
+this.
 $paste = $('
@@ -1140,33 +1140,32 @@
 : 0%0A        %7D);%0A
-%0A
         $editabl
@@ -1170,94 +1170,81 @@
 ble.
-on('keydown', function (e) %7B%0A          if (e.ctrlKey && e.keyCode === key.code.V
+before(this.$paste);%0A%0A        this.$paste.on('paste', function (event
 ) %7B%0A
-  
     
@@ -1261,128 +1261,107 @@
 ext.
-invoke('editor.saveRange');%0A            $paste.focus(
+triggerEvent('paste', event);%0A        %7D
 );%0A
-%0A
       
-      setTimeout(function () %7B%0A              self
+%7D else %7B%0A        $editable.on('paste', this
 .pasteBy
 Hook
@@ -1348,37 +1348,37 @@
 e', this.pasteBy
-Hook(
+Event
 );%0A            %7D
@@ -1374,142 +1374,76 @@
     
- 
-     %7D, 0);%0A          %7D%0A        %7D);%0A%0A        $editable.before($paste);%0A      %7D else %7B%0A        $editable.on('paste',
+%7D%0A    %7D;%0A%0A    this.destroy = function () %7B%0A     
  this.
+$
 paste
-ByEvent
+.remove(
 );%0A 
@@ -1439,33 +1439,51 @@
 remove();%0A      
-%7D
+this.$paste = null;
 %0A    %7D;%0A%0A    thi
@@ -1529,16 +1529,21 @@
  node = 
+this.
 $paste%5B0
@@ -2150,16 +2150,21 @@
 ').html(
+this.
 $paste.h
@@ -2379,16 +2379,21 @@
 %0A%0A      
+this.
 $paste.e

Attach `paste` event on dummy $paste for hooking. - Fixed 1382.