Merge branch 'MDL-68541-39' of https://github.com/PoetOS/moodle
[moodle.git] / lib / editor / atto / plugins / image / yui / src / button / js / button.js
index ac9120a..774d8b1 100644 (file)
@@ -247,6 +247,7 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
         });
         this.editor.delegate('dblclick', this._displayDialogue, 'img', this);
         this.editor.delegate('click', this._handleClick, 'img', this);
+        this.editor.on('paste', this._handlePaste, this);
         this.editor.on('drop', this._handleDragDrop, this);
 
         // e.preventDefault needed to stop the default event from clobbering the desired behaviour in some browsers.
@@ -263,118 +264,189 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
      *
      * @method _handleDragDrop
      * @param {EventFacade} e
-     * @return mixed
+     * @return {boolean} false if we handled the event, else true.
      * @private
      */
     _handleDragDrop: function(e) {
+        if (!e._event || !e._event.dataTransfer) {
+            // Drop not fully supported in this browser.
+            return true;
+        }
 
-        var self = this,
-            host = this.get('host'),
-            template = Y.Handlebars.compile(IMAGETEMPLATE);
+        return this._handlePasteOrDropHelper(e, e._event.dataTransfer);
+    },
 
-        host.saveSelection();
-        e = e._event;
+    /**
+     * Handles paste events where - if the thing being pasted is an image.
+     *
+     * @method _handlePaste
+     * @param {EventFacade} e
+     * @return {boolean} false if we handled the event, else true.
+     * @private
+     */
+    _handlePaste: function(e) {
+        if (!e._event || !e._event.clipboardData) {
+            // Paste not fully supported in this browser.
+            return true;
+        }
 
-        // Only handle the event if an image file was dropped in.
-        var handlesDataTransfer = (e.dataTransfer && e.dataTransfer.files && e.dataTransfer.files.length);
-        if (handlesDataTransfer && /^image\//.test(e.dataTransfer.files[0].type)) {
+        return this._handlePasteOrDropHelper(e, e._event.clipboardData);
+    },
 
-            var options = host.get('filepickeroptions').image,
-                savepath = (options.savepath === undefined) ? '/' : options.savepath,
-                formData = new FormData(),
-                timestamp = 0,
-                uploadid = "",
-                xhr = new XMLHttpRequest(),
-                imagehtml = "",
-                keys = Object.keys(options.repositories);
+    /**
+     * Handle a drag and drop event with an image.
+     *
+     * @method _handleDragDrop
+     * @param {EventFacade} e
+     * @param {DataTransfer} dataTransfer
+     * @return {boolean} false if we handled the event, else true.
+     * @private
+     */
+    _handlePasteOrDropHelper: function(e, dataTransfer) {
+
+        var items = dataTransfer.items,
+            didUpload = false;
+        for (var i = 0; i < items.length; i++) {
+            var item = items[i];
+            if (item.kind !== 'file') {
+                continue;
+            }
+            if (!this._isImage(item.type)) {
+                continue;
+            }
+            this._uploadImage(item.getAsFile());
+            didUpload = true;
+        }
 
+        if (didUpload) {
+            // We handled this.
             e.preventDefault();
             e.stopPropagation();
-            formData.append('repo_upload_file', e.dataTransfer.files[0]);
-            formData.append('itemid', options.itemid);
-
-            // List of repositories is an object rather than an array.  This makes iteration more awkward.
-            for (var i = 0; i < keys.length; i++) {
-                if (options.repositories[keys[i]].type === 'upload') {
-                    formData.append('repo_id', options.repositories[keys[i]].id);
-                    break;
-                }
-            }
-            formData.append('env', options.env);
-            formData.append('sesskey', M.cfg.sesskey);
-            formData.append('client_id', options.client_id);
-            formData.append('savepath', savepath);
-            formData.append('ctx_id', options.context.id);
-
-            // Insert spinner as a placeholder.
-            timestamp = new Date().getTime();
-            uploadid = 'moodleimage_' + Math.round(Math.random() * 100000) + '-' + timestamp;
-            host.focus();
-            host.restoreSelection();
-            imagehtml = template({
-                url: M.util.image_url("i/loading_small", 'moodle'),
-                alt: M.util.get_string('uploading', COMPONENTNAME),
-                id: uploadid
-            });
-            host.insertContentAtFocusPoint(imagehtml);
-            self.markUpdated();
-
-            // Kick off a XMLHttpRequest.
-            xhr.onreadystatechange = function() {
-                var placeholder = self.editor.one('#' + uploadid),
-                    result,
-                    file,
-                    newhtml,
-                    newimage;
-
-                if (xhr.readyState === 4) {
-                    if (xhr.status === 200) {
-                        result = JSON.parse(xhr.responseText);
-                        if (result) {
-                            if (result.error) {
-                                if (placeholder) {
-                                    placeholder.remove(true);
-                                }
-                                return new M.core.ajaxException(result);
-                            }
+            return false;
+        } else {
+            // Let someone else try to handle it.
+            return true;
+        }
+    },
 
-                            file = result;
-                            if (result.event && result.event === 'fileexists') {
-                                // A file with this name is already in use here - rename to avoid conflict.
-                                // Chances are, it's a different image (stored in a different folder on the user's computer).
-                                // If the user wants to reuse an existing image, they can copy/paste it within the editor.
-                                file = result.newfile;
-                            }
+    /**
+     * Is this file an image?
+     *
+     * @method _isImage
+     * @param {string} mimeType the file's mime type.
+     * @return {boolean} true if the file has an image mimeType.
+     * @private
+     */
+    _isImage: function(mimeType) {
+        return mimeType.indexOf('image/') === 0;
+    },
+
+    /**
+     * Used by _handleDragDrop and _handlePaste to upload an image and insert it.
+     *
+     * @method _uploadImage
+     * @param {File} fileToSave
+     * @private
+     */
+    _uploadImage: function(fileToSave) {
+
+        var self = this,
+            host = this.get('host'),
+            template = Y.Handlebars.compile(IMAGETEMPLATE);
+
+        host.saveSelection();
 
-                            // Replace placeholder with actual image.
-                            newhtml = template({
-                                url: file.url,
-                                presentation: true
-                            });
-                            newimage = Y.Node.create(newhtml);
+        var options = host.get('filepickeroptions').image,
+            savepath = (options.savepath === undefined) ? '/' : options.savepath,
+            formData = new FormData(),
+            timestamp = 0,
+            uploadid = "",
+            xhr = new XMLHttpRequest(),
+            imagehtml = "",
+            keys = Object.keys(options.repositories);
+
+        formData.append('repo_upload_file', fileToSave);
+        formData.append('itemid', options.itemid);
+
+        // List of repositories is an object rather than an array.  This makes iteration more awkward.
+        for (var i = 0; i < keys.length; i++) {
+            if (options.repositories[keys[i]].type === 'upload') {
+                formData.append('repo_id', options.repositories[keys[i]].id);
+                break;
+            }
+        }
+        formData.append('env', options.env);
+        formData.append('sesskey', M.cfg.sesskey);
+        formData.append('client_id', options.client_id);
+        formData.append('savepath', savepath);
+        formData.append('ctx_id', options.context.id);
+
+        // Insert spinner as a placeholder.
+        timestamp = new Date().getTime();
+        uploadid = 'moodleimage_' + Math.round(Math.random() * 100000) + '-' + timestamp;
+        host.focus();
+        host.restoreSelection();
+        imagehtml = template({
+            url: M.util.image_url("i/loading_small", 'moodle'),
+            alt: M.util.get_string('uploading', COMPONENTNAME),
+            id: uploadid
+        });
+        host.insertContentAtFocusPoint(imagehtml);
+        self.markUpdated();
+
+        // Kick off a XMLHttpRequest.
+        xhr.onreadystatechange = function() {
+            var placeholder = self.editor.one('#' + uploadid),
+                result,
+                file,
+                newhtml,
+                newimage;
+
+            if (xhr.readyState === 4) {
+                if (xhr.status === 200) {
+                    result = JSON.parse(xhr.responseText);
+                    if (result) {
+                        if (result.error) {
                             if (placeholder) {
-                                placeholder.replace(newimage);
-                            } else {
-                                self.editor.appendChild(newimage);
+                                placeholder.remove(true);
                             }
-                            self.markUpdated();
+                            throw new M.core.ajaxException(result);
                         }
-                    } else {
-                        Y.use('moodle-core-notification-alert', function() {
-                            new M.core.alert({message: M.util.get_string('servererror', 'moodle')});
+
+                        file = result;
+                        if (result.event && result.event === 'fileexists') {
+                            // A file with this name is already in use here - rename to avoid conflict.
+                            // Chances are, it's a different image (stored in a different folder on the user's computer).
+                            // If the user wants to reuse an existing image, they can copy/paste it within the editor.
+                            file = result.newfile;
+                        }
+
+                        // Replace placeholder with actual image.
+                        newhtml = template({
+                            url: file.url,
+                            presentation: true
                         });
+                        newimage = Y.Node.create(newhtml);
                         if (placeholder) {
-                            placeholder.remove(true);
+                            placeholder.replace(newimage);
+                        } else {
+                            self.editor.appendChild(newimage);
                         }
+                        self.markUpdated();
+                    }
+                } else {
+                    Y.use('moodle-core-notification-alert', function() {
+                        new M.core.alert({message: M.util.get_string('servererror', 'moodle')});
+                    });
+                    if (placeholder) {
+                        placeholder.remove(true);
                     }
                 }
-            };
-            xhr.open("POST", M.cfg.wwwroot + '/repository/repository_ajax.php?action=upload', true);
-            xhr.send(formData);
-            return false;
-        }
-
-},
+            }
+        };
+        xhr.open("POST", M.cfg.wwwroot + '/repository/repository_ajax.php?action=upload', true);
+        xhr.send(formData);
+    },
 
     /**
      * Handle a click on an image.