diff --git a/README.md b/README.md
index 5904951..a00e12e 100644
--- a/README.md
+++ b/README.md
@@ -152,16 +152,19 @@ easyMDE.value('New input for **EasyMDE**');
- **imageMaxSize**: Maximum image size in bytes, checked before upload (note: never trust client, always check image size at server-side). Defaults to `1024*1024*2` (2Mb).
- **imageAccept**: A comma-separated list of mime-types used to check image type before upload (note: never trust client, always check file types at server-side). Defaults to `image/png, image/jpeg`.
- **imageUploadEndpoint**: The endpoint where the images data will be sent, via an asynchronous *POST* request. The server is supposed to save this image, and if it's successful, return a 200-OK HTTP response containing the relative path of the image. No default value.
-- **imageTexts**: Several string literals used in image-upload features:
- - **sbInit**: Status message displayed initially if `uploadImage` is set to `true`. Defaults to `Attach files by drag and dropping or pasting from clipboard.`,
- - **sbOnDragEnter**: Status message displayed when the user drags a file to the text area. Defaults to `Drop image to upload it.`,
+- **imageTexts**: Texts displayed to the user (mainly on the status bar) for the import image feature, where `#image_name#`, `#image_size#` and `#image_max_size#` will replaced by their respective values, that can be used for customization or internationalization:
+ - **sbInit**: Status message displayed initially if `uploadImage` is set to `true`. Defaults to `Attach files by drag and dropping or pasting from clipboard.`.
+ - **sbOnDragEnter**: Status message displayed when the user drags a file to the text area. Defaults to `Drop image to upload it.`.
- **sbOnDrop**: Status message displayed when the user drops a file in the text area. Defaults to `Uploading images #images_names#`.
- - **sbProgress**: Status message displayed to show uploading progress. Defaults to `Uploading #file_name#: #progress#%`,
- - **sbOnUploaded**: Status message displayed when the image has been uploaded. Defaults to `Uploaded #image_name#`,
- - **errorImport**: Error message prompted when the served did not return a 200 response code. Defaults to `Can not import #image_name#`,
- - **errorImageTooBig**: Error message prompted to the user when the size of the image being imported is bigger than the `imageMaxSize`, where `#image_name#`, `#image_size#` and `#image_max_size#` will replaced by their respective values. Defaults to `Image #image_name# is too big (#image_size#).\n' +
- 'Maximum file size is #image_max_size#.`.
+ - **sbProgress**: Status message displayed to show uploading progress. Defaults to `Uploading #file_name#: #progress#%`.
+ - **sbOnUploaded**: Status message displayed when the image has been uploaded. Defaults to `Uploaded #image_name#`.
- **sizeUnits**: A comma-separated list of units used to display messages with human-readable file sizes. Defaults to `b,Kb,Mb`.
+- **errorMessages**: Errors displayed to the user, mainly on alert popups, where `#image_name#`, `#image_size#` and `#image_max_size#` will replaced by their respective values, that can be used for customization or internationalization:
+ - **noFileGiven**: The server did not receive any file from the user. Defaults to `You must select a file.`.
+ - **imageTypeNotAllowed**: The user send a file type which doesn't match the `imageAccept` list, or the server returned this error code. Defaults to `This image type is not allowed.`.
+ - **imageTooLarge**: The size of the image being imported is bigger than the `imageMaxSize`, or if the server returned this error code. Defaults to `Image #image_name# is too big (#image_size#).\nMaximum file size is #image_max_size#.`.
+ - **imageImportError**: An unexpected error occurred when uploading the image. Defaults to `Something went wrong when uploading the image #image_name#.`.
+
- **renderingConfig**: Adjust settings for parsing the Markdown during previewing (not editing).
- **codeSyntaxHighlighting**: If set to `true`, will highlight using [highlight.js](https://github.com/isagalaev/highlight.js). Defaults to `false`. To use this feature you must include highlight.js on your page or pass in using the `hljs` option. For example, include the script and the CSS files like: `` ``
- **hljs**: An injectible instance of [highlight.js](https://github.com/isagalaev/highlight.js). If you don't want to rely on the global namespace (`window.hljs`), you can provide an instance here. Defaults to `undefined`.
diff --git a/src/js/easymde.js b/src/js/easymde.js
index b74aa6f..51fd564 100644
--- a/src/js/easymde.js
+++ b/src/js/easymde.js
@@ -705,6 +705,7 @@ function drawImage(editor) {
/**
* Action for opening the browse-file window to upload an image to a server.
+ * @param editor {EasyMDE} The EasyMDE object
*/
function drawUploadedImage(editor) {
// TODO: Draw the image template with a fake url, ie: '![](importing foo.png...)'
@@ -714,7 +715,7 @@ function drawUploadedImage(editor) {
/**
* Action executed after an image have been successfully imported on the server.
- * @param editor The EasyMDE object
+ * @param editor {EasyMDE} The EasyMDE object
* @param url {string} The url of the uploaded image
*/
function afterImageUploaded(editor, url) {
@@ -1411,18 +1412,31 @@ var blockStyles = {
'italic': '*',
};
+/**
+ * Texts displayed to the user (mainly on the status bar) for the import image
+ * feature. Can be used for customization or internationalization.
+ */
var imageTexts = {
sbInit: 'Attach files by drag and dropping or pasting from clipboard.',
sbOnDragEnter: 'Drop image to upload it.',
sbOnDrop: 'Uploading image #images_names#...',
sbProgress: 'Uploading #file_name#: #progress#%',
sbOnUploaded: 'Uploaded #image_name#',
- errorImport: 'Can not import #image_name#',
- errorImageTooBig: 'Image #image_name# is too big (#image_size#).\n' +
- 'Maximum file size is #image_max_size#.',
sizeUnits: 'b,Kb,Mb',
};
+/**
+ * Errors displayed to the user, mainly on alert popups. Can be used for
+ * customization or internationalization.
+ */
+var errorMessages = {
+ noFileGiven: 'You must select a file.',
+ imageTypeNotAllowed: 'This image type is not allowed.',
+ imageTooLarge: 'Image #image_name# is too big (#image_size#).\n' +
+ 'Maximum file size is #image_max_size#.',
+ imageImportError: 'Something went wrong when uploading the image #image_name#.',
+};
+
/**
* Interface of EasyMDE.
*/
@@ -1534,11 +1548,12 @@ function EasyMDE(options) {
options.minHeight = options.minHeight || '300px';
- // import-image default configuration
+ // Import-image default configuration
options.uploadImage = options.uploadImage || false;
options.imageMaxSize = options.imageMaxSize || 1024*1024*2;
- options.imageTexts = extend({}, imageTexts, options.imageTexts || {});
options.imageAccept = options.imageAccept || 'image/png, image/jpeg';
+ options.imageTexts = extend({}, imageTexts, options.imageTexts || {});
+ options.errorMessages = extend({}, errorMessages, options.errorMessages || {});
// Change unique_id to uniqueId for backwards compatibility
@@ -1605,18 +1620,17 @@ EasyMDE.prototype.uploadImages = function(files) {
this.uploadImage(files[i], function onSuccess(imageUrl) {
afterImageUploaded(self, imageUrl);
- }, function onFailure(imageName, errorStatus, errorStatusText) {
- alert(self.options.imageTexts.errorImport.replace('#image_name#', imageName));
- console.log('EasyMDE: error ' + errorStatus + ' when importing image ' + imageName + ': ' + errorStatusText);
+ }, function onFailure(error) {
+ alert(error);
});
}
this.updateStatusBar('upload-image', self.options.imageTexts.sbOnDrop.replace('#images_names#', names.join(', ')));
};
/**
- *
- * @param itemName
- * @param content
+ * Update an item in the status bar.
+ * @param itemName {string} The name of the item to update (ie. 'upload-image', 'autosave', etc.).
+ * @param content {string} the new content of the item to write in the status bar.
*/
EasyMDE.prototype.updateStatusBar = function(itemName, content) {
var matchingClasses = this.gui.statusbar.getElementsByClassName(itemName);
@@ -1890,23 +1904,23 @@ EasyMDE.prototype.clearAutosavedValue = function () {
/**
* Upload an image to the server.
*
- * @param file {File} The image to upload as a HTML5 File object (https://developer.mozilla.org/en-US/docs/Web/API/File)
- * @param onSuccess {function} A callback function to execute after the image have been successfully uploaded, with parameters:
+ * @param file {File} The image to upload, as a HTML5 File object (https://developer.mozilla.org/en-US/docs/Web/API/File)
+ * @param onSuccess {function} A callback function to execute after the image has been successfully uploaded, with one parameter:
* - url (string): The URL of the uploaded image.
- * @param onError {function} A callback function to execute when the image upload fails, with parameters:
- * - fileName: the name of the image file provided by the user.
- * - errorStatus (number): The status of the response of the request, provided by XMLHttpRequest (see https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/status).
- * - errorStatusText (string): the response string returned by the HTTP server, provided by XMLHttpRequest (see https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/statusText).
+ * @param onError {function} A callback function to execute when the image upload fails, with one parameter:
+ * - error (string): the detailed error to display to the user (based on messages from options.errorMessages).
*/
EasyMDE.prototype.uploadImage = function(file, onSuccess, onError) {
- if (file.size >= this.options.imageMaxSize) {
- var units = this.options.imageTexts.sizeUnits.split(',');
- alert(this.options.imageTexts.errorImageTooBig
- .replace('#image_name#', file.name)
- .replace('#image_size#', humanFileSize(file.size, units))
- .replace('#image_max_size#', humanFileSize(this.options.imageMaxSize, units))
- );
- return;
+ function fillErrorMessage(errorMessage) {
+ var units = self.options.imageTexts.sizeUnits.split(',');
+ return errorMessage
+ .replace('#image_name#', file.name)
+ .replace('#image_size#', humanFileSize(file.size, units))
+ .replace('#image_max_size#', humanFileSize(self.options.imageMaxSize, units));
+ }
+
+ if (file.size > this.options.imageMaxSize) {
+ onError(fillErrorMessage(this.options.errorMessages.imageTooLarge));
}
var formData = new FormData();
@@ -1914,24 +1928,42 @@ EasyMDE.prototype.uploadImage = function(file, onSuccess, onError) {
var request = new XMLHttpRequest();
request.open('POST', this.options.imageUploadEndpoint);
request.send(formData);
-
var self = this;
+
request.onprogress = function (event) {
if (event.lengthComputable) {
- // TODO: test with a big image on a remote web server
+ // FIXME: progress doesn't work well
var progress = '' + Math.round((event.loaded * 100) / event.total);
self.updateStatusBar('upload-image', self.options.imageTexts.sbProgress.replace('#file_name#', file.name).replace('#progress#', progress));
}
};
request.onload = function () {
- if(this.status === 200) {
+ try {
+ var response = JSON.parse(this.responseText);
+ } catch (error) {
+ console.log('EasyMDE: The server did not return a valid json.');
+ onError(fillErrorMessage(self.options.errorMessages.imageImportError));
+ return;
+ }
+ if(this.status === 200 && response && response.data && !response.error) {
onSuccess(window.location.origin + '/' + this.responseText);
} else {
- onError(file.name, this.status, this.statusText.toString());
- // TODO: handle several errors defined by the server (bad type, file too large, etc.)
+ if(response.error && response.error in self.options.errorMessages) {
+ onError(fillErrorMessage(self.options.errorMessages[response.error]));
+ } else {
+ console.log('EasyMDE: Received an unexpected response after uploading the image.'
+ + this.status + ' (' + this.statusText + ')');
+ onError(fillErrorMessage(self.options.errorMessages.imageImportError));
+ }
}
};
+
+ request.onerror = function (event) {
+ console.log('EasyMDE: An unexpected error occurred when trying to upload the image.'
+ + event.target.status + ' (' + event.target.statusText + ')');
+ onError(self.options.errorMessages.imageImportError);
+ };
};
EasyMDE.prototype.createSideBySide = function () {