This commit is contained in:
Jake Dallimore
2020-05-05 11:55:15 +08:00
4 changed files with 483 additions and 267 deletions
@@ -243,6 +243,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.
@@ -259,118 +260,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;
}
return this._handlePasteOrDropHelper(e, e._event.dataTransfer);
},
/**
* 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;
}
return this._handlePasteOrDropHelper(e, e._event.clipboardData);
},
/**
* 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();
return false;
} else {
// Let someone else try to handle it.
return true;
}
},
/**
* 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();
e = e._event;
// 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)) {
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);
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);
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;
}
// 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);
}
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();
// 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;
// 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);
}
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 (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.
File diff suppressed because one or more lines are too long
@@ -243,6 +243,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.
@@ -259,118 +260,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;
}
return this._handlePasteOrDropHelper(e, e._event.dataTransfer);
},
/**
* 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;
}
return this._handlePasteOrDropHelper(e, e._event.clipboardData);
},
/**
* 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();
return false;
} else {
// Let someone else try to handle it.
return true;
}
},
/**
* 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();
e = e._event;
// 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)) {
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);
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);
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;
}
// 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);
}
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();
// 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;
// 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);
}
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 (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.
+160 -88
View File
@@ -241,6 +241,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.
@@ -257,118 +258,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;
}
return this._handlePasteOrDropHelper(e, e._event.dataTransfer);
},
/**
* 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;
}
return this._handlePasteOrDropHelper(e, e._event.clipboardData);
},
/**
* 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();
return false;
} else {
// Let someone else try to handle it.
return true;
}
},
/**
* 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();
e = e._event;
// 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)) {
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);
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);
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;
}
// 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);
}
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();
// 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;
// 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);
}
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 (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.