});
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.
*
* @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.