From 11e613b3d57ba1814ac7a612c122fbe147387f0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathana=C3=ABl=20Jourdane?= Date: Mon, 4 Mar 2019 17:05:22 +0100 Subject: [PATCH 01/51] [wip upload-image] Add image icon to open the browse-file window --- src/js/easymde.js | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/js/easymde.js b/src/js/easymde.js index bf59082..7fdaeed 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -170,6 +170,30 @@ function createTooltip(title, action, shortcuts) { return tooltip; } +/** + * Create the input element (ie. ) used to open the + * browse-file window in order to allow the user to select an image to be + * imported to the server. Used among with the 'import-image' icon. + * @param editor {Object} the EasyMDE object + * @returns Node The created input DOM element. + */ +function createImageInput(editor) { + var imageInput = document.createElement('input'); + imageInput.className = 'imageInput'; + imageInput.type = 'file'; + imageInput.multiple = true; + imageInput.name = 'image'; + imageInput.accept = editor.options.imageAccept; + imageInput.style.display = 'none'; + imageInput.style.opacity = 0; + imageInput.addEventListener('change', function(event) { + for(var i=0; i Date: Mon, 4 Mar 2019 17:10:11 +0100 Subject: [PATCH 02/51] [wip upload-image] Upload image when selecting it on browse-file window --- src/js/easymde.js | 76 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/src/js/easymde.js b/src/js/easymde.js index 7fdaeed..c7d2b47 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -188,7 +188,7 @@ function createImageInput(editor) { imageInput.style.opacity = 0; imageInput.addEventListener('change', function(event) { for(var i=0; i= 1024 && u < units.length); + return '' + bytes.toFixed(1) + units[u]; +} + +/** + * Upload an image to the server. + * + * Can be triggered by: + * - drag&drop; // TODO + * - copy-paste; // TODO + * - the browse-file window (opened when the user clicks on the *upload-image* icon). + * + * @param file {File} The image to upload as a HTML5 File object (https://developer.mozilla.org/en-US/docs/Web/API/File) + * @param options The EasyMDE options. + */ +function uploadImage(file, options) { + if (file.size >= options.imageMaxSize) { + var units = options.imageTexts.sizeUnits.split(','); + alert(options.text.errorImageTooBig + .replace('#image_name#', file.name) + .replace('#image_size#', humanFileSize(file.size, units)) + .replace('#image_max_size#', humanFileSize(options.imageMaxSize, units)) + ); + return; + } + + var formData = new FormData(); + formData.append('image', file); + var request = new XMLHttpRequest(); + request.open('POST', options.imageUploadEndpoint); + request.send(formData); + + request.onprogress = function (event) { + if (event.lengthComputable) { + // TODO: test with a big image on a remote web server + var progress = Math.round((event.loaded * 100) / event.total); + console.log('EasyMDE: image upload progress: ' + progress + '%'); + // TODO: show progress on status bar instead + } + }; + + request.onload = function () { + if(this.status === 200) { + console.log('image url: ' + window.location.origin + '/' + this.responseText); + } else { + console.log('EasyMDE: Error ' + this.status + ' while importing image: ' + this.statusText.toString()); + } + }; +} + // Merge the properties of one object into another. function _mergeProperties(target, source) { for (var property in source) { @@ -1380,6 +1445,12 @@ var blockStyles = { 'italic': '*', }; +var imageTexts = { + errorImageTooBig: 'Image #image_name# is too big (#image_size#).\n' + + 'Maximum file size is #image_max_size#.', + sizeUnits: 'b,Kb,Mb', +}; + /** * Interface of EasyMDE. */ @@ -1488,6 +1559,9 @@ function EasyMDE(options) { // 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'; From aa39672e4eb5e7da2f546a4ea6e88a1195e744c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathana=C3=ABl=20Jourdane?= Date: Mon, 4 Mar 2019 18:10:46 +0100 Subject: [PATCH 03/51] [wip upload-image] After image upload, insert image markdown template with uploaded image url --- src/js/easymde.js | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/js/easymde.js b/src/js/easymde.js index c7d2b47..66d99b1 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -188,7 +188,11 @@ function createImageInput(editor) { imageInput.style.opacity = 0; imageInput.addEventListener('change', function(event) { for(var i=0; i= options.imageMaxSize) { var units = options.imageTexts.sizeUnits.split(','); alert(options.text.errorImageTooBig @@ -1186,9 +1207,9 @@ function uploadImage(file, options) { request.onload = function () { if(this.status === 200) { - console.log('image url: ' + window.location.origin + '/' + this.responseText); + onSuccess(window.location.origin + '/' + this.responseText); } else { - console.log('EasyMDE: Error ' + this.status + ' while importing image: ' + this.statusText.toString()); + onError(this.status, this.statusText.toString()); } }; } @@ -1430,6 +1451,8 @@ var toolbarBuiltInButtons = { var insertTexts = { link: ['[', '](#url#)'], image: ['![](', '#url#)'], + uploadedImage: ['![](#url#)', ''], + // uploadedImage: ['![](#url#)\n', ''], // TODO: New line insertion doesn't work here. table: ['', '\n\n| Column 1 | Column 2 | Column 3 |\n| -------- | -------- | -------- |\n| Text | Text | Text |\n\n'], horizontalRule: ['', '\n\n-----\n\n'], }; From 070e3e5c839eb574ff3b1b4bc6e1f57d77c7e4d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathana=C3=ABl=20Jourdane?= Date: Mon, 4 Mar 2019 18:12:54 +0100 Subject: [PATCH 04/51] [wip upload-image] update readme with new upload-image options --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 5e61481..b9101b7 100644 --- a/README.md +++ b/README.md @@ -148,6 +148,14 @@ easyMDE.value('New input for **EasyMDE**'); - **promptTexts**: Customize the text used to prompt for URLs. - **image**: The text to use when prompting for an image's URL. Defaults to `URL of the image:`. - **link**: The text to use when prompting for a link's URL. Defaults to `URL for the link:`. +- **uploadImage**: If set to `true`, enables the image upload functionality, which can be triggered by drag&drop, copy-paste and through the browse-file window (opened when the user click on the *upload-image* icon). Defaults to `false`. +- **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: + - **errorImageTooBig**: The error 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#.`. + - **sizeUnits**: A comma-separated list of units used to display messages with human-readable file sizes. Defaults to `b,Kb,Mb`. - **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`. From e1536da530e51b711fee6680abf4dad8dc5ece9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathana=C3=ABl=20Jourdane?= Date: Tue, 5 Mar 2019 10:08:01 +0100 Subject: [PATCH 05/51] [wip upload-image] bugfix error popup --- src/js/easymde.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/easymde.js b/src/js/easymde.js index 0e5a29f..cb25a6b 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -1199,7 +1199,7 @@ function humanFileSize(bytes, units) { function uploadImage(file, options, onSuccess, onError) { if (file.size >= options.imageMaxSize) { var units = options.imageTexts.sizeUnits.split(','); - alert(options.text.errorImageTooBig + alert(options.imageTexts.errorImageTooBig .replace('#image_name#', file.name) .replace('#image_size#', humanFileSize(file.size, units)) .replace('#image_max_size#', humanFileSize(options.imageMaxSize, units)) From 3cb4a817f2a3c006c2c0f521a8fd61e862476b12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathana=C3=ABl=20Jourdane?= Date: Tue, 5 Mar 2019 11:44:31 +0100 Subject: [PATCH 06/51] [wip upload-image] Allow image upload with drag&drop --- src/js/easymde.js | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/js/easymde.js b/src/js/easymde.js index cb25a6b..1399e59 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -1624,6 +1624,37 @@ function EasyMDE(options) { if (options.initialValue && (!this.options.autosave || this.options.autosave.foundSavedValue !== true)) { this.value(options.initialValue); } + + if (options.uploadImage) { + var self = this; + + this.codemirror.on('dragenter', function(cm, event) { + event.stopPropagation(); + event.preventDefault(); + }); + + this.codemirror.on('dragover', function(cm, event) { + event.stopPropagation(); + event.preventDefault(); + }); + + this.codemirror.on('drop', function(cm, event) { + event.stopPropagation(); + event.preventDefault(); + + var dt = event.dataTransfer; + var files = dt.files; + console.log(files); + + for(var i=0; i Date: Tue, 5 Mar 2019 18:08:33 +0100 Subject: [PATCH 07/51] [wip upload-image] Display status messages about image upload in status bar. --- README.md | 8 ++++- src/js/easymde.js | 79 +++++++++++++++++++++++++++++++++++------------ 2 files changed, 66 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 92298a7..5904951 100644 --- a/README.md +++ b/README.md @@ -153,7 +153,13 @@ easyMDE.value('New input for **EasyMDE**'); - **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: - - **errorImageTooBig**: The error 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' + + - **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#.`. - **sizeUnits**: A comma-separated list of units used to display messages with human-readable file sizes. Defaults to `b,Kb,Mb`. - **renderingConfig**: Adjust settings for parsing the Markdown during previewing (not editing). diff --git a/src/js/easymde.js b/src/js/easymde.js index 1399e59..ee3d51f 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -205,9 +205,10 @@ function createImageInput(editor) { imageInput.style.opacity = 0; imageInput.addEventListener('change', function(event) { for(var i=0; i= options.imageMaxSize) { - var units = options.imageTexts.sizeUnits.split(','); - alert(options.imageTexts.errorImageTooBig +function uploadImage(file, editor, onSuccess, onError) { + if (file.size >= editor.options.imageMaxSize) { + var units = editor.options.imageTexts.sizeUnits.split(','); + alert(editor.options.imageTexts.errorImageTooBig .replace('#image_name#', file.name) .replace('#image_size#', humanFileSize(file.size, units)) - .replace('#image_max_size#', humanFileSize(options.imageMaxSize, units)) + .replace('#image_max_size#', humanFileSize(editor.options.imageMaxSize, units)) ); return; } @@ -1210,15 +1217,14 @@ function uploadImage(file, options, onSuccess, onError) { var formData = new FormData(); formData.append('image', file); var request = new XMLHttpRequest(); - request.open('POST', options.imageUploadEndpoint); + request.open('POST', editor.options.imageUploadEndpoint); request.send(formData); request.onprogress = function (event) { if (event.lengthComputable) { // TODO: test with a big image on a remote web server var progress = Math.round((event.loaded * 100) / event.total); - console.log('EasyMDE: image upload progress: ' + progress + '%'); - // TODO: show progress on status bar instead + editor.updateStatusBar('upload-image', editor.options.imageTexts.sbProgress.replace('#file_name#', file.name).replace('#progress#', progress)); } }; @@ -1226,7 +1232,7 @@ function uploadImage(file, options, onSuccess, onError) { if(this.status === 200) { onSuccess(window.location.origin + '/' + this.responseText); } else { - onError(this.status, this.statusText.toString()); + onError(file.name, this.status, this.statusText.toString()); } }; } @@ -1486,6 +1492,12 @@ var blockStyles = { }; var imageTexts = { + sbInit: 'Attach files by drag and dropping or pasting from clipboard.', + sbOnDragEnter: 'Drop image to upload it.', + sbOnDrop: 'Uploading images #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', @@ -1561,7 +1573,11 @@ function EasyMDE(options) { // Handle status bar if (!options.hasOwnProperty('status')) { - options.status = ['autosave', 'lines', 'words', 'cursor']; + if (options.uploadImage) { + options.status = ['upload-image', 'autosave', 'lines', 'words', 'cursor']; + } else { + options.status = ['autosave', 'lines', 'words', 'cursor']; + } } @@ -1629,6 +1645,7 @@ function EasyMDE(options) { var self = this; this.codemirror.on('dragenter', function(cm, event) { + self.updateStatusBar('upload-image', self.options.imageTexts.sbOnDragEnter); event.stopPropagation(); event.preventDefault(); }); @@ -1642,21 +1659,39 @@ function EasyMDE(options) { event.stopPropagation(); event.preventDefault(); - var dt = event.dataTransfer; - var files = dt.files; - console.log(files); - + var files = event.dataTransfer.files; + var names = []; for(var i=0; i Date: Wed, 6 Mar 2019 15:30:51 +0100 Subject: [PATCH 08/51] [wip upload-image] Refactoring: remove createImageInput(), set uploadImage() as a prototype, create uploadImages() --- src/js/easymde.js | 182 ++++++++++++++++++++++------------------------ 1 file changed, 88 insertions(+), 94 deletions(-) diff --git a/src/js/easymde.js b/src/js/easymde.js index ee3d51f..436c2cf 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -187,35 +187,6 @@ function createTooltip(title, action, shortcuts) { return tooltip; } -/** - * Create the input element (ie. ) used to open the - * browse-file window in order to allow the user to select an image to be - * imported to the server. Used among with the 'import-image' icon. - * @param editor {Object} the EasyMDE object - * @returns Node The created input DOM element. - */ -function createImageInput(editor) { - var imageInput = document.createElement('input'); - imageInput.className = 'imageInput'; - imageInput.type = 'file'; - imageInput.multiple = true; - imageInput.name = 'image'; - imageInput.accept = editor.options.imageAccept; - imageInput.style.display = 'none'; - imageInput.style.opacity = 0; - imageInput.addEventListener('change', function(event) { - for(var i=0; i= editor.options.imageMaxSize) { - var units = editor.options.imageTexts.sizeUnits.split(','); - alert(editor.options.imageTexts.errorImageTooBig - .replace('#image_name#', file.name) - .replace('#image_size#', humanFileSize(file.size, units)) - .replace('#image_max_size#', humanFileSize(editor.options.imageMaxSize, units)) - ); - return; - } - - var formData = new FormData(); - formData.append('image', file); - var request = new XMLHttpRequest(); - request.open('POST', editor.options.imageUploadEndpoint); - request.send(formData); - - request.onprogress = function (event) { - if (event.lengthComputable) { - // TODO: test with a big image on a remote web server - var progress = Math.round((event.loaded * 100) / event.total); - editor.updateStatusBar('upload-image', editor.options.imageTexts.sbProgress.replace('#file_name#', file.name).replace('#progress#', progress)); - } - }; - - request.onload = function () { - if(this.status === 200) { - onSuccess(window.location.origin + '/' + this.responseText); - } else { - onError(file.name, this.status, this.statusText.toString()); - } - }; -} - // Merge the properties of one object into another. function _mergeProperties(target, source) { for (var property in source) { @@ -1658,23 +1578,36 @@ function EasyMDE(options) { this.codemirror.on('drop', function(cm, event) { event.stopPropagation(); event.preventDefault(); + self.uploadImages(event.dataTransfer.files); + }); + } +} - var files = event.dataTransfer.files; - var names = []; - for(var i=0; i= 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; + } + + var formData = new FormData(); + formData.append('image', file); + 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 + 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) { + 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.) + } + }; +}; + EasyMDE.prototype.createSideBySide = function () { var cm = this.codemirror; var wrapper = cm.getWrapperElement(); @@ -2067,8 +2047,22 @@ EasyMDE.prototype.createToolbar = function (items) { toolbarData[item.name || item] = el; bar.appendChild(el); + + // Create the input element (ie. ), used among + // with the 'import-image' icon to open the browse-file window. if (item.name === 'upload-image') { - bar.appendChild(createImageInput(self)); + var imageInput = document.createElement('input'); + imageInput.className = 'imageInput'; + imageInput.type = 'file'; + imageInput.multiple = true; + imageInput.name = 'image'; + imageInput.accept = self.options.imageAccept; + imageInput.style.display = 'none'; + imageInput.style.opacity = 0; + imageInput.addEventListener('change', function (event) { + self.uploadImages(event.target.files); + }); + bar.appendChild(imageInput); } })(items[i]); } From effc080bae340a8fd2a20322bb243b5fb82e3cce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathana=C3=ABl=20Jourdane?= Date: Wed, 6 Mar 2019 15:36:58 +0100 Subject: [PATCH 09/51] [wip upload-image] Allow image upload with copy-paste --- src/js/easymde.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/js/easymde.js b/src/js/easymde.js index 436c2cf..0fe954d 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -1580,6 +1580,10 @@ function EasyMDE(options) { event.preventDefault(); self.uploadImages(event.dataTransfer.files); }); + + this.codemirror.on('paste', function(cm, event) { + self.uploadImages(event.clipboardData.files); + }); } } From 9f33099b1c9c596b512908387ba6adf4d710a8b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathana=C3=ABl=20Jourdane?= Date: Thu, 7 Mar 2019 11:31:48 +0100 Subject: [PATCH 10/51] Use textContent instead innerHTML when appropriate to avoid XSS --- src/js/easymde.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/js/easymde.js b/src/js/easymde.js index 0fe954d..b74aa6f 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -169,7 +169,7 @@ function createToolbarButton(options, enableTooltips, shortcuts) { function createSep() { var el = document.createElement('i'); el.className = 'separator'; - el.innerHTML = '|'; + el.textContent = '|'; return el; } @@ -1414,7 +1414,7 @@ var blockStyles = { var imageTexts = { sbInit: 'Attach files by drag and dropping or pasting from clipboard.', sbOnDragEnter: 'Drop image to upload it.', - sbOnDrop: 'Uploading images #images_names#', + sbOnDrop: 'Uploading image #images_names#...', sbProgress: 'Uploading #file_name#: #progress#%', sbOnUploaded: 'Uploaded #image_name#', errorImport: 'Can not import #image_name#', @@ -1621,7 +1621,7 @@ EasyMDE.prototype.uploadImages = function(files) { EasyMDE.prototype.updateStatusBar = function(itemName, content) { var matchingClasses = this.gui.statusbar.getElementsByClassName(itemName); if (matchingClasses.length === 1) { - this.gui.statusbar.getElementsByClassName(itemName)[0].innerHTML = content; + this.gui.statusbar.getElementsByClassName(itemName)[0].textContent = content; } else if (matchingClasses.length === 0) { console.log('EasyMDE: status bar item ' + itemName + ' was not found.'); } else { @@ -1863,7 +1863,7 @@ EasyMDE.prototype.autosave = function () { } m = m < 10 ? '0' + m : m; - el.innerHTML = 'Autosaved: ' + h + ':' + m + ' ' + dd; + el.textContent = 'Autosaved: ' + h + ':' + m + ' ' + dd; } this.autosaveTimeoutId = setTimeout(function () { @@ -2128,25 +2128,25 @@ EasyMDE.prototype.createStatusbar = function (status) { if (name === 'words') { defaultValue = function (el) { - el.innerHTML = wordCount(cm.getValue()); + el.textContent = wordCount(cm.getValue()); }; onUpdate = function (el) { - el.innerHTML = wordCount(cm.getValue()); + el.textContent = wordCount(cm.getValue()); }; } else if (name === 'lines') { defaultValue = function (el) { - el.innerHTML = cm.lineCount(); + el.textContent = cm.lineCount(); }; onUpdate = function (el) { - el.innerHTML = cm.lineCount(); + el.textContent = cm.lineCount(); }; } else if (name === 'cursor') { defaultValue = function (el) { - el.innerHTML = '0:0'; + el.textContent = '0:0'; }; onUpdate = function (el) { var pos = cm.getCursor(); - el.innerHTML = pos.line + ':' + pos.ch; + el.textContent = pos.line + ':' + pos.ch; }; } else if (name === 'autosave') { defaultValue = function (el) { @@ -2156,7 +2156,7 @@ EasyMDE.prototype.createStatusbar = function (status) { }; } else if (name === 'upload-image') { defaultValue = function (el) { - el.innerHTML = options.imageTexts.sbInit; + el.textContent = options.imageTexts.sbInit; }; } From d374c5faec9ee89b95eda2683273d4956c951b74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathana=C3=ABl=20Jourdane?= Date: Thu, 7 Mar 2019 18:15:59 +0100 Subject: [PATCH 11/51] [wip upload-image] Better errors support and small code improvements --- README.md | 19 ++++++---- src/js/easymde.js | 94 +++++++++++++++++++++++++++++++---------------- 2 files changed, 74 insertions(+), 39 deletions(-) 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 () { From 6c8ce85ea97850ed75dcf1bc4b15a2e761f05c91 Mon Sep 17 00:00:00 2001 From: roipoussiere Date: Thu, 7 Mar 2019 20:41:45 +0100 Subject: [PATCH 12/51] Add errorCallback option --- README.md | 4 ++-- src/js/easymde.js | 15 +++++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index a00e12e..18de629 100644 --- a/README.md +++ b/README.md @@ -159,12 +159,12 @@ easyMDE.value('New input for **EasyMDE**'); - **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: +- **errorMessages**: Errors displayed to the user, using the `errorCallback` option, 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#.`. - +- **errorCallback**: A callback function used to define how to display an error message. Defaults to `function(errorMessage) {alert(errorMessage);};`. - **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 51fd564..17a58d3 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -1426,7 +1426,7 @@ var imageTexts = { }; /** - * Errors displayed to the user, mainly on alert popups. Can be used for + * Errors displayed to the user, using the `errorCallback` option. Can be used for * customization or internationalization. */ var errorMessages = { @@ -1547,6 +1547,9 @@ function EasyMDE(options) { options.minHeight = options.minHeight || '300px'; + options.errorCallback = options.errorCallback || function(errorMessage) { + alert(errorMessage); + }; // Import-image default configuration options.uploadImage = options.uploadImage || false; @@ -1621,7 +1624,7 @@ EasyMDE.prototype.uploadImages = function(files) { this.uploadImage(files[i], function onSuccess(imageUrl) { afterImageUploaded(self, imageUrl); }, function onFailure(error) { - alert(error); + self.options.errorCallback(error); }); } this.updateStatusBar('upload-image', self.options.imageTexts.sbOnDrop.replace('#images_names#', names.join(', '))); @@ -1831,22 +1834,22 @@ EasyMDE.prototype.autosave = function () { console.log('EasyMDE: You must set a uniqueId to use the autosave feature'); return; } - + if(this.options.autosave.binded !== true) { if (easyMDE.element.form != null && easyMDE.element.form != undefined) { easyMDE.element.form.addEventListener('submit', function () { clearTimeout(easyMDE.autosaveTimeoutId); easyMDE.autosaveTimeoutId = undefined; - + localStorage.removeItem('smde_' + easyMDE.options.autosave.uniqueId); - + // Restart autosaving in case the submit will be cancelled down the line setTimeout(function() { easyMDE.autosave(); }, easyMDE.options.autosave.delay || 10000); }); } - + this.options.autosave.binded = true; } From 8eff45f7a07f138961ce15253de3c11b284e9f7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathana=C3=ABl=20Jourdane?= Date: Mon, 11 Mar 2019 17:19:27 +0100 Subject: [PATCH 13/51] [wip upload-image] image server is now supposed to return a json object --- README.md | 2 +- src/js/easymde.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 18de629..bd70fcd 100644 --- a/README.md +++ b/README.md @@ -151,7 +151,7 @@ easyMDE.value('New input for **EasyMDE**'); - **uploadImage**: If set to `true`, enables the image upload functionality, which can be triggered by drag&drop, copy-paste and through the browse-file window (opened when the user click on the *upload-image* icon). Defaults to `false`. - **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. +- **imageUploadEndpoint**: The endpoint where the images data will be sent, via an asynchronous *POST* request. The server is supposed to save this image, and return a 200-OK HTTP response containing: `{"data": {"filePath": ""}}` where *imageFilePath* is the relative path of the image, otherwise, return `{"error": ""}`, where *errorCode* can be `noFileGiven`, `imageTypeNotAllowed`, `imageTooLarge` or `imageImportError` (see *errorMessages* below). No default value. - **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.`. diff --git a/src/js/easymde.js b/src/js/easymde.js index 17a58d3..1bb6fbf 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -1949,8 +1949,8 @@ EasyMDE.prototype.uploadImage = function(file, onSuccess, onError) { onError(fillErrorMessage(self.options.errorMessages.imageImportError)); return; } - if(this.status === 200 && response && response.data && !response.error) { - onSuccess(window.location.origin + '/' + this.responseText); + if(this.status === 200 && response && !response.error && response.data && response.data.filePath) { + onSuccess(window.location.origin + '/' + response.data.filePath); } else { if(response.error && response.error in self.options.errorMessages) { onError(fillErrorMessage(self.options.errorMessages[response.error])); From 5fa549d3b343bd20fb60801bdb700690fbf3d2cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathana=C3=ABl=20Jourdane?= Date: Mon, 11 Mar 2019 18:17:29 +0100 Subject: [PATCH 14/51] [wip upload-image] make onError optionnal --- src/js/easymde.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/js/easymde.js b/src/js/easymde.js index 1bb6fbf..c151668 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -1623,8 +1623,6 @@ EasyMDE.prototype.uploadImages = function(files) { this.uploadImage(files[i], function onSuccess(imageUrl) { afterImageUploaded(self, imageUrl); - }, function onFailure(error) { - self.options.errorCallback(error); }); } this.updateStatusBar('upload-image', self.options.imageTexts.sbOnDrop.replace('#images_names#', names.join(', '))); @@ -1910,10 +1908,13 @@ EasyMDE.prototype.clearAutosavedValue = function () { * @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 one parameter: + * @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) { + var self = this; + onError = onError || self.options.errorCallback; + function fillErrorMessage(errorMessage) { var units = self.options.imageTexts.sizeUnits.split(','); return errorMessage @@ -1931,7 +1932,6 @@ 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) { From 17f5d064a22fdb9802cdfe6c907e3e68aad888a5 Mon Sep 17 00:00:00 2001 From: Jeroen Akkerman Date: Fri, 8 Mar 2019 15:11:17 +0100 Subject: [PATCH 15/51] Added links to users, issues and PRs to changelog --- CHANGELOG.md | 57 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a79b5dc..0c0a5aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,17 +6,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added -- Contributing guide (Thanks to @roipoussiere, #54). +- Contributing guide (Thanks to [@roipoussiere], [#54]). - Issue templates. - Standardized changelog file. ### Changed -- Finish rewrite of README (Thanks to @roipoussiere, #54). +- Finish rewrite of README (Thanks to [@roipoussiere], [#54]). - Image and link prompt fill with "https://" by default. - Link to markdown guide to https://www.markdownguide.org/basic-syntax/. ### Fixed -- Backwards compatibility in the API with SimpleMDE 1.0.0 (#41). +- Backwards compatibility in the API with SimpleMDE 1.0.0 ([#41]). - Automatic publish of master branch to `@next` ### Removed @@ -24,12 +24,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [2.5.1] - 2019-01-17 ### Fixed -- `role="button"` needed to be `type="button"`, fixes #45. +- `role="button"` needed to be `type="button"` ([#45]). ## [2.5.0] - 2019-01-17 ### Added -- Typescript support (Thanks to @FranklinWhale, #44). -- `role="button"` to toolbar buttons (#38). +- Typescript support (Thanks to [@FranklinWhale], [#44]). +- `role="button"` to toolbar buttons ([#38]). ### Fixed - Eraser icon not working with FontAwesome 5. @@ -40,19 +40,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Header button icons not showing sub-icons with FontAwesome 5. -- Inconsistent autosave behaviour when submitting a form (Thanks to @Furgas and @adamb70, #31). +- Inconsistent autosave behaviour when submitting a form (Thanks to [@Furgas] and [@adamb70], [#31]). ## [2.4.1] - 2018-10-15 ### Added -- `fa-redo` class to redo button for FA5 compatibility (Thanks to @Summon528, #27). +- `fa-redo` class to redo button for FA5 compatibility (Thanks to [@Summon528], [#27]). ## [2.4.0] - 2018-10-15 ### Added -- Theming support (Thanks to @LeviticusMB, #17). -- onToggleFullscreen event hook (Thanks to @n-3-0, #16). +- Theming support (Thanks to [@LeviticusMB], [#17]). +- onToggleFullscreen event hook (Thanks to [@n-3-0], [#16]). ### Fixed -- Fullscreen not working with `toolbar: false` (Thanks to @aphitiel, #19). +- Fullscreen not working with `toolbar: false` (Thanks to [@aphitiel], [#19]). ## [2.2.2] - 2019-07-03 ### Fixed @@ -64,8 +64,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Links in the preview window will open in a new tab by default. ### Fixed -- Multi-text select issue by disabling multi-select in the editor (#10). -- `main` file in package.json (Thanks to @sne11ius, #11). +- Multi-text select issue by disabling multi-select in the editor ([#10]). +- `main` file in package.json (Thanks to [@sne11ius], [#11]). ## [2.0.1] - 2018-05-13 ### Changed @@ -73,7 +73,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Updated gulp to version 4.0.0. ### Fixed -- Icons for `heading-smaller`, `heading-bigger`, `heading-1`, `heading-2` and `heading-3` not showing (#9). +- Icons for `heading-smaller`, `heading-bigger`, `heading-1`, `heading-2` and `heading-3` not showing ([#9]). ## [2.0.0] - 2018-04-23 Project forked from [SimpleMDE](https://github.com/sparksuite/simplemde-markdown-editor) @@ -94,6 +94,35 @@ Project forked from [SimpleMDE](https://github.com/sparksuite/simplemde-markdown ### Fixed - Cursor not always showing in "text" mode over the edit field + +[#45]: https://github.com/Ionaru/easy-markdown-editor/issues/45 +[#44]: https://github.com/Ionaru/easy-markdown-editor/issues/44 +[#41]: https://github.com/Ionaru/easy-markdown-editor/issues/41 +[#38]: https://github.com/Ionaru/easy-markdown-editor/issues/38 +[#17]: https://github.com/Ionaru/easy-markdown-editor/issues/17 +[#16]: https://github.com/Ionaru/easy-markdown-editor/issues/16 +[#11]: https://github.com/Ionaru/easy-markdown-editor/issues/11 +[#10]: https://github.com/Ionaru/easy-markdown-editor/issues/10 +[#9]: https://github.com/Ionaru/easy-markdown-editor/issues/9 + + +[#54]: https://github.com/Ionaru/easy-markdown-editor/pull/54 +[#31]: https://github.com/Ionaru/easy-markdown-editor/pull/31 +[#27]: https://github.com/Ionaru/easy-markdown-editor/pull/27 +[#19]: https://github.com/Ionaru/easy-markdown-editor/pull/19 + + +[@roipoussiere]: https://github.com/roipoussiere +[@FranklinWhale]: https://github.com/FranklinWhale +[@Furgas]: https://github.com/Furgas +[@adamb70]: https://github.com/adamb70 +[@Summon528]: https://github.com/Summon528 +[@LeviticusMB]: https://github.com/LeviticusMB +[@n-3-0]: https://github.com/n-3-0 +[@aphitiel]: https://github.com/aphitiel +[@sne11ius]: https://github.com/sne11ius + + [Unreleased]: https://github.com/Ionaru/easy-markdown-editor/compare/2.5.1...HEAD [2.5.1]: https://github.com/Ionaru/easy-markdown-editor/compare/2.5.0...2.5.1 [2.5.0]: https://github.com/Ionaru/easy-markdown-editor/compare/2.4.2...2.5.0 From 50fb9a9a3f3578e6a9e35256051e8a694b240111 Mon Sep 17 00:00:00 2001 From: Jeroen Akkerman Date: Fri, 8 Mar 2019 18:08:25 +0100 Subject: [PATCH 16/51] Version 2.2.1 wasn't yanked --- CHANGELOG.md | 2 +- test/test.html | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 test/test.html diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c0a5aa..dd6c508 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,7 +58,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Automatic publish only publishing tags. -## [2.2.1] - 2019-06-29 [YANKED] +## [2.2.1] - 2019-06-29 ### Changed - Attempt automatic publish `@next` version on npm. - Links in the preview window will open in a new tab by default. diff --git a/test/test.html b/test/test.html new file mode 100644 index 0000000..781aa00 --- /dev/null +++ b/test/test.html @@ -0,0 +1,29 @@ + + + + + EASYMDE TEST + + + + + + + + + + From fb1ce409bb853280e90192332459c51eae7d84df Mon Sep 17 00:00:00 2001 From: Jeroen Akkerman Date: Fri, 8 Mar 2019 18:10:46 +0100 Subject: [PATCH 17/51] Did not mean to commit that test.html file --- test/test.html | 29 ----------------------------- 1 file changed, 29 deletions(-) delete mode 100644 test/test.html diff --git a/test/test.html b/test/test.html deleted file mode 100644 index 781aa00..0000000 --- a/test/test.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - - EASYMDE TEST - - - - - - - - - - From 4ac86cc49d494ba2a57c63d9703821e086dcec6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathana=C3=ABl=20Jourdane?= Date: Tue, 12 Mar 2019 15:59:40 +0100 Subject: [PATCH 18/51] [wip upload-image] use more generic error codes, so the server could be used to upload other files than images --- README.md | 4 +++- src/js/easymde.js | 14 +++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index bd70fcd..4c5b51e 100644 --- a/README.md +++ b/README.md @@ -151,7 +151,9 @@ easyMDE.value('New input for **EasyMDE**'); - **uploadImage**: If set to `true`, enables the image upload functionality, which can be triggered by drag&drop, copy-paste and through the browse-file window (opened when the user click on the *upload-image* icon). Defaults to `false`. - **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 return a 200-OK HTTP response containing: `{"data": {"filePath": ""}}` where *imageFilePath* is the relative path of the image, otherwise, return `{"error": ""}`, where *errorCode* can be `noFileGiven`, `imageTypeNotAllowed`, `imageTooLarge` or `imageImportError` (see *errorMessages* below). No default value. +- **imageUploadEndpoint**: The endpoint where the images data will be sent, via an asynchronous *POST* request. The server is supposed to save this image, and return a json response. + - if the request was successfully processed (HTTP 200-OK): `{"data": {"filePath": ""}}` where *filePath* is the relative path of the image; + - otherwise: `{"error": ""}`, where *errorCode* can be `noFileGiven` (HTTP 400), `typeNotAllowed` (HTTP 415), `fileTooLarge` (HTTP 413) or `importError` (see *errorMessages* below). No default value. - **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.`. diff --git a/src/js/easymde.js b/src/js/easymde.js index c151668..b854152 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -1431,10 +1431,10 @@ var imageTexts = { */ 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' + + typeNotAllowed: 'This image type is not allowed.', + fileTooLarge: '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#.', + importError: 'Something went wrong when uploading the image #image_name#.', }; /** @@ -1924,7 +1924,7 @@ EasyMDE.prototype.uploadImage = function(file, onSuccess, onError) { } if (file.size > this.options.imageMaxSize) { - onError(fillErrorMessage(this.options.errorMessages.imageTooLarge)); + onError(fillErrorMessage(this.options.errorMessages.fileTooLarge)); } var formData = new FormData(); @@ -1946,7 +1946,7 @@ EasyMDE.prototype.uploadImage = function(file, onSuccess, onError) { 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)); + onError(fillErrorMessage(self.options.errorMessages.importError)); return; } if(this.status === 200 && response && !response.error && response.data && response.data.filePath) { @@ -1957,7 +1957,7 @@ EasyMDE.prototype.uploadImage = function(file, onSuccess, onError) { } else { console.log('EasyMDE: Received an unexpected response after uploading the image.' + this.status + ' (' + this.statusText + ')'); - onError(fillErrorMessage(self.options.errorMessages.imageImportError)); + onError(fillErrorMessage(self.options.errorMessages.importError)); } } }; @@ -1965,7 +1965,7 @@ EasyMDE.prototype.uploadImage = function(file, onSuccess, onError) { 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); + onError(self.options.errorMessages.importError); }; }; From 6e35026a756eb6ae6e44290b0e901c97957681c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathana=C3=ABl=20Jourdane?= Date: Tue, 12 Mar 2019 16:02:01 +0100 Subject: [PATCH 19/51] [wip upload-image] bugfix error message displayed twice --- src/js/easymde.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/js/easymde.js b/src/js/easymde.js index b854152..ee5ad80 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -1925,6 +1925,7 @@ EasyMDE.prototype.uploadImage = function(file, onSuccess, onError) { if (file.size > this.options.imageMaxSize) { onError(fillErrorMessage(this.options.errorMessages.fileTooLarge)); + return; } var formData = new FormData(); From 4ae7fc8bc9a370c57834ef71534e7a13e28aa2b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathana=C3=ABl=20Jourdane?= Date: Wed, 13 Mar 2019 18:48:36 +0100 Subject: [PATCH 20/51] Allow openBrowseFileWindow() external call with custom callback --- src/js/easymde.js | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/src/js/easymde.js b/src/js/easymde.js index ee5ad80..3ff39a0 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -708,9 +708,8 @@ function drawImage(editor) { * @param editor {EasyMDE} The EasyMDE object */ function drawUploadedImage(editor) { - // TODO: Draw the image template with a fake url, ie: '![](importing foo.png...)' - var imageInput = editor.gui.toolbar.getElementsByClassName('imageInput')[0]; - imageInput.dispatchEvent(new MouseEvent('click')); + // TODO: Draw the image template with a fake url? ie: '![](importing foo.png...)' + editor.openBrowseFileWindow(); } /** @@ -1612,20 +1611,17 @@ function EasyMDE(options) { * - drag&drop; * - copy-paste; * - the browse-file window (opened when the user clicks on the *upload-image* icon). - * @param {FileList} files The files to upload the the server. + * @param [onSuccess] {function} see EasyMDE.prototype.uploadImage + * @param [onError] {function} see EasyMDE.prototype.uploadImage */ -EasyMDE.prototype.uploadImages = function(files) { +EasyMDE.prototype.uploadImages = function(files, onSuccess, onError) { var names = []; - var self = this; for(var i=0; i Date: Thu, 11 Jul 2019 02:31:16 +0000 Subject: [PATCH 21/51] Bump lodash.template from 4.4.0 to 4.5.0 Bumps [lodash.template](https://github.com/lodash/lodash) from 4.4.0 to 4.5.0. - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](https://github.com/lodash/lodash/compare/4.4.0...4.5.0) Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4bd6897..84d4373 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3484,12 +3484,12 @@ "dev": true }, "lodash.template": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.4.0.tgz", - "integrity": "sha1-5zoDhcg1VZF0bgILmWecaQ5o+6A=", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", + "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", "dev": true, "requires": { - "lodash._reinterpolate": "~3.0.0", + "lodash._reinterpolate": "^3.0.0", "lodash.templatesettings": "^4.0.0" } }, From 073bfbcea57d93a744d29c456ed052674bbb2350 Mon Sep 17 00:00:00 2001 From: Jeroen Akkerman Date: Thu, 11 Jul 2019 10:18:48 +0200 Subject: [PATCH 22/51] Updated dependencies and made code comply with new eslint rules --- CHANGELOG.md | 6 +- package-lock.json | 280 ++++++++++++++++++++++------------------------ package.json | 12 +- src/js/easymde.js | 7 +- 4 files changed, 150 insertions(+), 155 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f008117..62d4069 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,11 @@ All notable changes to easymde will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - +## [Unreleased] +### Fixed +- Updated dependencies to resolve potential security issue. +- Resolved small code style issues shown by new eslint rules. + ## [2.6.1] - 2019-06-17 ### Fixed - Error when toggling between ordered and unordered lists (Thanks to [@roryok], [#93]). diff --git a/package-lock.json b/package-lock.json index 84d4373..5175dd5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,9 +14,9 @@ } }, "@babel/highlight": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", - "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", + "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", "dev": true, "requires": { "chalk": "^2.0.0", @@ -25,9 +25,9 @@ } }, "@types/codemirror": { - "version": "0.0.74", - "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-0.0.74.tgz", - "integrity": "sha512-pjc14HE6KCCk3SYoC49k/gJJHkredJy4GdSK+lGRMIBfG+Uq6vT8oZiKToFH2J7pZ5pUd69UGD6CgmFG1V17wA==", + "version": "0.0.76", + "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-0.0.76.tgz", + "integrity": "sha512-k/hpUb+Ebyn9z63qM8IbsRiW0eYHZ+pi/1e2reGzBKAZJzkjWmNTXXqLLiNv5d9ekyxkajxRBr5Hu2WZq/nokw==", "dev": true, "requires": { "@types/tern": "*" @@ -59,9 +59,9 @@ } }, "acorn": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz", - "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.2.0.tgz", + "integrity": "sha512-8oe72N3WPMjA+2zVG71Ia0nXZ8DpQH+QyyHO+p06jT8eg8FGG3FbcUIi8KziHlAfheJQZeoqbvq1mQSQHXKYLw==", "dev": true }, "acorn-dynamic-import": { @@ -77,27 +77,27 @@ "dev": true }, "acorn-node": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.6.2.tgz", - "integrity": "sha512-rIhNEZuNI8ibQcL7ANm/mGyPukIaZsRNX9psFNQURyJW0nu6k8wjSDld20z6v2mDBWqX13pIEnk9gGZJHIlEXg==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.7.0.tgz", + "integrity": "sha512-XhahLSsCB6X6CJbe+uNu3Mn9sJBNFxtBN9NLgAOQovfS6Kh0lDUtmlclhjn9CvEK7A7YyRU13PXlNcpSiLI9Yw==", "dev": true, "requires": { - "acorn": "^6.0.2", + "acorn": "^6.1.1", "acorn-dynamic-import": "^4.0.0", - "acorn-walk": "^6.1.0", + "acorn-walk": "^6.1.1", "xtend": "^4.0.1" } }, "acorn-walk": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz", - "integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", + "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==", "dev": true }, "ajv": { - "version": "6.9.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.9.2.tgz", - "integrity": "sha512-4UFy0/LgDo7Oa/+wOAlj44tp9K78u38E5/359eSrqEp1Z5PdVfimCcs7SluXMP755RUQu6d2b4AvF0R1C9RZjg==", + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.1.tgz", + "integrity": "sha512-w1YQaVGNC6t2UCPjEawK/vo/dG8OOrVtUmhBT1uJJYxbl5kU2Tj3v6LGqBcsysN1yhuCStJCCA3GqdvKY8sqXQ==", "dev": true, "requires": { "fast-deep-equal": "^2.0.1", @@ -323,11 +323,12 @@ } }, "assert": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", - "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", "dev": true, "requires": { + "object-assign": "^4.1.1", "util": "0.10.3" }, "dependencies": { @@ -584,9 +585,9 @@ } }, "browserify": { - "version": "16.2.3", - "resolved": "https://registry.npmjs.org/browserify/-/browserify-16.2.3.tgz", - "integrity": "sha512-zQt/Gd1+W+IY+h/xX2NYMW4orQWhqSwyV+xsblycTtpOuB27h1fZhhNQuipJ4t79ohw4P4mMem0jp/ZkISQtjQ==", + "version": "16.3.0", + "resolved": "https://registry.npmjs.org/browserify/-/browserify-16.3.0.tgz", + "integrity": "sha512-BWaaD7alyGZVEBBwSTYx4iJF5DswIGzK17o8ai9w4iKRbYpk3EOiprRHMRRA8DCZFmFeOdx7A385w2XdFvxWmg==", "dev": true, "requires": { "JSONStream": "^1.0.3", @@ -768,9 +769,9 @@ "dev": true }, "callsites": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.0.0.tgz", - "integrity": "sha512-tWnkwu9YEq2uzlBDI4RcLn8jrFvF9AOi8PxDNU3hZZjJcjkcRAq3vCI+vZcg1SuxISDYe86k9VZFwAxDiJGoAw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true }, "camelcase": { @@ -936,9 +937,9 @@ "dev": true }, "codemirror": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.47.0.tgz", - "integrity": "sha512-kV49Fr+NGFHFc/Imsx6g180hSlkGhuHxTSDDmDHOuyln0MQYFLixDY4+bFkBVeCEiepYfDimAF/e++9jPJk4QA==" + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.48.0.tgz", + "integrity": "sha512-3Ter+tYtRlTNtxtYdYNPxGxBL/b3cMcvPdPm70gvmcOO2Rauv/fUEewWa0tT596Hosv6ea2mtpx28OXBy1mQCg==" }, "codemirror-spell-checker": { "version": "1.1.2", @@ -1385,9 +1386,9 @@ } }, "elliptic": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz", - "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.0.tgz", + "integrity": "sha512-eFOJTMyCYb7xtE/caJ6JJu+bhi67WCYNbkGSknu20pmM8Ke/bqOfdnZWxyoGN26JgfxTbXrsCkEw4KheCT/KGg==", "dev": true, "requires": { "bn.js": "^4.4.0", @@ -1474,32 +1475,33 @@ "dev": true }, "eslint": { - "version": "5.14.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.14.1.tgz", - "integrity": "sha512-CyUMbmsjxedx8B0mr79mNOqetvkbij/zrXnFeK2zc3pGRn3/tibjiNAv/3UxFEyfMDjh+ZqTrJrEGBFiGfD5Og==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.0.1.tgz", + "integrity": "sha512-DyQRaMmORQ+JsWShYsSg4OPTjY56u1nCjAmICrE8vLWqyLKxhFXOthwMj1SA8xwfrv0CofLNVnqbfyhwCkaO0w==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "ajv": "^6.9.1", + "ajv": "^6.10.0", "chalk": "^2.1.0", "cross-spawn": "^6.0.5", "debug": "^4.0.1", "doctrine": "^3.0.0", - "eslint-scope": "^4.0.0", + "eslint-scope": "^4.0.3", "eslint-utils": "^1.3.1", "eslint-visitor-keys": "^1.0.0", - "espree": "^5.0.1", + "espree": "^6.0.0", "esquery": "^1.0.1", "esutils": "^2.0.2", "file-entry-cache": "^5.0.1", "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", + "glob-parent": "^3.1.0", "globals": "^11.7.0", "ignore": "^4.0.6", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "inquirer": "^6.2.2", - "js-yaml": "^3.12.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.3.0", "lodash": "^4.17.11", @@ -1507,7 +1509,6 @@ "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", "progress": "^2.0.0", "regexpp": "^2.0.1", "semver": "^5.5.1", @@ -1533,9 +1534,9 @@ } }, "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, "strip-ansi": { @@ -1550,9 +1551,9 @@ } }, "eslint-scope": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz", - "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", "dev": true, "requires": { "esrecurse": "^4.1.0", @@ -1572,9 +1573,9 @@ "dev": true }, "espree": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", - "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.0.0.tgz", + "integrity": "sha512-lJvCS6YbCn3ImT3yKkPe0+tJ+mH6ljhGNjHQH9mRtiO6gjhVAOhVXW1yjnwqGwTkK3bGbye+hb00nFNmu0l/1Q==", "dev": true, "requires": { "acorn": "^6.0.7", @@ -1706,9 +1707,9 @@ } }, "external-editor": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz", - "integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", "dev": true, "requires": { "chardet": "^0.7.0", @@ -1905,9 +1906,9 @@ } }, "flatted": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz", - "integrity": "sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", + "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", "dev": true }, "flush-write-stream": { @@ -2630,9 +2631,9 @@ } }, "globals": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", - "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==", + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, "glogg": { @@ -2725,12 +2726,12 @@ } }, "gulp-eslint": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/gulp-eslint/-/gulp-eslint-5.0.0.tgz", - "integrity": "sha512-9GUqCqh85C7rP9120cpxXuZz2ayq3BZc85pCTuPJS03VQYxne0aWPIXWx6LSvsGPa3uRqtSO537vaugOh+5cXg==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gulp-eslint/-/gulp-eslint-6.0.0.tgz", + "integrity": "sha512-dCVPSh1sA+UVhn7JSQt7KEb4An2sQNbOdB3PA8UCfxsoPlAKjJHxYHGXdXC7eb+V1FAnilSFFqslPrq037l1ig==", "dev": true, "requires": { - "eslint": "^5.0.1", + "eslint": "^6.0.0", "fancy-log": "^1.3.2", "plugin-error": "^1.0.1" } @@ -2933,9 +2934,9 @@ } }, "ieee754": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz", - "integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", "dev": true }, "ignore": { @@ -2945,9 +2946,9 @@ "dev": true }, "import-fresh": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.0.0.tgz", - "integrity": "sha512-pOnA9tfM3Uwics+SaBLCNyZZZbK+4PTu0OPZtLlMIrv17EdBoC15S9Kn8ckJ9TZTyKb3ywNE5y1yeDxxGA7nTQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", + "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", "dev": true, "requires": { "parent-module": "^1.0.0", @@ -2992,9 +2993,9 @@ } }, "inquirer": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.2.tgz", - "integrity": "sha512-Z2rREiXA6cHRR9KBOarR3WuLlFzlIfAEIiB45ll5SSadMg7WqOh1MKEjjndfuH5ewXdixWCxqnVfGOQzPeiztA==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.0.tgz", + "integrity": "sha512-scfHejeG/lVZSpvCXpsB4j/wQNPM5JC8kiElOI0OUTwmc1RTpXr4H32/HOlQHcZiYl2z2VElwuCVDRG8vFmbnA==", "dev": true, "requires": { "ansi-escapes": "^3.2.0", @@ -3003,12 +3004,12 @@ "cli-width": "^2.0.0", "external-editor": "^3.0.3", "figures": "^2.0.0", - "lodash": "^4.17.11", + "lodash": "^4.17.12", "mute-stream": "0.0.7", "run-async": "^2.2.0", "rxjs": "^6.4.0", "string-width": "^2.1.0", - "strip-ansi": "^5.0.0", + "strip-ansi": "^5.1.0", "through": "^2.3.6" }, "dependencies": { @@ -3046,18 +3047,18 @@ } }, "strip-ansi": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.0.0.tgz", - "integrity": "sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { - "ansi-regex": "^4.0.0" + "ansi-regex": "^4.1.0" }, "dependencies": { "ansi-regex": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.0.0.tgz", - "integrity": "sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true } } @@ -3371,22 +3372,13 @@ "dev": true }, "labeled-stream-splicer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.1.tgz", - "integrity": "sha512-MC94mHZRvJ3LfykJlTUipBqenZz1pacOZEMhhQ8dMGcDHs0SBE5GbsavUXV7YtP3icBW17W0Zy1I0lfASmo9Pg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.2.tgz", + "integrity": "sha512-Ca4LSXFFZUjPScRaqOcFxneA0VpKZr4MMYCljyQr4LIewTLb3Y0IUTIsnBBsVubIeEfxeSZpSjSsRM8APEQaAw==", "dev": true, "requires": { "inherits": "^2.0.1", - "isarray": "^2.0.4", "stream-splicer": "^2.0.0" - }, - "dependencies": { - "isarray": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.4.tgz", - "integrity": "sha512-GMxXOiUirWg1xTKRipM0Ek07rX+ubx4nNVElTJdNLYmNO/2YrDkgJGw9CljXn+r4EWiDQg/8lsRdHyg2PJuUaA==", - "dev": true - } } }, "last-run": { @@ -3466,9 +3458,9 @@ } }, "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", + "version": "4.17.14", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz", + "integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==", "dev": true }, "lodash._reinterpolate": { @@ -3548,9 +3540,9 @@ } }, "marked": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/marked/-/marked-0.6.2.tgz", - "integrity": "sha512-LqxwVH3P/rqKX4EKGz7+c2G9r98WeM/SW34ybhgNGhUQNKtf1GmmSkJ6cDGJ/t6tiyae49qRkpyTw2B9HOrgUA==" + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.7.0.tgz", + "integrity": "sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg==" }, "matchdep": { "version": "2.0.0", @@ -3701,14 +3693,14 @@ } }, "module-deps": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.2.0.tgz", - "integrity": "sha512-hKPmO06so6bL/ZvqVNVqdTVO8UAYsi3tQWlCa+z9KuWhoN4KDQtb5hcqQQv58qYiDE21wIvnttZEPiDgEbpwbA==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.2.1.tgz", + "integrity": "sha512-UnEn6Ah36Tu4jFiBbJVUtt0h+iXqxpLqDvPS8nllbw5RZFmNJ1+Mz5BjYnM9ieH80zyxHkARGLnMIHlPK5bu6A==", "dev": true, "requires": { "JSONStream": "^1.0.3", "browser-resolve": "^1.7.0", - "cached-path-relative": "^1.0.0", + "cached-path-relative": "^1.0.2", "concat-stream": "~1.6.0", "defined": "^1.0.0", "detective": "^5.0.2", @@ -3821,6 +3813,12 @@ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, "object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", @@ -3983,15 +3981,15 @@ "dev": true }, "pako": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.8.tgz", - "integrity": "sha512-6i0HVbUfcKaTv+EG8ZTr75az7GFXcLYk9UyLEg7Notv/Ma+z/UG3TCoz6GiNeOrn1E/e63I0X/Hpw18jHOTUnA==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", + "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==", "dev": true }, "parent-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.0.tgz", - "integrity": "sha512-8Mf5juOMmiE4FcmzYc4IaiS9L3+9paz2KOiXzkRviCP6aDmN49Hz6EMWz0lGNp9pX80GvvAuLADtyGfW/Em3TA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, "requires": { "callsites": "^3.0.0" @@ -4085,12 +4083,6 @@ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true - }, "path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", @@ -4534,9 +4526,9 @@ } }, "rxjs": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", - "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz", + "integrity": "sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==", "dev": true, "requires": { "tslib": "^1.9.0" @@ -4961,9 +4953,9 @@ "dev": true }, "stream-splicer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.0.tgz", - "integrity": "sha1-G2O+Q4oTPktnHMGTUZdgAXWRDYM=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.1.tgz", + "integrity": "sha512-Xizh4/NPuYSyAXyT7g8IvdJ9HJpxIGL9PjyhtywCZvvP0OPIdqyrr4dMikeuvY8xahpdKEBlBTySe583totajg==", "dev": true, "requires": { "inherits": "^2.0.1", @@ -5052,9 +5044,9 @@ } }, "table": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/table/-/table-5.2.3.tgz", - "integrity": "sha512-N2RsDAMvDLvYwFcwbPyF3VmVSSkuF+G1e+8inhBLtHpvwXGw4QRPEZhihQNeEN0i1up6/f6ObCJXNdlRG3YVyQ==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.1.tgz", + "integrity": "sha512-E6CK1/pZe2N75rGZQotFOdmzWQ1AILtgYbMAbAjvms0S1l5IDB47zG3nCnFGB/w+7nB3vKofbLXCH7HPBo864w==", "dev": true, "requires": { "ajv": "^6.9.1", @@ -5064,9 +5056,9 @@ }, "dependencies": { "ansi-regex": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.0.0.tgz", - "integrity": "sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, "is-fullwidth-code-point": { @@ -5076,23 +5068,23 @@ "dev": true }, "string-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.0.0.tgz", - "integrity": "sha512-rr8CUxBbvOZDUvc5lNIJ+OC1nPVpz+Siw9VBtUjB9b6jZehZLFt0JMCZzShFHIsI8cbhm0EsNIfWJMFV3cu3Ew==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.0.0" + "strip-ansi": "^5.1.0" } }, "strip-ansi": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.0.0.tgz", - "integrity": "sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { - "ansi-regex": "^4.0.0" + "ansi-regex": "^4.1.0" } } } @@ -5240,9 +5232,9 @@ } }, "tslib": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", - "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", "dev": true }, "tty-browserify": { @@ -5267,9 +5259,9 @@ "dev": true }, "typescript": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.1.tgz", - "integrity": "sha512-64HkdiRv1yYZsSe4xC1WVgamNigVYjlssIoaH2HcZF0+ijsk5YK2g0G34w9wJkze8+5ow4STd22AynfO6ZYYLw==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz", + "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==", "dev": true }, "typo-js": { diff --git a/package.json b/package.json index a2f05ec..6ca6355 100644 --- a/package.json +++ b/package.json @@ -19,22 +19,22 @@ "license": "MIT", "author": "Jeroen Akkerman", "dependencies": { - "codemirror": "^5.47.0", + "codemirror": "^5.48.0", "codemirror-spell-checker": "1.1.2", - "marked": "^0.6.2" + "marked": "^0.7.0" }, "devDependencies": { - "@types/codemirror": "0.0.74", - "browserify": "^16.2.3", + "@types/codemirror": "0.0.76", + "browserify": "^16.3.0", "gulp": "^4.0.2", "gulp-clean-css": "^4.2.0", "gulp-concat": "^2.6.1", - "gulp-eslint": "^5.0.0", + "gulp-eslint": "^6.0.0", "gulp-header": "^2.0.7", "gulp-rename": "^1.4.0", "gulp-terser": "^1.2.0", "gulp-uglify": "^3.0.2", - "typescript": "^3.5.1", + "typescript": "^3.5.3", "vinyl-buffer": "^1.0.0", "vinyl-source-stream": "^2.0.0" }, diff --git a/src/js/easymde.js b/src/js/easymde.js index 445fbd3..1ed5083 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -1,4 +1,3 @@ -/*global require,module*/ 'use strict'; var CodeMirror = require('codemirror'); require('codemirror/addon/edit/continuelist.js'); @@ -1131,7 +1130,7 @@ function _cleanBlock(cm) { // Merge the properties of one object into another. function _mergeProperties(target, source) { for (var property in source) { - if (source.hasOwnProperty(property)) { + if (Object.prototype.hasOwnProperty.call(source, property)) { if (source[property] instanceof Array) { target[property] = source[property].concat(target[property] instanceof Array ? target[property] : []); } else if ( @@ -1429,7 +1428,7 @@ function EasyMDE(options) { // Loop over the built in buttons, to get the preferred order for (var key in toolbarBuiltInButtons) { - if (toolbarBuiltInButtons.hasOwnProperty(key)) { + if (Object.prototype.hasOwnProperty.call(toolbarBuiltInButtons, key)) { if (key.indexOf('separator-') != -1) { options.toolbar.push('|'); } @@ -1443,7 +1442,7 @@ function EasyMDE(options) { // Handle status bar - if (!options.hasOwnProperty('status')) { + if (!Object.prototype.hasOwnProperty.call(options, 'status')) { options.status = ['autosave', 'lines', 'words', 'cursor']; } From 5ffeba5a3cb8134b2b8ec10e84d2d61675cd03a8 Mon Sep 17 00:00:00 2001 From: Jeroen Akkerman Date: Fri, 12 Jul 2019 14:00:23 +0200 Subject: [PATCH 23/51] Added option to override the preview screen styling --- README.md | 5 +++++ src/css/easymde.css | 21 +++++++++------------ src/js/easymde.js | 35 +++++++++++++++++++++++++++++++++-- 3 files changed, 47 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index c3446f7..2b2ab92 100644 --- a/README.md +++ b/README.md @@ -143,6 +143,7 @@ easyMDE.value('New input for **EasyMDE**'); - **strikethrough**: If set to `false`, will not process GFM strikethrough syntax. Defaults to `true`. - **underscoresBreakWords**: If set to `true`, let underscores be a delimiter for separating words. Defaults to `false`. - **placeholder**: If set, displays a custom placeholder message. +- **previewClass**: A string or array of strings that will be applied to the preview screen when activated. Defaults to `"editor-preview"`. - **previewRender**: Custom function for parsing the plaintext Markdown and returning HTML. Used when user previews. - **promptURLs**: If set to `true`, a JS alert window appears asking for the link or image URL. Defaults to `false`. - **promptTexts**: Customize the text used to prompt for URLs. @@ -201,6 +202,10 @@ var editor = new EasyMDE({ underscoresBreakWords: true, }, placeholder: "Type here...", + + previewClass: "my-custom-styling", + previewClass: ["my-custom-styling", "more-custom-styling"], + previewRender: function(plainText) { return customMarkdownParser(plainText); // Returns HTML from a custom parser }, diff --git a/src/css/easymde.css b/src/css/easymde.css index 3843bdc..a027a14 100644 --- a/src/css/easymde.css +++ b/src/css/easymde.css @@ -213,14 +213,12 @@ content: 'characters: ' } -.editor-preview { - padding: 10px; +.editor-preview-full { position: absolute; width: 100%; height: 100%; top: 0; left: 0; - background: #fafafa; z-index: 7; overflow: auto; display: none; @@ -228,13 +226,11 @@ } .editor-preview-side { - padding: 10px; position: fixed; bottom: 0; width: 50%; top: 50px; right: 0; - background: #fafafa; z-index: 9; overflow: auto; display: none; @@ -251,21 +247,22 @@ display: block } -.editor-preview > p, -.editor-preview-side > p { +.editor-preview { + padding: 10px; + background: #fafafa; +} + +.editor-preview > p { margin-top: 0 } -.editor-preview pre, -.editor-preview-side pre { +.editor-preview pre { background: #eee; margin-bottom: 10px; } .editor-preview table td, -.editor-preview table th, -.editor-preview-side table td, -.editor-preview-side table th { +.editor-preview table th { border: 1px solid #ddd; padding: 5px; } diff --git a/src/js/easymde.js b/src/js/easymde.js index 1ed5083..0d8aa5c 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -818,9 +818,23 @@ function togglePreview(editor) { var toolbar_div = wrapper.previousSibling; var toolbar = editor.options.toolbar ? editor.toolbarElements.preview : false; var preview = wrapper.lastChild; - if (!preview || !/editor-preview/.test(preview.className)) { + if (!preview || !/editor-preview-full/.test(preview.className)) { + preview = document.createElement('div'); - preview.className = 'editor-preview'; + preview.className = 'editor-preview-full'; + + if (editor.options.previewClass) { + + if (Array.isArray(editor.options.previewClass)) { + for (var i = 0; i < editor.options.previewClass.length; i++) { + preview.className += (' ' + editor.options.previewClass[i]); + } + + } else if (typeof editor.options.previewClass === 'string') { + preview.className += (' ' + editor.options.previewClass); + } + } + wrapper.appendChild(preview); } if (/editor-preview-active/.test(preview.className)) { @@ -1440,6 +1454,10 @@ function EasyMDE(options) { } } + // Editor preview styling class. + if (!Object.prototype.hasOwnProperty.call(options, 'previewClass')) { + options.previewClass = 'editor-preview'; + } // Handle status bar if (!Object.prototype.hasOwnProperty.call(options, 'status')) { @@ -1772,6 +1790,19 @@ EasyMDE.prototype.createSideBySide = function () { if (!preview || !/editor-preview-side/.test(preview.className)) { preview = document.createElement('div'); preview.className = 'editor-preview-side'; + + if (this.options.previewClass) { + + if (Array.isArray(this.options.previewClass)) { + for (var i = 0; i < this.options.previewClass.length; i++) { + preview.className += (' ' + this.options.previewClass[i]); + } + + } else if (typeof this.options.previewClass === 'string') { + preview.className += (' ' + this.options.previewClass); + } + } + wrapper.parentNode.insertBefore(preview, wrapper.nextSibling); } From 71170a7eef2576dd45ca27f22ad3158c3cd0c815 Mon Sep 17 00:00:00 2001 From: Jeroen Akkerman Date: Fri, 12 Jul 2019 14:10:56 +0200 Subject: [PATCH 24/51] Updated changelog for previewClass feature, closes #99 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 62d4069..03e9a46 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- `previewClass` option for overwriting the preview screen class ([#99]). + ### Fixed - Updated dependencies to resolve potential security issue. - Resolved small code style issues shown by new eslint rules. @@ -105,6 +108,7 @@ Project forked from [SimpleMDE](https://github.com/sparksuite/simplemde-markdown - Cursor not always showing in "text" mode over the edit field +[#99]: https://github.com/Ionaru/easy-markdown-editor/issues/99 [#45]: https://github.com/Ionaru/easy-markdown-editor/issues/45 [#44]: https://github.com/Ionaru/easy-markdown-editor/issues/44 [#41]: https://github.com/Ionaru/easy-markdown-editor/issues/41 @@ -124,6 +128,7 @@ Project forked from [SimpleMDE](https://github.com/sparksuite/simplemde-markdown [#19]: https://github.com/Ionaru/easy-markdown-editor/pull/19 +[@sn3p]: https://github.com/sn3p [@roryok]: https://github.com/roryok [@ysykzheng]: https://github.com/ysykzheng [@roipoussiere]: https://github.com/roipoussiere From 7cfeb37257b73352bb8e1dcc6caf770dbd50a6cd Mon Sep 17 00:00:00 2001 From: Jeroen Akkerman Date: Fri, 12 Jul 2019 14:36:59 +0200 Subject: [PATCH 25/51] Added typings for new option --- types/easymde-test.ts | 31 +++++++++++++++++++++++++++++++ types/easymde.d.ts | 1 + 2 files changed, 32 insertions(+) diff --git a/types/easymde-test.ts b/types/easymde-test.ts index 2d5f5b7..f240ee9 100644 --- a/types/easymde-test.ts +++ b/types/easymde-test.ts @@ -7,6 +7,7 @@ const editor = new EasyMDE({ drawTable: 'Cmd-Alt-T', toggleFullScreen: null }, + previewClass: 'my-custom-class', spellChecker: false, onToggleFullScreen: (full: boolean) => { console.log('FullscreenToggled', full); @@ -28,3 +29,33 @@ editor.codemirror.setOption('readOnly', true); EasyMDE.toggleItalic = (editor: EasyMDE) => { console.log('SomeButtonOverride'); }; + +const editor2 = new EasyMDE({ + autoDownloadFontAwesome: undefined, + previewClass: ['my-custom-class', 'some-other-class'], + toolbar: [{ + name: 'bold', + action: EasyMDE.toggleBold, + className: 'fa fa-bolt', + title: 'Bold', + }, '|', { // Separator + name: 'alert', + action: (editor) => { + alert('This is from a custom button action!'); + // Custom functions have access to the `editor` instance. + }, + className: 'fa fa-star', + title: 'A Custom Button', + noDisable: undefined, + noMobile: false, + }, '|', { + name: 'link', + action: 'https://github.com/Ionaru/easy-markdown-editor', + className: 'fa fab fa-github', + title: 'A Custom Link', + noDisable: true, + noMobile: true, + }] +}); + +editor2.clearAutosavedValue(); diff --git a/types/easymde.d.ts b/types/easymde.d.ts index 07e9d4c..d5ce507 100644 --- a/types/easymde.d.ts +++ b/types/easymde.d.ts @@ -100,6 +100,7 @@ declare namespace EasyMDE { lineWrapping?: boolean; parsingConfig?: ParsingOptions; placeholder?: string; + previewClass?: string | ReadonlyArray; previewRender?: (markdownPlaintext: string, previewElement: HTMLElement) => string; promptURLs?: boolean; renderingConfig?: RenderingOptions; From 41e9d9a80688dbf3719d33c009add6bb8bc2f8a4 Mon Sep 17 00:00:00 2001 From: Jeroen Akkerman Date: Sat, 13 Jul 2019 19:16:12 +0200 Subject: [PATCH 26/51] Updated changelog for 2.7.0 --- CHANGELOG.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03e9a46..57a3414 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,8 @@ All notable changes to easymde will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] + +## [2.7.0] - 2019-07-13 ### Added - `previewClass` option for overwriting the preview screen class ([#99]). @@ -142,7 +143,8 @@ Project forked from [SimpleMDE](https://github.com/sparksuite/simplemde-markdown [@sne11ius]: https://github.com/sne11ius -[Unreleased]: https://github.com/Ionaru/easy-markdown-editor/compare/2.6.1...HEAD +[Unreleased]: https://github.com/Ionaru/easy-markdown-editor/compare/2.7.0...HEAD +[2.7.0]: https://github.com/Ionaru/easy-markdown-editor/compare/2.6.1...2.7.0 [2.6.1]: https://github.com/Ionaru/easy-markdown-editor/compare/2.6.0...2.6.1 [2.6.0]: https://github.com/Ionaru/easy-markdown-editor/compare/2.5.1...2.6.0 [2.5.1]: https://github.com/Ionaru/easy-markdown-editor/compare/2.5.0...2.5.1 From 66dcf7d868755f37b345059dea83a4ead0c00534 Mon Sep 17 00:00:00 2001 From: Jeroen Akkerman Date: Sat, 13 Jul 2019 19:20:21 +0200 Subject: [PATCH 27/51] 2.7.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5175dd5..8d774ec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "easymde", - "version": "2.6.1", + "version": "2.7.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 6ca6355..19ec93f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "easymde", - "version": "2.6.1", + "version": "2.7.0", "description": "A simple, beautiful, and embeddable JavaScript Markdown editor that easy to use. Features include autosaving and spell checking.", "files": [ "dist/**/*", From 23cfe89fa0df84c0d1a3011e01513574a430bf52 Mon Sep 17 00:00:00 2001 From: Jeroen Akkerman Date: Sat, 13 Jul 2019 19:14:38 +0200 Subject: [PATCH 28/51] Run typescript tests automatically --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 19ec93f..38429f3 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "repository": "github:Ionaru/easy-markdown-editor", "scripts": { "prepare": "gulp", + "test": "npm run test:types", "test:types": "tsc --project types/tsconfig.json" } } From ff0db2000a261a8c4761299d1520d8b57a776ccc Mon Sep 17 00:00:00 2001 From: Jeroen van Oorschot Date: Mon, 15 Jul 2019 11:37:22 +0200 Subject: [PATCH 29/51] Merge with 2.7.0. --- CHANGELOG.md | 22 +++++++-- gulpfile.js | 4 +- src/js/easymde.js | 104 +++++++++++++++++++++++++++++++----------- types/easymde-test.ts | 31 +++++++++++++ types/easymde.d.ts | 7 +-- 5 files changed, 133 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd6c508..d8ed5ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,26 @@ # EasyMDE Changelog -All notable changes to this project will be documented in this file. +All notable changes to easymde will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] + +Merge 2.7.0 with https://github.com/Ionaru/easy-markdown-editor/pull/71 @jeroenvo + +## [2.7.0] - 2019-07-13 +### Added +- `previewClass` option for overwriting the preview screen class ([#99]). + +### Fixed +- Updated dependencies to resolve potential security issue. +- Resolved small code style issues shown by new eslint rules. + +## [2.6.1] - 2019-06-17 +### Fixed +- Error when toggling between ordered and unordered lists (Thanks to [@roryok], [#93]). +- Keyboard shortcuts for custom actions not working (Thanks to [@ysykzheng], [#75]). + +## [2.6.0] - 2019-04-15 ### Added - Contributing guide (Thanks to [@roipoussiere], [#54]). - Issue templates. @@ -13,7 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Finish rewrite of README (Thanks to [@roipoussiere], [#54]). - Image and link prompt fill with "https://" by default. -- Link to markdown guide to https://www.markdownguide.org/basic-syntax/. +- Link to markdown guide to . ### Fixed - Backwards compatibility in the API with SimpleMDE 1.0.0 ([#41]). diff --git a/gulpfile.js b/gulpfile.js index fdc76f5..99fba6f 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -2,7 +2,7 @@ var gulp = require('gulp'); var cleanCSS = require('gulp-clean-css'); -var uglify = require('gulp-uglify'); +var terser = require('gulp-terser'); var concat = require('gulp-concat'); var header = require('gulp-header'); var buffer = require('vinyl-buffer'); @@ -31,7 +31,7 @@ function scripts() { return browserify({entries: './src/js/easymde.js', standalone: 'EasyMDE'}).bundle() .pipe(source('easymde.min.js')) .pipe(buffer()) - .pipe(uglify()) + .pipe(terser()) .pipe(header(banner, {pkg: pkg})) .pipe(gulp.dest('./dist/')); } diff --git a/src/js/easymde.js b/src/js/easymde.js index 3ff39a0..cb4f50b 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -1,4 +1,3 @@ -/*global require,module*/ 'use strict'; var CodeMirror = require('codemirror'); require('codemirror/addon/edit/continuelist.js'); @@ -122,6 +121,11 @@ function createToolbarButton(options, enableTooltips, shortcuts) { el.setAttribute('type', 'button'); enableTooltips = (enableTooltips == undefined) ? true : enableTooltips; + // Properly hande custom shortcuts + if( options.name && options.name in shortcuts ){ + bindings[options.name] = options.action; + } + if (options.title && enableTooltips) { el.title = createTooltip(options.title, options.action, shortcuts); @@ -169,7 +173,7 @@ function createToolbarButton(options, enableTooltips, shortcuts) { function createSep() { var el = document.createElement('i'); el.className = 'separator'; - el.textContent = '|'; + el.innerHTML = '|'; return el; } @@ -840,9 +844,23 @@ function togglePreview(editor) { var toolbar_div = wrapper.previousSibling; var toolbar = editor.options.toolbar ? editor.toolbarElements.preview : false; var preview = wrapper.lastChild; - if (!preview || !/editor-preview/.test(preview.className)) { + if (!preview || !/editor-preview-full/.test(preview.className)) { + preview = document.createElement('div'); - preview.className = 'editor-preview'; + preview.className = 'editor-preview-full'; + + if (editor.options.previewClass) { + + if (Array.isArray(editor.options.previewClass)) { + for (var i = 0; i < editor.options.previewClass.length; i++) { + preview.className += (' ' + editor.options.previewClass[i]); + } + + } else if (typeof editor.options.previewClass === 'string') { + preview.className += (' ' + editor.options.previewClass); + } + } + wrapper.appendChild(preview); } if (/editor-preview-active/.test(preview.className)) { @@ -885,7 +903,6 @@ function _replaceSelection(cm, active, startEnd, url) { Object.assign(startPoint, cm.getCursor('start')); Object.assign(endPoint, cm.getCursor('end')); if (url) { - start = start.replace('#url#', url); end = end.replace('#url#', url); } if (active) { @@ -1010,13 +1027,27 @@ function _toggleLine(cm, name) { var map = { 'quote': '>', 'unordered-list': '*', - 'ordered-list': 'd+.', + 'ordered-list': '\\d+.', }; var rt = new RegExp(map[name]); return char && rt.test(char); }; + var _toggle = function (name, text, untoggleOnly) { + var arr = listRegexp.exec(text); + var char = _getChar(name, line); + if (arr !== null) { + if (_checkChar(name, arr[2])) { + char = ''; + } + text = arr[1] + char + arr[3] + text.replace(whitespacesRegexp, '').replace(repl[name], '$1'); + } else if (untoggleOnly == false){ + text = char + ' ' + text; + } + return text; + }; + var line = 1; for (var i = startPoint.line; i <= endPoint.line; i++) { (function (i) { @@ -1024,16 +1055,13 @@ function _toggleLine(cm, name) { if (stat[name]) { text = text.replace(repl[name], '$1'); } else { - var arr = listRegexp.exec(text); - var char = _getChar(name, line); - if (arr !== null) { - if (_checkChar(name, arr[2])) { - char = ''; - } - text = arr[1] + char + arr[3] + text.replace(whitespacesRegexp, '').replace(repl[name], '$1'); - } else { - text = char + ' ' + text; + // If we're toggling unordered-list formatting, check if the current line + // is part of an ordered-list, and if so, untoggle that first. + // Workaround for https://github.com/Ionaru/easy-markdown-editor/issues/92 + if (name == 'unordered-list') { + text = _toggle('ordered-list', text, true); } + text = _toggle(name, text, false); line += 1; } cm.replaceRange(text, { @@ -1160,7 +1188,7 @@ function humanFileSize(bytes, units) { // Merge the properties of one object into another. function _mergeProperties(target, source) { for (var property in source) { - if (source.hasOwnProperty(property)) { + if (Object.prototype.hasOwnProperty.call(source, property)) { if (source[property] instanceof Array) { target[property] = source[property].concat(target[property] instanceof Array ? target[property] : []); } else if ( @@ -1491,7 +1519,7 @@ function EasyMDE(options) { // Loop over the built in buttons, to get the preferred order for (var key in toolbarBuiltInButtons) { - if (toolbarBuiltInButtons.hasOwnProperty(key)) { + if (Object.prototype.hasOwnProperty.call(toolbarBuiltInButtons, key)) { if (key.indexOf('separator-') != -1) { options.toolbar.push('|'); } @@ -1503,9 +1531,13 @@ function EasyMDE(options) { } } + // Editor preview styling class. + if (!Object.prototype.hasOwnProperty.call(options, 'previewClass')) { + options.previewClass = 'editor-preview'; + } // Handle status bar - if (!options.hasOwnProperty('status')) { + if (!Object.prototype.hasOwnProperty.call(options, 'status')) { if (options.uploadImage) { options.status = ['upload-image', 'autosave', 'lines', 'words', 'cursor']; } else { @@ -1710,7 +1742,12 @@ EasyMDE.prototype.render = function (el) { if (options.shortcuts[key] !== null && bindings[key] !== null) { (function (key) { keyMaps[fixShortcut(options.shortcuts[key])] = function () { - bindings[key](self); + var action = bindings[key]; + if (typeof action === 'function') { + action(self); + } else if (typeof action === 'string') { + window.open(action, '_blank'); + } }; })(key); } @@ -1874,7 +1911,7 @@ EasyMDE.prototype.autosave = function () { } m = m < 10 ? '0' + m : m; - el.textContent = 'Autosaved: ' + h + ':' + m + ' ' + dd; + el.innerHTML = 'Autosaved: ' + h + ':' + m + ' ' + dd; } this.autosaveTimeoutId = setTimeout(function () { @@ -1993,6 +2030,19 @@ EasyMDE.prototype.createSideBySide = function () { if (!preview || !/editor-preview-side/.test(preview.className)) { preview = document.createElement('div'); preview.className = 'editor-preview-side'; + + if (this.options.previewClass) { + + if (Array.isArray(this.options.previewClass)) { + for (var i = 0; i < this.options.previewClass.length; i++) { + preview.className += (' ' + this.options.previewClass[i]); + } + + } else if (typeof this.options.previewClass === 'string') { + preview.className += (' ' + this.options.previewClass); + } + } + wrapper.parentNode.insertBefore(preview, wrapper.nextSibling); } @@ -2176,25 +2226,25 @@ EasyMDE.prototype.createStatusbar = function (status) { if (name === 'words') { defaultValue = function (el) { - el.textContent = wordCount(cm.getValue()); + el.innerHTML = wordCount(cm.getValue()); }; onUpdate = function (el) { - el.textContent = wordCount(cm.getValue()); + el.innerHTML = wordCount(cm.getValue()); }; } else if (name === 'lines') { defaultValue = function (el) { - el.textContent = cm.lineCount(); + el.innerHTML = cm.lineCount(); }; onUpdate = function (el) { - el.textContent = cm.lineCount(); + el.innerHTML = cm.lineCount(); }; } else if (name === 'cursor') { defaultValue = function (el) { - el.textContent = '0:0'; + el.innerHTML = '0:0'; }; onUpdate = function (el) { var pos = cm.getCursor(); - el.textContent = pos.line + ':' + pos.ch; + el.innerHTML = pos.line + ':' + pos.ch; }; } else if (name === 'autosave') { defaultValue = function (el) { @@ -2204,7 +2254,7 @@ EasyMDE.prototype.createStatusbar = function (status) { }; } else if (name === 'upload-image') { defaultValue = function (el) { - el.textContent = options.imageTexts.sbInit; + el.innerHTML = options.imageTexts.sbInit; }; } diff --git a/types/easymde-test.ts b/types/easymde-test.ts index 2d5f5b7..f240ee9 100644 --- a/types/easymde-test.ts +++ b/types/easymde-test.ts @@ -7,6 +7,7 @@ const editor = new EasyMDE({ drawTable: 'Cmd-Alt-T', toggleFullScreen: null }, + previewClass: 'my-custom-class', spellChecker: false, onToggleFullScreen: (full: boolean) => { console.log('FullscreenToggled', full); @@ -28,3 +29,33 @@ editor.codemirror.setOption('readOnly', true); EasyMDE.toggleItalic = (editor: EasyMDE) => { console.log('SomeButtonOverride'); }; + +const editor2 = new EasyMDE({ + autoDownloadFontAwesome: undefined, + previewClass: ['my-custom-class', 'some-other-class'], + toolbar: [{ + name: 'bold', + action: EasyMDE.toggleBold, + className: 'fa fa-bolt', + title: 'Bold', + }, '|', { // Separator + name: 'alert', + action: (editor) => { + alert('This is from a custom button action!'); + // Custom functions have access to the `editor` instance. + }, + className: 'fa fa-star', + title: 'A Custom Button', + noDisable: undefined, + noMobile: false, + }, '|', { + name: 'link', + action: 'https://github.com/Ionaru/easy-markdown-editor', + className: 'fa fab fa-github', + title: 'A Custom Link', + noDisable: true, + noMobile: true, + }] +}); + +editor2.clearAutosavedValue(); diff --git a/types/easymde.d.ts b/types/easymde.d.ts index 07e9d4c..2055b77 100644 --- a/types/easymde.d.ts +++ b/types/easymde.d.ts @@ -1,16 +1,16 @@ // This file is based on https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/simplemde/index.d.ts, // which is written by Scalesoft and licensed under the MIT license: -// +// // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -100,6 +100,7 @@ declare namespace EasyMDE { lineWrapping?: boolean; parsingConfig?: ParsingOptions; placeholder?: string; + previewClass?: string | ReadonlyArray; previewRender?: (markdownPlaintext: string, previewElement: HTMLElement) => string; promptURLs?: boolean; renderingConfig?: RenderingOptions; From d317873fb060215144d3b164934552a2efe44ba1 Mon Sep 17 00:00:00 2001 From: Jeroen van Oorschot Date: Mon, 15 Jul 2019 13:24:58 +0200 Subject: [PATCH 30/51] update auxilary files and readme with 2.7.0 --- .travis.yml | 53 ++-- README.md | 5 + gulpfile.js | 2 +- package-lock.json | 700 +++++++++++++++++++++++--------------------- package.json | 30 +- src/css/easymde.css | 21 +- src/js/easymde.js | 1 + 7 files changed, 428 insertions(+), 384 deletions(-) diff --git a/.travis.yml b/.travis.yml index db3ff7c..55f3438 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,32 +1,33 @@ language: node_js node_js: + - '12' # EOL: April 2022 - '11' # EOL: June 2019 - '10' # EOL: April 2021 - '8' # EOL: December 2019 - '6' # EOL: April 2019 -script: - - npm run prepare - - npm run test:types -before_deploy: - - if [ "$TRAVIS_BRANCH" = master ] && [ "$TRAVIS_PULL_REQUEST" = false ]; then npm version prerelease --no-git-tag-version --preid "$TRAVIS_BUILD_NUMBER"; fi -deploy: - - provider: npm - email: info@saturnserver.org - api_key: - secure: rp4P11u0Vvz6iTkC1uj9LfNVOJASnTjffpqpe9lhuC/php7+fdoYvZ4e1EwKj2RVbi7YNqZE6w+Y6fsxZk72N4RGVO6HROm6gNv2wl+qk0B1XwciONO9y5FhTcdZrsq5Vx5WdoZThs5CSkXpvtHiavAnAt1ufYjqKGBZOENdxJ40kkn9WdQG2WvG7iZWDlDpDoqof2uO9k89d2UuTG5DKAoMpN+4UH0Fr0gV0u11IcBeH7rlSo2btlMaMsSO9Nb10Zf1rC0USHfyrui/BKvVGeRh7FASYrHwjqt4bwqzKZlP5bZ4zGIPMYXXsGLcidxIvSsNIRp7cgkWvsywe8cIi5XzaM48afWsbMUfMgXi9BDNjK7vBiuPBnGWYS3ylJZn/7SvMuqsoj4De5GWrCJ5pTsEKD5yw5+iqQv7v2ZYhuN7/tTSoEy/BOMdN43zWquJp57LXkyFQ9esGoI0bfeYojV2BvcpwY/UFS27e/9bH+RBlXsLfP0kEtosVGZ6i3AuUKtsYOxo4QZSI4yHtP7fKsoCoJIvpW3hcWjrnI8N7IC18/KihsUByuMgDgTTXXtDKxLbNVjbiVvFJeuClwe1oc1uusY1v/EkNpGDFZX5zFEVv3zC76NaLB75kCUN3gGC0RRFk0J9i3k8qa42TLjbOqvxgRxOEtVeRxowBNrymIQ= - tag: next - skip_cleanup: true - on: - node: 10 - branch: master - repo: Ionaru/easy-markdown-editor - - provider: npm - email: info@saturnserver.org - api_key: - secure: rp4P11u0Vvz6iTkC1uj9LfNVOJASnTjffpqpe9lhuC/php7+fdoYvZ4e1EwKj2RVbi7YNqZE6w+Y6fsxZk72N4RGVO6HROm6gNv2wl+qk0B1XwciONO9y5FhTcdZrsq5Vx5WdoZThs5CSkXpvtHiavAnAt1ufYjqKGBZOENdxJ40kkn9WdQG2WvG7iZWDlDpDoqof2uO9k89d2UuTG5DKAoMpN+4UH0Fr0gV0u11IcBeH7rlSo2btlMaMsSO9Nb10Zf1rC0USHfyrui/BKvVGeRh7FASYrHwjqt4bwqzKZlP5bZ4zGIPMYXXsGLcidxIvSsNIRp7cgkWvsywe8cIi5XzaM48afWsbMUfMgXi9BDNjK7vBiuPBnGWYS3ylJZn/7SvMuqsoj4De5GWrCJ5pTsEKD5yw5+iqQv7v2ZYhuN7/tTSoEy/BOMdN43zWquJp57LXkyFQ9esGoI0bfeYojV2BvcpwY/UFS27e/9bH+RBlXsLfP0kEtosVGZ6i3AuUKtsYOxo4QZSI4yHtP7fKsoCoJIvpW3hcWjrnI8N7IC18/KihsUByuMgDgTTXXtDKxLbNVjbiVvFJeuClwe1oc1uusY1v/EkNpGDFZX5zFEVv3zC76NaLB75kCUN3gGC0RRFk0J9i3k8qa42TLjbOqvxgRxOEtVeRxowBNrymIQ= - skip_cleanup: true - on: - node: 10 - branch: master - tags: true - repo: Ionaru/easy-markdown-editor + +jobs: + include: + - stage: deploy + node_js: "lts/*" + script: skip + before_deploy: if [ "$TRAVIS_BRANCH" = master ] && [ "$TRAVIS_PULL_REQUEST" = false ]; then npm version prerelease --no-git-tag-version --preid "$TRAVIS_BUILD_NUMBER"; fi + deploy: + - provider: npm + email: info@saturnserver.org + api_key: + secure: rp4P11u0Vvz6iTkC1uj9LfNVOJASnTjffpqpe9lhuC/php7+fdoYvZ4e1EwKj2RVbi7YNqZE6w+Y6fsxZk72N4RGVO6HROm6gNv2wl+qk0B1XwciONO9y5FhTcdZrsq5Vx5WdoZThs5CSkXpvtHiavAnAt1ufYjqKGBZOENdxJ40kkn9WdQG2WvG7iZWDlDpDoqof2uO9k89d2UuTG5DKAoMpN+4UH0Fr0gV0u11IcBeH7rlSo2btlMaMsSO9Nb10Zf1rC0USHfyrui/BKvVGeRh7FASYrHwjqt4bwqzKZlP5bZ4zGIPMYXXsGLcidxIvSsNIRp7cgkWvsywe8cIi5XzaM48afWsbMUfMgXi9BDNjK7vBiuPBnGWYS3ylJZn/7SvMuqsoj4De5GWrCJ5pTsEKD5yw5+iqQv7v2ZYhuN7/tTSoEy/BOMdN43zWquJp57LXkyFQ9esGoI0bfeYojV2BvcpwY/UFS27e/9bH+RBlXsLfP0kEtosVGZ6i3AuUKtsYOxo4QZSI4yHtP7fKsoCoJIvpW3hcWjrnI8N7IC18/KihsUByuMgDgTTXXtDKxLbNVjbiVvFJeuClwe1oc1uusY1v/EkNpGDFZX5zFEVv3zC76NaLB75kCUN3gGC0RRFk0J9i3k8qa42TLjbOqvxgRxOEtVeRxowBNrymIQ= + tag: next + skip_cleanup: true + on: + branch: master + repo: Ionaru/easy-markdown-editor + - provider: npm + email: info@saturnserver.org + api_key: + secure: rp4P11u0Vvz6iTkC1uj9LfNVOJASnTjffpqpe9lhuC/php7+fdoYvZ4e1EwKj2RVbi7YNqZE6w+Y6fsxZk72N4RGVO6HROm6gNv2wl+qk0B1XwciONO9y5FhTcdZrsq5Vx5WdoZThs5CSkXpvtHiavAnAt1ufYjqKGBZOENdxJ40kkn9WdQG2WvG7iZWDlDpDoqof2uO9k89d2UuTG5DKAoMpN+4UH0Fr0gV0u11IcBeH7rlSo2btlMaMsSO9Nb10Zf1rC0USHfyrui/BKvVGeRh7FASYrHwjqt4bwqzKZlP5bZ4zGIPMYXXsGLcidxIvSsNIRp7cgkWvsywe8cIi5XzaM48afWsbMUfMgXi9BDNjK7vBiuPBnGWYS3ylJZn/7SvMuqsoj4De5GWrCJ5pTsEKD5yw5+iqQv7v2ZYhuN7/tTSoEy/BOMdN43zWquJp57LXkyFQ9esGoI0bfeYojV2BvcpwY/UFS27e/9bH+RBlXsLfP0kEtosVGZ6i3AuUKtsYOxo4QZSI4yHtP7fKsoCoJIvpW3hcWjrnI8N7IC18/KihsUByuMgDgTTXXtDKxLbNVjbiVvFJeuClwe1oc1uusY1v/EkNpGDFZX5zFEVv3zC76NaLB75kCUN3gGC0RRFk0J9i3k8qa42TLjbOqvxgRxOEtVeRxowBNrymIQ= + skip_cleanup: true + on: + branch: master + repo: Ionaru/easy-markdown-editor + tags: true diff --git a/README.md b/README.md index 4c5b51e..227fe78 100644 --- a/README.md +++ b/README.md @@ -143,6 +143,7 @@ easyMDE.value('New input for **EasyMDE**'); - **strikethrough**: If set to `false`, will not process GFM strikethrough syntax. Defaults to `true`. - **underscoresBreakWords**: If set to `true`, let underscores be a delimiter for separating words. Defaults to `false`. - **placeholder**: If set, displays a custom placeholder message. +- **previewClass**: A string or array of strings that will be applied to the preview screen when activated. Defaults to `"editor-preview"`. - **previewRender**: Custom function for parsing the plaintext Markdown and returning HTML. Used when user previews. - **promptURLs**: If set to `true`, a JS alert window appears asking for the link or image URL. Defaults to `false`. - **promptTexts**: Customize the text used to prompt for URLs. @@ -220,6 +221,10 @@ var editor = new EasyMDE({ underscoresBreakWords: true, }, placeholder: "Type here...", + + previewClass: "my-custom-styling", + previewClass: ["my-custom-styling", "more-custom-styling"], + previewRender: function(plainText) { return customMarkdownParser(plainText); // Returns HTML from a custom parser }, diff --git a/gulpfile.js b/gulpfile.js index 99fba6f..be9e581 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -31,7 +31,7 @@ function scripts() { return browserify({entries: './src/js/easymde.js', standalone: 'EasyMDE'}).bundle() .pipe(source('easymde.min.js')) .pipe(buffer()) - .pipe(terser()) + // .pipe(terser()) // TODO enable to minify output .pipe(header(banner, {pkg: pkg})) .pipe(gulp.dest('./dist/')); } diff --git a/package-lock.json b/package-lock.json index d132614..98c7c63 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "easymde", - "version": "2.5.1", + "version": "2.7.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -14,9 +14,9 @@ } }, "@babel/highlight": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", - "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", + "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", "dev": true, "requires": { "chalk": "^2.0.0", @@ -25,9 +25,9 @@ } }, "@types/codemirror": { - "version": "0.0.72", - "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-0.0.72.tgz", - "integrity": "sha512-dKtEP139Jxdrog/6zW8akX3LdhJ3V8NjYNCpIHdBVVo6ZiYpShPamtQoGpVhzrUzTOu5A6NlozOSiZipCEVCow==", + "version": "0.0.76", + "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-0.0.76.tgz", + "integrity": "sha512-k/hpUb+Ebyn9z63qM8IbsRiW0eYHZ+pi/1e2reGzBKAZJzkjWmNTXXqLLiNv5d9ekyxkajxRBr5Hu2WZq/nokw==", "dev": true, "requires": { "@types/tern": "*" @@ -40,9 +40,9 @@ "dev": true }, "@types/tern": { - "version": "0.22.2", - "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.22.2.tgz", - "integrity": "sha512-+NIfiqlXrItuv0M6DiXF8gFTQ0CITidyATwTJLmu442x6M38dn0RKFsgRQzm9wFF0WE/PYM1Hf3hLSZxMDkoyQ==", + "version": "0.23.3", + "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.3.tgz", + "integrity": "sha512-imDtS4TAoTcXk0g7u4kkWqedB3E4qpjXzCpD2LU5M5NAXHzCDsypyvXSaG7mM8DKYkCRa7tFp4tS/lp/Wo7Q3w==", "dev": true, "requires": { "@types/estree": "*" @@ -59,9 +59,9 @@ } }, "acorn": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz", - "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.2.0.tgz", + "integrity": "sha512-8oe72N3WPMjA+2zVG71Ia0nXZ8DpQH+QyyHO+p06jT8eg8FGG3FbcUIi8KziHlAfheJQZeoqbvq1mQSQHXKYLw==", "dev": true }, "acorn-dynamic-import": { @@ -77,27 +77,27 @@ "dev": true }, "acorn-node": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.6.2.tgz", - "integrity": "sha512-rIhNEZuNI8ibQcL7ANm/mGyPukIaZsRNX9psFNQURyJW0nu6k8wjSDld20z6v2mDBWqX13pIEnk9gGZJHIlEXg==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.7.0.tgz", + "integrity": "sha512-XhahLSsCB6X6CJbe+uNu3Mn9sJBNFxtBN9NLgAOQovfS6Kh0lDUtmlclhjn9CvEK7A7YyRU13PXlNcpSiLI9Yw==", "dev": true, "requires": { - "acorn": "^6.0.2", + "acorn": "^6.1.1", "acorn-dynamic-import": "^4.0.0", - "acorn-walk": "^6.1.0", + "acorn-walk": "^6.1.1", "xtend": "^4.0.1" } }, "acorn-walk": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz", - "integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", + "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==", "dev": true }, "ajv": { - "version": "6.9.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.9.2.tgz", - "integrity": "sha512-4UFy0/LgDo7Oa/+wOAlj44tp9K78u38E5/359eSrqEp1Z5PdVfimCcs7SluXMP755RUQu6d2b4AvF0R1C9RZjg==", + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", "dev": true, "requires": { "fast-deep-equal": "^2.0.1", @@ -323,11 +323,12 @@ } }, "assert": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", - "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", "dev": true, "requires": { + "object-assign": "^4.1.1", "util": "0.10.3" }, "dependencies": { @@ -361,29 +362,21 @@ "dev": true }, "async-done": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.1.tgz", - "integrity": "sha512-R1BaUeJ4PMoLNJuk+0tLJgjmEqVsdN118+Z8O+alhnQDQgy0kmD5Mqi0DNEmMx2LM0Ed5yekKu+ZXYvIHceicg==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz", + "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==", "dev": true, "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.2", - "process-nextick-args": "^1.0.7", + "process-nextick-args": "^2.0.0", "stream-exhaust": "^1.0.1" - }, - "dependencies": { - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", - "dev": true - } } }, "async-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", - "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", "dev": true }, "async-settle": { @@ -486,9 +479,9 @@ "dev": true }, "binary-extensions": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.0.tgz", - "integrity": "sha512-EgmjVLMn22z7eGGv3kcnHwSnJXmFHjISTY9E/S5lIcTD3Oxw05QTcBLNkJFzcb3cNueUdF/IN4U+d78V0zO8Hw==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", "dev": true }, "bl": { @@ -584,9 +577,9 @@ } }, "browserify": { - "version": "16.2.3", - "resolved": "https://registry.npmjs.org/browserify/-/browserify-16.2.3.tgz", - "integrity": "sha512-zQt/Gd1+W+IY+h/xX2NYMW4orQWhqSwyV+xsblycTtpOuB27h1fZhhNQuipJ4t79ohw4P4mMem0jp/ZkISQtjQ==", + "version": "16.3.0", + "resolved": "https://registry.npmjs.org/browserify/-/browserify-16.3.0.tgz", + "integrity": "sha512-BWaaD7alyGZVEBBwSTYx4iJF5DswIGzK17o8ai9w4iKRbYpk3EOiprRHMRRA8DCZFmFeOdx7A385w2XdFvxWmg==", "dev": true, "requires": { "JSONStream": "^1.0.3", @@ -768,9 +761,9 @@ "dev": true }, "callsites": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.0.0.tgz", - "integrity": "sha512-tWnkwu9YEq2uzlBDI4RcLn8jrFvF9AOi8PxDNU3hZZjJcjkcRAq3vCI+vZcg1SuxISDYe86k9VZFwAxDiJGoAw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true }, "camelcase": { @@ -797,9 +790,9 @@ "dev": true }, "chokidar": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.2.tgz", - "integrity": "sha512-IwXUx0FXc5ibYmPC2XeEj5mpXoV66sR+t3jqu2NS2GYwCktt3KF1/Qqjws/NkegajBA4RbZ5+DDwlOiJsxDHEg==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.6.tgz", + "integrity": "sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g==", "dev": true, "requires": { "anymatch": "^2.0.0", @@ -813,7 +806,7 @@ "normalize-path": "^3.0.0", "path-is-absolute": "^1.0.0", "readdirp": "^2.2.1", - "upath": "^1.1.0" + "upath": "^1.1.1" }, "dependencies": { "normalize-path": { @@ -936,9 +929,9 @@ "dev": true }, "codemirror": { - "version": "5.44.0", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.44.0.tgz", - "integrity": "sha512-3l42syTNakCdCQuYeZJXTyxina6Y9i4V0ighSJXNCQtRbaCN76smKKLu1ZHPHQon3rnzC7l4i/0r4gp809K1wg==" + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.48.0.tgz", + "integrity": "sha512-3Ter+tYtRlTNtxtYdYNPxGxBL/b3cMcvPdPm70gvmcOO2Rauv/fUEewWa0tT596Hosv6ea2mtpx28OXBy1mQCg==" }, "codemirror-spell-checker": { "version": "1.1.2", @@ -1003,15 +996,15 @@ } }, "commander": { - "version": "2.17.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", - "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", "dev": true }, "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", "dev": true }, "concat-map": { @@ -1162,12 +1155,13 @@ } }, "d": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", - "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", "dev": true, "requires": { - "es5-ext": "^0.10.9" + "es5-ext": "^0.10.50", + "type": "^1.0.1" } }, "dash-ast": { @@ -1385,9 +1379,9 @@ } }, "elliptic": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz", - "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.0.tgz", + "integrity": "sha512-eFOJTMyCYb7xtE/caJ6JJu+bhi67WCYNbkGSknu20pmM8Ke/bqOfdnZWxyoGN26JgfxTbXrsCkEw4KheCT/KGg==", "dev": true, "requires": { "bn.js": "^4.4.0", @@ -1424,14 +1418,14 @@ } }, "es5-ext": { - "version": "0.10.48", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.48.tgz", - "integrity": "sha512-CdRvPlX/24Mj5L4NVxTs4804sxiS2CjVprgCmrgoDkdmjdY4D+ySHa7K3jJf8R40dFg0tIm3z/dk326LrnuSGw==", + "version": "0.10.50", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.50.tgz", + "integrity": "sha512-KMzZTPBkeQV/JcSQhI5/z6d9VWJ3EnQ194USTUwIYZ2ZbpN8+SGXQKt1h68EX44+qt+Fzr8DO17vnxrw7c3agw==", "dev": true, "requires": { "es6-iterator": "~2.0.3", "es6-symbol": "~3.1.1", - "next-tick": "1" + "next-tick": "^1.0.0" } }, "es6-iterator": { @@ -1456,14 +1450,14 @@ } }, "es6-weak-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", - "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", "dev": true, "requires": { "d": "1", - "es5-ext": "^0.10.14", - "es6-iterator": "^2.0.1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", "es6-symbol": "^3.1.1" } }, @@ -1474,32 +1468,33 @@ "dev": true }, "eslint": { - "version": "5.14.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.14.1.tgz", - "integrity": "sha512-CyUMbmsjxedx8B0mr79mNOqetvkbij/zrXnFeK2zc3pGRn3/tibjiNAv/3UxFEyfMDjh+ZqTrJrEGBFiGfD5Og==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.0.1.tgz", + "integrity": "sha512-DyQRaMmORQ+JsWShYsSg4OPTjY56u1nCjAmICrE8vLWqyLKxhFXOthwMj1SA8xwfrv0CofLNVnqbfyhwCkaO0w==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "ajv": "^6.9.1", + "ajv": "^6.10.0", "chalk": "^2.1.0", "cross-spawn": "^6.0.5", "debug": "^4.0.1", "doctrine": "^3.0.0", - "eslint-scope": "^4.0.0", + "eslint-scope": "^4.0.3", "eslint-utils": "^1.3.1", "eslint-visitor-keys": "^1.0.0", - "espree": "^5.0.1", + "espree": "^6.0.0", "esquery": "^1.0.1", "esutils": "^2.0.2", "file-entry-cache": "^5.0.1", "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", + "glob-parent": "^3.1.0", "globals": "^11.7.0", "ignore": "^4.0.6", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "inquirer": "^6.2.2", - "js-yaml": "^3.12.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.3.0", "lodash": "^4.17.11", @@ -1507,7 +1502,6 @@ "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", "progress": "^2.0.0", "regexpp": "^2.0.1", "semver": "^5.5.1", @@ -1533,9 +1527,9 @@ } }, "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, "strip-ansi": { @@ -1550,9 +1544,9 @@ } }, "eslint-scope": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz", - "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", "dev": true, "requires": { "esrecurse": "^4.1.0", @@ -1560,10 +1554,13 @@ } }, "eslint-utils": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz", - "integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==", - "dev": true + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.0.tgz", + "integrity": "sha512-7ehnzPaP5IIEh1r1tkjuIrxqhNkzUJa9z3R92tLJdZIVdWaczEhr3EbhGtsMrVxi1KeR8qA7Off6SWc5WNQqyQ==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.0.0" + } }, "eslint-visitor-keys": { "version": "1.0.0", @@ -1572,9 +1569,9 @@ "dev": true }, "espree": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", - "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.0.0.tgz", + "integrity": "sha512-lJvCS6YbCn3ImT3yKkPe0+tJ+mH6ljhGNjHQH9mRtiO6gjhVAOhVXW1yjnwqGwTkK3bGbye+hb00nFNmu0l/1Q==", "dev": true, "requires": { "acorn": "^6.0.7", @@ -1706,9 +1703,9 @@ } }, "external-editor": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz", - "integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", "dev": true, "requires": { "chardet": "^0.7.0", @@ -1863,32 +1860,21 @@ } }, "findup-sync": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", - "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", "dev": true, "requires": { "detect-file": "^1.0.0", - "is-glob": "^3.1.0", + "is-glob": "^4.0.0", "micromatch": "^3.0.4", "resolve-dir": "^1.0.1" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } } }, "fined": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/fined/-/fined-1.1.1.tgz", - "integrity": "sha512-jQp949ZmEbiYHk3gkbdtpJ0G1+kgtLQBNdP5edFP7Fh+WAYceLQz6yO1SBj72Xkg8GVyTB3bBzAYrHJVh5Xd5g==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", + "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", "dev": true, "requires": { "expand-tilde": "^2.0.2", @@ -1916,9 +1902,9 @@ } }, "flatted": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz", - "integrity": "sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", + "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", "dev": true }, "flush-write-stream": { @@ -1972,14 +1958,14 @@ "dev": true }, "fsevents": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.7.tgz", - "integrity": "sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", "dev": true, "optional": true, "requires": { - "nan": "^2.9.2", - "node-pre-gyp": "^0.10.0" + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" }, "dependencies": { "abbrev": { @@ -2057,12 +2043,12 @@ "optional": true }, "debug": { - "version": "2.6.9", + "version": "4.1.1", "bundled": true, "dev": true, "optional": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "deep-extend": { @@ -2233,24 +2219,24 @@ } }, "ms": { - "version": "2.0.0", + "version": "2.1.1", "bundled": true, "dev": true, "optional": true }, "needle": { - "version": "2.2.4", + "version": "2.3.0", "bundled": true, "dev": true, "optional": true, "requires": { - "debug": "^2.1.2", + "debug": "^4.1.0", "iconv-lite": "^0.4.4", "sax": "^1.2.4" } }, "node-pre-gyp": { - "version": "0.10.3", + "version": "0.12.0", "bundled": true, "dev": true, "optional": true, @@ -2278,13 +2264,13 @@ } }, "npm-bundled": { - "version": "1.0.5", + "version": "1.0.6", "bundled": true, "dev": true, "optional": true }, "npm-packlist": { - "version": "1.2.0", + "version": "1.4.1", "bundled": true, "dev": true, "optional": true, @@ -2423,7 +2409,7 @@ "optional": true }, "semver": { - "version": "5.6.0", + "version": "5.7.0", "bundled": true, "dev": true, "optional": true @@ -2550,9 +2536,9 @@ "dev": true }, "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -2641,9 +2627,9 @@ } }, "globals": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", - "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==", + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, "glogg": { @@ -2656,27 +2642,27 @@ } }, "graceful-fs": { - "version": "4.1.15", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz", + "integrity": "sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg==", "dev": true }, "gulp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.0.tgz", - "integrity": "sha1-lXZsYB2t5Kd+0+eyttwDiBtZY2Y=", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz", + "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==", "dev": true, "requires": { - "glob-watcher": "^5.0.0", - "gulp-cli": "^2.0.0", - "undertaker": "^1.0.0", + "glob-watcher": "^5.0.3", + "gulp-cli": "^2.2.0", + "undertaker": "^1.2.1", "vinyl-fs": "^3.0.0" }, "dependencies": { "gulp-cli": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.0.1.tgz", - "integrity": "sha512-RxujJJdN8/O6IW2nPugl7YazhmrIEjmiVfPKrWt68r71UCaLKS71Hp0gpKT+F6qOUFtr7KqtifDKaAJPRVvMYQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.2.0.tgz", + "integrity": "sha512-rGs3bVYHdyJpLqR0TUBnlcZ1O5O++Zs4bA0ajm+zr3WFCfiSLjGwoCBqFs18wzN+ZxahT9DkOK5nDf26iDsWjA==", "dev": true, "requires": { "ansi-colors": "^1.0.1", @@ -2689,7 +2675,7 @@ "gulplog": "^1.0.0", "interpret": "^1.1.0", "isobject": "^3.0.1", - "liftoff": "^2.5.0", + "liftoff": "^3.1.0", "matchdep": "^2.0.0", "mute-stdout": "^1.0.0", "pretty-hrtime": "^1.0.0", @@ -2702,25 +2688,24 @@ } }, "gulp-clean-css": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/gulp-clean-css/-/gulp-clean-css-4.0.0.tgz", - "integrity": "sha512-/Hs+dmclQfFBSpwrAKd4wTVsahJvrVIg2ga0J7Eo7DKVTVfJrM7wXlfU1mK9iJ9Y7OmkO/YstZVtmhfAKzZ00g==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/gulp-clean-css/-/gulp-clean-css-4.2.0.tgz", + "integrity": "sha512-r4zQsSOAK2UYUL/ipkAVCTRg/2CLZ2A+oPVORopBximRksJ6qy3EX1KGrIWT4ZrHxz3Hlobb1yyJtqiut7DNjA==", "dev": true, "requires": { "clean-css": "4.2.1", "plugin-error": "1.0.1", - "through2": "3.0.0", + "through2": "3.0.1", "vinyl-sourcemaps-apply": "0.2.1" }, "dependencies": { "through2": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.0.tgz", - "integrity": "sha512-8B+sevlqP4OiCjonI1Zw03Sf8PuV1eRsYQgLad5eonILOdyeRsY27A/2Ze8IlvlMvq31OH+3fz/styI7Ya62yQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", + "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", "dev": true, "requires": { - "readable-stream": "2 || 3", - "xtend": "~4.0.1" + "readable-stream": "2 || 3" } } } @@ -2737,12 +2722,12 @@ } }, "gulp-eslint": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/gulp-eslint/-/gulp-eslint-5.0.0.tgz", - "integrity": "sha512-9GUqCqh85C7rP9120cpxXuZz2ayq3BZc85pCTuPJS03VQYxne0aWPIXWx6LSvsGPa3uRqtSO537vaugOh+5cXg==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gulp-eslint/-/gulp-eslint-6.0.0.tgz", + "integrity": "sha512-dCVPSh1sA+UVhn7JSQt7KEb4An2sQNbOdB3PA8UCfxsoPlAKjJHxYHGXdXC7eb+V1FAnilSFFqslPrq037l1ig==", "dev": true, "requires": { - "eslint": "^5.0.1", + "eslint": "^6.0.0", "fancy-log": "^1.3.2", "plugin-error": "^1.0.1" } @@ -2765,15 +2750,40 @@ "integrity": "sha512-swzbIGb/arEoFK89tPY58vg3Ok1bw+d35PfUNwWqdo7KM4jkmuGA78JiDNqR+JeZFaeeHnRg9N7aihX3YPmsyg==", "dev": true }, + "gulp-terser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gulp-terser/-/gulp-terser-1.2.0.tgz", + "integrity": "sha512-lf+jE2DALg2w32p0HRiYMlFYRYelKZPNunHp2pZccCYrrdCLOs0ItbZcN63yr2pbz116IyhUG9mD/QbtRO1FKA==", + "dev": true, + "requires": { + "plugin-error": "^1.0.1", + "terser": "^4.0.0", + "through2": "^3.0.1", + "vinyl-sourcemaps-apply": "^0.2.1" + }, + "dependencies": { + "through2": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", + "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", + "dev": true, + "requires": { + "readable-stream": "2 || 3" + } + } + } + }, "gulp-uglify": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/gulp-uglify/-/gulp-uglify-3.0.1.tgz", - "integrity": "sha512-KVffbGY9d4Wv90bW/B1KZJyunLMyfHTBbilpDvmcrj5Go0/a1G3uVpt+1gRBWSw/11dqR3coJ1oWNTt1AiXuWQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gulp-uglify/-/gulp-uglify-3.0.2.tgz", + "integrity": "sha512-gk1dhB74AkV2kzqPMQBLA3jPoIAPd/nlNzP2XMDSG8XZrqnlCiDGAqC+rZOumzFvB5zOphlFh6yr3lgcAb/OOg==", "dev": true, "requires": { + "array-each": "^1.0.1", + "extend-shallow": "^3.0.2", "gulplog": "^1.0.0", "has-gulplog": "^0.1.0", - "lodash": "^4.13.1", + "isobject": "^3.0.1", "make-error-cause": "^1.1.1", "safe-buffer": "^5.1.2", "through2": "^2.0.0", @@ -2920,9 +2930,9 @@ } }, "ieee754": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz", - "integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", "dev": true }, "ignore": { @@ -2932,9 +2942,9 @@ "dev": true }, "import-fresh": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.0.0.tgz", - "integrity": "sha512-pOnA9tfM3Uwics+SaBLCNyZZZbK+4PTu0OPZtLlMIrv17EdBoC15S9Kn8ckJ9TZTyKb3ywNE5y1yeDxxGA7nTQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", + "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", "dev": true, "requires": { "parent-module": "^1.0.0", @@ -2979,9 +2989,9 @@ } }, "inquirer": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.2.tgz", - "integrity": "sha512-Z2rREiXA6cHRR9KBOarR3WuLlFzlIfAEIiB45ll5SSadMg7WqOh1MKEjjndfuH5ewXdixWCxqnVfGOQzPeiztA==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.0.tgz", + "integrity": "sha512-scfHejeG/lVZSpvCXpsB4j/wQNPM5JC8kiElOI0OUTwmc1RTpXr4H32/HOlQHcZiYl2z2VElwuCVDRG8vFmbnA==", "dev": true, "requires": { "ansi-escapes": "^3.2.0", @@ -2990,12 +3000,12 @@ "cli-width": "^2.0.0", "external-editor": "^3.0.3", "figures": "^2.0.0", - "lodash": "^4.17.11", + "lodash": "^4.17.12", "mute-stream": "0.0.7", "run-async": "^2.2.0", "rxjs": "^6.4.0", "string-width": "^2.1.0", - "strip-ansi": "^5.0.0", + "strip-ansi": "^5.1.0", "through": "^2.3.6" }, "dependencies": { @@ -3033,18 +3043,18 @@ } }, "strip-ansi": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.0.0.tgz", - "integrity": "sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { - "ansi-regex": "^4.0.0" + "ansi-regex": "^4.1.0" }, "dependencies": { "ansi-regex": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.0.0.tgz", - "integrity": "sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true } } @@ -3193,9 +3203,9 @@ } }, "is-glob": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", - "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", "dev": true, "requires": { "is-extglob": "^2.1.1" @@ -3303,9 +3313,9 @@ "dev": true }, "js-yaml": { - "version": "3.12.2", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.2.tgz", - "integrity": "sha512-QHn/Lh/7HhZ/Twc7vJYQTkjuCa0kaCcDcjK5Zlk2rvnUpy7DxMJ23+Jc2dcyvltwQVg1nygAVlB2oRDFHoRS5Q==", + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", "dev": true, "requires": { "argparse": "^1.0.7", @@ -3358,22 +3368,13 @@ "dev": true }, "labeled-stream-splicer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.1.tgz", - "integrity": "sha512-MC94mHZRvJ3LfykJlTUipBqenZz1pacOZEMhhQ8dMGcDHs0SBE5GbsavUXV7YtP3icBW17W0Zy1I0lfASmo9Pg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.2.tgz", + "integrity": "sha512-Ca4LSXFFZUjPScRaqOcFxneA0VpKZr4MMYCljyQr4LIewTLb3Y0IUTIsnBBsVubIeEfxeSZpSjSsRM8APEQaAw==", "dev": true, "requires": { "inherits": "^2.0.1", - "isarray": "^2.0.4", "stream-splicer": "^2.0.0" - }, - "dependencies": { - "isarray": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.4.tgz", - "integrity": "sha512-GMxXOiUirWg1xTKRipM0Ek07rX+ubx4nNVElTJdNLYmNO/2YrDkgJGw9CljXn+r4EWiDQg/8lsRdHyg2PJuUaA==", - "dev": true - } } }, "last-run": { @@ -3424,13 +3425,13 @@ } }, "liftoff": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-2.5.0.tgz", - "integrity": "sha1-IAkpG7Mc6oYbvxCnwVooyvdcMew=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", + "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", "dev": true, "requires": { "extend": "^3.0.0", - "findup-sync": "^2.0.0", + "findup-sync": "^3.0.0", "fined": "^1.0.1", "flagged-respawn": "^1.0.0", "is-plain-object": "^2.0.4", @@ -3453,9 +3454,9 @@ } }, "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", + "version": "4.17.14", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz", + "integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==", "dev": true }, "lodash._reinterpolate": { @@ -3535,9 +3536,9 @@ } }, "marked": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/marked/-/marked-0.6.1.tgz", - "integrity": "sha512-+H0L3ibcWhAZE02SKMqmvYsErLo4EAVJxu5h3bHBBDvvjeWXtl92rGUSBYHL2++5Y+RSNgl8dYOAXcYe7lp1fA==" + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.7.0.tgz", + "integrity": "sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg==" }, "matchdep": { "version": "2.0.0", @@ -3549,6 +3550,29 @@ "micromatch": "^3.0.4", "resolve": "^1.4.0", "stack-trace": "0.0.10" + }, + "dependencies": { + "findup-sync": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", + "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "dev": true, + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^3.1.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + } + }, + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } } }, "md5.js": { @@ -3627,9 +3651,9 @@ "dev": true }, "mixin-deep": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", - "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", "dev": true, "requires": { "for-in": "^1.0.2", @@ -3665,14 +3689,14 @@ } }, "module-deps": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.2.0.tgz", - "integrity": "sha512-hKPmO06so6bL/ZvqVNVqdTVO8UAYsi3tQWlCa+z9KuWhoN4KDQtb5hcqQQv58qYiDE21wIvnttZEPiDgEbpwbA==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.2.1.tgz", + "integrity": "sha512-UnEn6Ah36Tu4jFiBbJVUtt0h+iXqxpLqDvPS8nllbw5RZFmNJ1+Mz5BjYnM9ieH80zyxHkARGLnMIHlPK5bu6A==", "dev": true, "requires": { "JSONStream": "^1.0.3", "browser-resolve": "^1.7.0", - "cached-path-relative": "^1.0.0", + "cached-path-relative": "^1.0.2", "concat-stream": "~1.6.0", "defined": "^1.0.0", "detective": "^5.0.2", @@ -3706,9 +3730,9 @@ "dev": true }, "nan": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz", - "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", "dev": true, "optional": true }, @@ -3771,9 +3795,9 @@ } }, "now-and-later": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.0.tgz", - "integrity": "sha1-vGHLtFbXnLMiB85HygUTb/Ln1u4=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", + "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==", "dev": true, "requires": { "once": "^1.3.2" @@ -3785,6 +3809,12 @@ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, "object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", @@ -3817,9 +3847,9 @@ } }, "object-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.0.tgz", - "integrity": "sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true }, "object-visit": { @@ -3947,15 +3977,15 @@ "dev": true }, "pako": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.8.tgz", - "integrity": "sha512-6i0HVbUfcKaTv+EG8ZTr75az7GFXcLYk9UyLEg7Notv/Ma+z/UG3TCoz6GiNeOrn1E/e63I0X/Hpw18jHOTUnA==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", + "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==", "dev": true }, "parent-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.0.tgz", - "integrity": "sha512-8Mf5juOMmiE4FcmzYc4IaiS9L3+9paz2KOiXzkRviCP6aDmN49Hz6EMWz0lGNp9pX80GvvAuLADtyGfW/Em3TA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, "requires": { "callsites": "^3.0.0" @@ -4049,12 +4079,6 @@ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true - }, "path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", @@ -4414,9 +4438,9 @@ "dev": true }, "resolve": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", - "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.1.tgz", + "integrity": "sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==", "dev": true, "requires": { "path-parse": "^1.0.6" @@ -4498,9 +4522,9 @@ } }, "rxjs": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", - "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz", + "integrity": "sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==", "dev": true, "requires": { "tslib": "^1.9.0" @@ -4528,9 +4552,9 @@ "dev": true }, "semver": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", "dev": true }, "semver-greatest-satisfied-range": { @@ -4549,9 +4573,9 @@ "dev": true }, "set-value": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", "dev": true, "requires": { "extend-shallow": "^2.0.1", @@ -4775,6 +4799,24 @@ "urix": "^0.1.0" } }, + "source-map-support": { + "version": "0.5.12", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.12.tgz", + "integrity": "sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "source-map-url": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", @@ -4814,9 +4856,9 @@ } }, "spdx-license-ids": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz", - "integrity": "sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", "dev": true }, "split-string": { @@ -4907,9 +4949,9 @@ "dev": true }, "stream-splicer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.0.tgz", - "integrity": "sha1-G2O+Q4oTPktnHMGTUZdgAXWRDYM=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.1.tgz", + "integrity": "sha512-Xizh4/NPuYSyAXyT7g8IvdJ9HJpxIGL9PjyhtywCZvvP0OPIdqyrr4dMikeuvY8xahpdKEBlBTySe583totajg==", "dev": true, "requires": { "inherits": "^2.0.1", @@ -4998,9 +5040,9 @@ } }, "table": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/table/-/table-5.2.3.tgz", - "integrity": "sha512-N2RsDAMvDLvYwFcwbPyF3VmVSSkuF+G1e+8inhBLtHpvwXGw4QRPEZhihQNeEN0i1up6/f6ObCJXNdlRG3YVyQ==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.1.tgz", + "integrity": "sha512-E6CK1/pZe2N75rGZQotFOdmzWQ1AILtgYbMAbAjvms0S1l5IDB47zG3nCnFGB/w+7nB3vKofbLXCH7HPBo864w==", "dev": true, "requires": { "ajv": "^6.9.1", @@ -5010,9 +5052,9 @@ }, "dependencies": { "ansi-regex": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.0.0.tgz", - "integrity": "sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, "is-fullwidth-code-point": { @@ -5022,27 +5064,46 @@ "dev": true }, "string-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.0.0.tgz", - "integrity": "sha512-rr8CUxBbvOZDUvc5lNIJ+OC1nPVpz+Siw9VBtUjB9b6jZehZLFt0JMCZzShFHIsI8cbhm0EsNIfWJMFV3cu3Ew==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.0.0" + "strip-ansi": "^5.1.0" } }, "strip-ansi": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.0.0.tgz", - "integrity": "sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { - "ansi-regex": "^4.0.0" + "ansi-regex": "^4.1.0" } } } }, + "terser": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.1.2.tgz", + "integrity": "sha512-jvNoEQSPXJdssFwqPSgWjsOrb+ELoE+ILpHPKXC83tIxOlh2U75F1KuB2luLD/3a6/7K3Vw5pDn+hvu0C4AzSw==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -5167,9 +5228,9 @@ } }, "tslib": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", - "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", "dev": true }, "tty-browserify": { @@ -5178,6 +5239,12 @@ "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==", "dev": true }, + "type": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/type/-/type-1.0.1.tgz", + "integrity": "sha512-MAM5dBMJCJNKs9E7JXo4CXRAansRfG0nlJxW7Wf6GZzSOvH31zClSaHdIMWLehe/EGMBkqeC55rrkaOr5Oo7Nw==", + "dev": true + }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -5194,9 +5261,9 @@ "dev": true }, "typescript": { - "version": "3.3.3333", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.3333.tgz", - "integrity": "sha512-JjSKsAfuHBE/fB2oZ8NxtRTk5iGcg6hkYXMnZ3Wc+b2RSqejEqTaem11mHASMnFilHrax3sLK0GDzcJrekZYLw==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz", + "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==", "dev": true }, "typo-js": { @@ -5205,12 +5272,12 @@ "integrity": "sha1-VNjrx5SfGngQkItgAsaEFSbJnVo=" }, "uglify-js": { - "version": "3.4.9", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz", - "integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz", + "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==", "dev": true, "requires": { - "commander": "~2.17.1", + "commander": "~2.20.0", "source-map": "~0.6.1" }, "dependencies": { @@ -5248,9 +5315,9 @@ } }, "undertaker": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.2.0.tgz", - "integrity": "sha1-M52kZGJS0ILcN45wgGcpl1DhG0k=", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.2.1.tgz", + "integrity": "sha512-71WxIzDkgYk9ZS+spIB8iZXchFhAdEo2YU8xYqBYJ39DIUIqziK78ftm26eecoIY49X0J2MLhG4hr18Yp6/CMA==", "dev": true, "requires": { "arr-flatten": "^1.0.1", @@ -5271,38 +5338,15 @@ "dev": true }, "union-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", - "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", "dev": true, "requires": { "arr-union": "^3.1.0", "get-value": "^2.0.6", "is-extendable": "^0.1.1", - "set-value": "^0.4.3" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "set-value": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", - "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" - } - } + "set-value": "^2.0.1" } }, "unique-stream": { @@ -5356,9 +5400,9 @@ } }, "upath": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz", - "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz", + "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==", "dev": true }, "uri-js": { @@ -5424,9 +5468,9 @@ "dev": true }, "v8flags": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.2.tgz", - "integrity": "sha512-MtivA7GF24yMPte9Rp/BWGCYQNaUj86zeYxV/x2RRJMKagImbbv3u8iJC57lNhWLPcGLJmHcHmFWkNsplbbLWw==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.3.tgz", + "integrity": "sha512-amh9CCg3ZxkzQ48Mhcb8iX7xpAfYJgePHxWMQCBWECpOSqJUXgY26ncA61UTV0BkPqfhcy6mzwCIoP4ygxpW8w==", "dev": true, "requires": { "homedir-polyfill": "^1.0.1" diff --git a/package.json b/package.json index a55a913..38429f3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "easymde", - "version": "2.5.1", + "version": "2.7.0", "description": "A simple, beautiful, and embeddable JavaScript Markdown editor that easy to use. Features include autosaving and spell checking.", "files": [ "dist/**/*", @@ -18,34 +18,30 @@ "types": "types/easymde.d.ts", "license": "MIT", "author": "Jeroen Akkerman", - "bugs": { - "url": "https://github.com/ionaru/easy-markdown-editor/issues" - }, "dependencies": { - "codemirror": "^5.43.0", + "codemirror": "^5.48.0", "codemirror-spell-checker": "1.1.2", - "marked": "^0.6.1" + "marked": "^0.7.0" }, "devDependencies": { - "@types/codemirror": "0.0.72", - "browserify": "^16.2.3", - "gulp": "^4.0.0", - "gulp-clean-css": "^4.0.0", + "@types/codemirror": "0.0.76", + "browserify": "^16.3.0", + "gulp": "^4.0.2", + "gulp-clean-css": "^4.2.0", "gulp-concat": "^2.6.1", - "gulp-eslint": "^5.0.0", + "gulp-eslint": "^6.0.0", "gulp-header": "^2.0.7", "gulp-rename": "^1.4.0", - "gulp-uglify": "^3.0.1", - "typescript": "^3.3.3", + "gulp-terser": "^1.2.0", + "gulp-uglify": "^3.0.2", + "typescript": "^3.5.3", "vinyl-buffer": "^1.0.0", "vinyl-source-stream": "^2.0.0" }, - "repository": { - "type": "git", - "url": "https://github.com/ionaru/easy-markdown-editor" - }, + "repository": "github:Ionaru/easy-markdown-editor", "scripts": { "prepare": "gulp", + "test": "npm run test:types", "test:types": "tsc --project types/tsconfig.json" } } diff --git a/src/css/easymde.css b/src/css/easymde.css index 3843bdc..a027a14 100644 --- a/src/css/easymde.css +++ b/src/css/easymde.css @@ -213,14 +213,12 @@ content: 'characters: ' } -.editor-preview { - padding: 10px; +.editor-preview-full { position: absolute; width: 100%; height: 100%; top: 0; left: 0; - background: #fafafa; z-index: 7; overflow: auto; display: none; @@ -228,13 +226,11 @@ } .editor-preview-side { - padding: 10px; position: fixed; bottom: 0; width: 50%; top: 50px; right: 0; - background: #fafafa; z-index: 9; overflow: auto; display: none; @@ -251,21 +247,22 @@ display: block } -.editor-preview > p, -.editor-preview-side > p { +.editor-preview { + padding: 10px; + background: #fafafa; +} + +.editor-preview > p { margin-top: 0 } -.editor-preview pre, -.editor-preview-side pre { +.editor-preview pre { background: #eee; margin-bottom: 10px; } .editor-preview table td, -.editor-preview table th, -.editor-preview-side table td, -.editor-preview-side table th { +.editor-preview table th { border: 1px solid #ddd; padding: 5px; } diff --git a/src/js/easymde.js b/src/js/easymde.js index cb4f50b..45dbdf8 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -903,6 +903,7 @@ function _replaceSelection(cm, active, startEnd, url) { Object.assign(startPoint, cm.getCursor('start')); Object.assign(endPoint, cm.getCursor('end')); if (url) { + start = start.replace('#url#', url); end = end.replace('#url#', url); } if (active) { From bbf3340581a86ce9d1db0d2427c5b5521e2a4ee1 Mon Sep 17 00:00:00 2001 From: Jeroen van Oorschot Date: Mon, 15 Jul 2019 15:11:07 +0200 Subject: [PATCH 31/51] IE11 compat. Fix status bar. --- CHANGELOG.md | 7 +++++-- src/js/easymde.js | 14 +++++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d8ed5ad..72ff45f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,11 @@ All notable changes to easymde will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -Merge 2.7.0 with https://github.com/Ionaru/easy-markdown-editor/pull/71 @jeroenvo +## [Unreleased/Forked] +- Merge 2.7.0 with https://github.com/Ionaru/easy-markdown-editor/pull/71 @jeroenvo +- replace MouseEvent(click) with .click() for IE compat +- Fix status bar update when dragging but not dropping +- ## [2.7.0] - 2019-07-13 ### Added diff --git a/src/js/easymde.js b/src/js/easymde.js index 45dbdf8..ea32e5b 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -727,6 +727,7 @@ function afterImageUploaded(editor, url) { var options = editor.options; var imageName = url.substr(url.lastIndexOf('/') + 1); _replaceSelection(cm, stat.image, options.insertTexts.uploadedImage, url); + // show uploaded image filename for 1000ms editor.updateStatusBar('upload-image', editor.options.imageTexts.sbOnUploaded.replace('#image_name#', imageName)); setTimeout(function() { editor.updateStatusBar('upload-image', editor.options.imageTexts.sbInit); @@ -1619,8 +1620,19 @@ function EasyMDE(options) { event.stopPropagation(); event.preventDefault(); }); + this.codemirror.on('dragend', function(cm, event) { + self.updateStatusBar('upload-image', self.options.imageTexts.sbInit); + event.stopPropagation(); + event.preventDefault(); + }); + this.codemirror.on('dragleave', function(cm, event) { + self.updateStatusBar('upload-image', self.options.imageTexts.sbInit); + event.stopPropagation(); + event.preventDefault(); + }); this.codemirror.on('dragover', function(cm, event) { + self.updateStatusBar('upload-image', self.options.imageTexts.sbOnDragEnter); event.stopPropagation(); event.preventDefault(); }); @@ -1944,7 +1956,7 @@ EasyMDE.prototype.clearAutosavedValue = function () { EasyMDE.prototype.openBrowseFileWindow = function(onSuccess, onError) { var self = this; var imageInput = this.gui.toolbar.getElementsByClassName('imageInput')[0]; - imageInput.dispatchEvent(new MouseEvent('click')); + imageInput.click() //dispatchEvent(new MouseEvent('click')); // replaced with click() for IE11 compatibility. function onChange(event) { self.uploadImages(event.target.files, onSuccess, onError); imageInput.removeEventListener('change', onChange); From c54168a656ca7f76dc57162989873df9149ec505 Mon Sep 17 00:00:00 2001 From: Jeroen van Oorschot Date: Mon, 15 Jul 2019 15:52:43 +0200 Subject: [PATCH 32/51] Fix status bar. --- CHANGELOG.md | 2 +- src/js/easymde.js | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 72ff45f..f02302e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Merge 2.7.0 with https://github.com/Ionaru/easy-markdown-editor/pull/71 @jeroenvo - replace MouseEvent(click) with .click() for IE compat - Fix status bar update when dragging but not dropping -- +- Fix progressbar ## [2.7.0] - 2019-07-13 ### Added diff --git a/src/js/easymde.js b/src/js/easymde.js index ea32e5b..2576221 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -1956,7 +1956,7 @@ EasyMDE.prototype.clearAutosavedValue = function () { EasyMDE.prototype.openBrowseFileWindow = function(onSuccess, onError) { var self = this; var imageInput = this.gui.toolbar.getElementsByClassName('imageInput')[0]; - imageInput.click() //dispatchEvent(new MouseEvent('click')); // replaced with click() for IE11 compatibility. + imageInput.click(); //dispatchEvent(new MouseEvent('click')); // replaced with click() for IE11 compatibility. function onChange(event) { self.uploadImages(event.target.files, onSuccess, onError); imageInput.removeEventListener('change', onChange); @@ -1996,16 +1996,15 @@ EasyMDE.prototype.uploadImage = function(file, onSuccess, onError) { var formData = new FormData(); formData.append('image', file); var request = new XMLHttpRequest(); - request.open('POST', this.options.imageUploadEndpoint); - request.send(formData); - - request.onprogress = function (event) { + // TODO insert csrf token in post ajax request + request.upload.onprogress = function (event) { if (event.lengthComputable) { - // 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.open('POST', this.options.imageUploadEndpoint); + request.onload = function () { try { @@ -2033,6 +2032,9 @@ EasyMDE.prototype.uploadImage = function(file, onSuccess, onError) { + event.target.status + ' (' + event.target.statusText + ')'); onError(self.options.errorMessages.importError); }; + + request.send(formData); + }; EasyMDE.prototype.createSideBySide = function () { From 29d145a9b135071d36881163938ec61b3be1ae1e Mon Sep 17 00:00:00 2001 From: Jeroen van Oorschot Date: Mon, 15 Jul 2019 21:39:49 +0200 Subject: [PATCH 33/51] Add option for CSRF token on AJAX image upload --- CHANGELOG.md | 1 + README.md | 1 + src/js/easymde.js | 7 +++++-- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f02302e..1775105 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - replace MouseEvent(click) with .click() for IE compat - Fix status bar update when dragging but not dropping - Fix progressbar +- Add option for CSRF token to include in AJAX call for imageupload ## [2.7.0] - 2019-07-13 ### Added diff --git a/README.md b/README.md index 227fe78..1b0b853 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,7 @@ easyMDE.value('New input for **EasyMDE**'); - **imageUploadEndpoint**: The endpoint where the images data will be sent, via an asynchronous *POST* request. The server is supposed to save this image, and return a json response. - if the request was successfully processed (HTTP 200-OK): `{"data": {"filePath": ""}}` where *filePath* is the relative path of the image; - otherwise: `{"error": ""}`, where *errorCode* can be `noFileGiven` (HTTP 400), `typeNotAllowed` (HTTP 415), `fileTooLarge` (HTTP 413) or `importError` (see *errorMessages* below). No default value. +- **imageCSRFToken**: CSRF token to include with AJAX call to upload image. For instance used with Django backend. - **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.`. diff --git a/src/js/easymde.js b/src/js/easymde.js index 2576221..f2a210f 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -1995,8 +1995,12 @@ EasyMDE.prototype.uploadImage = function(file, onSuccess, onError) { var formData = new FormData(); formData.append('image', file); + + // insert CSRF token if provided in config. + if(self.options.imageCSRFToken){ + formData.append('csrfmiddlewaretoken', self.options.imageCSRFToken); + } var request = new XMLHttpRequest(); - // TODO insert csrf token in post ajax request request.upload.onprogress = function (event) { if (event.lengthComputable) { var progress = '' + Math.round((event.loaded * 100) / event.total); @@ -2005,7 +2009,6 @@ EasyMDE.prototype.uploadImage = function(file, onSuccess, onError) { }; request.open('POST', this.options.imageUploadEndpoint); - request.onload = function () { try { var response = JSON.parse(this.responseText); From d9ee9c43d3d4379056830db9c29a8d4ed80a60ba Mon Sep 17 00:00:00 2001 From: Jeroen van Oorschot Date: Mon, 15 Jul 2019 22:04:02 +0200 Subject: [PATCH 34/51] Allow server side error messages. --- README.md | 3 ++- src/js/easymde.js | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1b0b853..72d9a94 100644 --- a/README.md +++ b/README.md @@ -154,7 +154,8 @@ easyMDE.value('New input for **EasyMDE**'); - **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 return a json response. - if the request was successfully processed (HTTP 200-OK): `{"data": {"filePath": ""}}` where *filePath* is the relative path of the image; - - otherwise: `{"error": ""}`, where *errorCode* can be `noFileGiven` (HTTP 400), `typeNotAllowed` (HTTP 415), `fileTooLarge` (HTTP 413) or `importError` (see *errorMessages* below). No default value. + - otherwise: `{"error": ""}`, where *errorCode* can be `noFileGiven` (HTTP 400), `typeNotAllowed` (HTTP 415), `fileTooLarge` (HTTP 413) or `importError` (see *errorMessages* below). If *errorCode* is not one of the *errorMessages*, it is alerted unchanged to the user. This allows for server side error messages. + No default value. - **imageCSRFToken**: CSRF token to include with AJAX call to upload image. For instance used with Django backend. - **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.`. diff --git a/src/js/easymde.js b/src/js/easymde.js index f2a210f..1b0b8b3 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -2020,9 +2020,11 @@ EasyMDE.prototype.uploadImage = function(file, onSuccess, onError) { if(this.status === 200 && response && !response.error && response.data && response.data.filePath) { onSuccess(window.location.origin + '/' + response.data.filePath); } else { - if(response.error && response.error in self.options.errorMessages) { + if(response.error && response.error in self.options.errorMessages) { // preformatted error message onError(fillErrorMessage(self.options.errorMessages[response.error])); - } else { + }else if(response.error){ // server side generated error message + onError(fillErrorMessage(response.error)); + } else { //unknown error console.log('EasyMDE: Received an unexpected response after uploading the image.' + this.status + ' (' + this.statusText + ')'); onError(fillErrorMessage(self.options.errorMessages.importError)); From 4f581b0c313511acbeb16f16d64eee4369ac846b Mon Sep 17 00:00:00 2001 From: Jeroen van Oorschot Date: Mon, 15 Jul 2019 22:29:11 +0200 Subject: [PATCH 35/51] Show error message in status bar and reset status bar afterwards. --- gulpfile.js | 2 +- src/js/easymde.js | 26 +++++++++++++++++++------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index be9e581..99fba6f 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -31,7 +31,7 @@ function scripts() { return browserify({entries: './src/js/easymde.js', standalone: 'EasyMDE'}).bundle() .pipe(source('easymde.min.js')) .pipe(buffer()) - // .pipe(terser()) // TODO enable to minify output + .pipe(terser()) .pipe(header(banner, {pkg: pkg})) .pipe(gulp.dest('./dist/')); } diff --git a/src/js/easymde.js b/src/js/easymde.js index 1b0b8b3..05c68aa 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -1978,7 +1978,19 @@ EasyMDE.prototype.uploadImage = function(file, onSuccess, onError) { onSuccess = onSuccess || function onSuccess(imageUrl) { afterImageUploaded(self, imageUrl); }; - onError = onError || self.options.errorCallback; + function onErrorSup(errorMessage){ + // show error on status bar and reset after 1000ms + self.updateStatusBar('upload-image', errorMessage); + setTimeout(function() { + self.updateStatusBar('upload-image', self.options.imageTexts.sbInit); + }, 1000); + // run custom error handler + if(onError && typeof onError === 'function'){ + onError(errorMessage); + } + // run error handler from options, this alerts the message. + self.options.errorCallback(errorMessage); + } function fillErrorMessage(errorMessage) { var units = self.options.imageTexts.sizeUnits.split(','); @@ -1989,7 +2001,7 @@ EasyMDE.prototype.uploadImage = function(file, onSuccess, onError) { } if (file.size > this.options.imageMaxSize) { - onError(fillErrorMessage(this.options.errorMessages.fileTooLarge)); + onErrorSup(fillErrorMessage(this.options.errorMessages.fileTooLarge)); return; } @@ -2014,20 +2026,20 @@ EasyMDE.prototype.uploadImage = function(file, onSuccess, onError) { var response = JSON.parse(this.responseText); } catch (error) { console.log('EasyMDE: The server did not return a valid json.'); - onError(fillErrorMessage(self.options.errorMessages.importError)); + onErrorSup(fillErrorMessage(self.options.errorMessages.importError)); return; } if(this.status === 200 && response && !response.error && response.data && response.data.filePath) { onSuccess(window.location.origin + '/' + response.data.filePath); } else { if(response.error && response.error in self.options.errorMessages) { // preformatted error message - onError(fillErrorMessage(self.options.errorMessages[response.error])); + onErrorSup(fillErrorMessage(self.options.errorMessages[response.error])); }else if(response.error){ // server side generated error message - onError(fillErrorMessage(response.error)); + onErrorSup(fillErrorMessage(response.error)); } else { //unknown error console.log('EasyMDE: Received an unexpected response after uploading the image.' + this.status + ' (' + this.statusText + ')'); - onError(fillErrorMessage(self.options.errorMessages.importError)); + onErrorSup(fillErrorMessage(self.options.errorMessages.importError)); } } }; @@ -2035,7 +2047,7 @@ EasyMDE.prototype.uploadImage = function(file, onSuccess, onError) { 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.importError); + onErrorSup(self.options.errorMessages.importError); }; request.send(formData); From 5f56c27ba77abc6d9c2b457cb303a2fcbd4da1ed Mon Sep 17 00:00:00 2001 From: Jeroen van Oorschot Date: Tue, 16 Jul 2019 11:01:05 +0200 Subject: [PATCH 36/51] update changelog --- CHANGELOG.md | 2 ++ src/js/easymde.js | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1775105..c289fc5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix status bar update when dragging but not dropping - Fix progressbar - Add option for CSRF token to include in AJAX call for imageupload +- Fix status bar reset after upload error +- Add server side error messages on image upload. ## [2.7.0] - 2019-07-13 ### Added diff --git a/src/js/easymde.js b/src/js/easymde.js index 05c68aa..3c336d9 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -904,7 +904,7 @@ function _replaceSelection(cm, active, startEnd, url) { Object.assign(startPoint, cm.getCursor('start')); Object.assign(endPoint, cm.getCursor('end')); if (url) { - start = start.replace('#url#', url); + start = start.replace('#url#', url); // url is in start for upload-image end = end.replace('#url#', url); } if (active) { From 6c66b54e2aeaef6883bd555e7ceabaf6f9ce64a2 Mon Sep 17 00:00:00 2001 From: Jeroen Akkerman Date: Thu, 18 Jul 2019 11:45:39 +0200 Subject: [PATCH 37/51] Improve status bar logic --- src/js/easymde.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/js/easymde.js b/src/js/easymde.js index 3c336d9..f2e338c 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -1540,10 +1540,10 @@ function EasyMDE(options) { // Handle status bar if (!Object.prototype.hasOwnProperty.call(options, 'status')) { + options.status = ['autosave', 'lines', 'words', 'cursor']; + if (options.uploadImage) { - options.status = ['upload-image', 'autosave', 'lines', 'words', 'cursor']; - } else { - options.status = ['autosave', 'lines', 'words', 'cursor']; + options.status.unshift('upload-image'); } } From f1b6a42561240323d700595b6a80a3c1f970864e Mon Sep 17 00:00:00 2001 From: Jeroen Akkerman Date: Thu, 18 Jul 2019 12:00:32 +0200 Subject: [PATCH 38/51] Auto-format of the code --- src/js/easymde.js | 84 ++++++++++++++++++++++++----------------------- 1 file changed, 43 insertions(+), 41 deletions(-) diff --git a/src/js/easymde.js b/src/js/easymde.js index f2e338c..055057c 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -122,8 +122,8 @@ function createToolbarButton(options, enableTooltips, shortcuts) { enableTooltips = (enableTooltips == undefined) ? true : enableTooltips; // Properly hande custom shortcuts - if( options.name && options.name in shortcuts ){ - bindings[options.name] = options.action; + if (options.name && options.name in shortcuts) { + bindings[options.name] = options.action; } if (options.title && enableTooltips) { @@ -284,7 +284,7 @@ function toggleFullScreen(editor) { if (/editor-preview-active-side/.test(sidebyside.className)) toggleSideBySide(editor); - if (editor.options.onToggleFullScreen) { + if (editor.options.onToggleFullScreen) { editor.options.onToggleFullScreen(cm.getOption('fullScreen') || false); } } @@ -729,7 +729,7 @@ function afterImageUploaded(editor, url) { _replaceSelection(cm, stat.image, options.insertTexts.uploadedImage, url); // show uploaded image filename for 1000ms editor.updateStatusBar('upload-image', editor.options.imageTexts.sbOnUploaded.replace('#image_name#', imageName)); - setTimeout(function() { + setTimeout(function () { editor.updateStatusBar('upload-image', editor.options.imageTexts.sbInit); }, 1000); } @@ -1044,7 +1044,7 @@ function _toggleLine(cm, name) { char = ''; } text = arr[1] + char + arr[3] + text.replace(whitespacesRegexp, '').replace(repl[name], '$1'); - } else if (untoggleOnly == false){ + } else if (untoggleOnly == false) { text = char + ' ' + text; } return text; @@ -1176,14 +1176,14 @@ function _cleanBlock(cm) { * @returns string A human-readable file size. Ex: '412Kb' */ function humanFileSize(bytes, units) { - if(Math.abs(bytes) < 1024) { + if (Math.abs(bytes) < 1024) { return '' + bytes + units[0]; } var u = 0; do { bytes /= 1024; ++u; - } while(Math.abs(bytes) >= 1024 && u < units.length); + } while (Math.abs(bytes) >= 1024 && u < units.length); return '' + bytes.toFixed(1) + units[u]; } @@ -1580,13 +1580,13 @@ function EasyMDE(options) { options.minHeight = options.minHeight || '300px'; - options.errorCallback = options.errorCallback || function(errorMessage) { - alert(errorMessage); + options.errorCallback = options.errorCallback || function (errorMessage) { + alert(errorMessage); }; // Import-image default configuration options.uploadImage = options.uploadImage || false; - options.imageMaxSize = options.imageMaxSize || 1024*1024*2; + options.imageMaxSize = options.imageMaxSize || 1024 * 1024 * 2; options.imageAccept = options.imageAccept || 'image/png, image/jpeg'; options.imageTexts = extend({}, imageTexts, options.imageTexts || {}); options.errorMessages = extend({}, errorMessages, options.errorMessages || {}); @@ -1615,35 +1615,35 @@ function EasyMDE(options) { if (options.uploadImage) { var self = this; - this.codemirror.on('dragenter', function(cm, event) { + this.codemirror.on('dragenter', function (cm, event) { self.updateStatusBar('upload-image', self.options.imageTexts.sbOnDragEnter); event.stopPropagation(); event.preventDefault(); }); - this.codemirror.on('dragend', function(cm, event) { + this.codemirror.on('dragend', function (cm, event) { self.updateStatusBar('upload-image', self.options.imageTexts.sbInit); event.stopPropagation(); event.preventDefault(); }); - this.codemirror.on('dragleave', function(cm, event) { + this.codemirror.on('dragleave', function (cm, event) { self.updateStatusBar('upload-image', self.options.imageTexts.sbInit); event.stopPropagation(); event.preventDefault(); }); - this.codemirror.on('dragover', function(cm, event) { + this.codemirror.on('dragover', function (cm, event) { self.updateStatusBar('upload-image', self.options.imageTexts.sbOnDragEnter); event.stopPropagation(); event.preventDefault(); }); - this.codemirror.on('drop', function(cm, event) { + this.codemirror.on('drop', function (cm, event) { event.stopPropagation(); event.preventDefault(); self.uploadImages(event.dataTransfer.files); }); - this.codemirror.on('paste', function(cm, event) { + this.codemirror.on('paste', function (cm, event) { self.uploadImages(event.clipboardData.files); }); } @@ -1660,9 +1660,9 @@ function EasyMDE(options) { * @param [onSuccess] {function} see EasyMDE.prototype.uploadImage * @param [onError] {function} see EasyMDE.prototype.uploadImage */ -EasyMDE.prototype.uploadImages = function(files, onSuccess, onError) { +EasyMDE.prototype.uploadImages = function (files, onSuccess, onError) { var names = []; - for(var i=0; i Date: Thu, 18 Jul 2019 12:01:50 +0200 Subject: [PATCH 39/51] Pre-calculate max file size --- src/js/easymde.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/easymde.js b/src/js/easymde.js index 055057c..489d4ff 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -1586,7 +1586,7 @@ function EasyMDE(options) { // Import-image default configuration options.uploadImage = options.uploadImage || false; - options.imageMaxSize = options.imageMaxSize || 1024 * 1024 * 2; + options.imageMaxSize = options.imageMaxSize || 2097152; // 1024 * 1024 * 2 options.imageAccept = options.imageAccept || 'image/png, image/jpeg'; options.imageTexts = extend({}, imageTexts, options.imageTexts || {}); options.errorMessages = extend({}, errorMessages, options.errorMessages || {}); From 11963829fc973c455fe4d219c6bd861569441cfe Mon Sep 17 00:00:00 2001 From: Jeroen Akkerman Date: Thu, 18 Jul 2019 12:35:14 +0200 Subject: [PATCH 40/51] Added typings for image upload --- README.md | 2 +- types/easymde-test.ts | 25 +++++++++++++++++++++++++ types/easymde.d.ts | 25 +++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 72d9a94..d240400 100644 --- a/README.md +++ b/README.md @@ -154,7 +154,7 @@ easyMDE.value('New input for **EasyMDE**'); - **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 return a json response. - if the request was successfully processed (HTTP 200-OK): `{"data": {"filePath": ""}}` where *filePath* is the relative path of the image; - - otherwise: `{"error": ""}`, where *errorCode* can be `noFileGiven` (HTTP 400), `typeNotAllowed` (HTTP 415), `fileTooLarge` (HTTP 413) or `importError` (see *errorMessages* below). If *errorCode* is not one of the *errorMessages*, it is alerted unchanged to the user. This allows for server side error messages. + - otherwise: `{"error": ""}`, where *errorCode* can be `noFileGiven` (HTTP 400), `typeNotAllowed` (HTTP 415), `fileTooLarge` (HTTP 413) or `importError` (see *errorMessages* below). If *errorCode* is not one of the *errorMessages*, it is alerted unchanged to the user. This allows for server side error messages. No default value. - **imageCSRFToken**: CSRF token to include with AJAX call to upload image. For instance used with Django backend. - **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: diff --git a/types/easymde-test.ts b/types/easymde-test.ts index f240ee9..b2fc8dc 100644 --- a/types/easymde-test.ts +++ b/types/easymde-test.ts @@ -59,3 +59,28 @@ const editor2 = new EasyMDE({ }); editor2.clearAutosavedValue(); + +const editorImages = new EasyMDE({ + uploadImage: true, + imageAccept: 'image/png, image/bmp', + imageCSRFToken: undefined, + imageMaxSize: 10485760, + imageUploadEndpoint: 'https://my.domain/image-upload/', + imageTexts: { + sbInit: 'Drag & drop images!', + sbOnDragEnter: 'Let it go, let it go', + sbOnDrop: 'Uploading...', + sbProgress: 'Uploading... (#progress#)', + sbOnUploaded: 'Upload complete!', + sizeUnits: 'b,Kb,Mb' + }, + errorMessages: { + noFileGiven: 'Please select a file', + imageTypeNotAllowed: 'This file type is not allowed!', + imageTooLarge: 'Image too big', + imageImportError: 'Something went oops!', + }, + errorCallback: (errorMessage) => { + console.error(errorMessage); + }, +}); diff --git a/types/easymde.d.ts b/types/easymde.d.ts index 2055b77..84ba65d 100644 --- a/types/easymde.d.ts +++ b/types/easymde.d.ts @@ -86,6 +86,22 @@ declare namespace EasyMDE { noMobile?: boolean; } + interface ImageTextsOptions { + sbInit?: string; + sbOnDragEnter?: string; + sbOnDrop?: string; + sbProgress?: string; + sbOnUploaded?: string; + sizeUnits?: string; + } + + interface ImageErrorTextsOptions { + noFileGiven?: string; + imageTypeNotAllowed?: string; + imageTooLarge?: string; + imageImportError?: string; + } + interface Options { autoDownloadFontAwesome?: boolean; autofocus?: boolean; @@ -114,6 +130,15 @@ declare namespace EasyMDE { toolbarTips?: boolean; onToggleFullScreen?: (goingIntoFullScreen: boolean) => void; theme?: string; + + uploadImage?: boolean; + imageMaxSize?: number; + imageAccept?: string; + imageUploadEndpoint?: string; + imageCSRFToken?: string; + imageTexts?: ImageTextsOptions; + errorMessages?: ImageErrorTextsOptions; + errorCallback?: (errorMessage: string) => void; } } From 65af615c9b9f5df05361f7980cdfde59aff9e7e1 Mon Sep 17 00:00:00 2001 From: Jeroen Akkerman Date: Thu, 18 Jul 2019 12:43:10 +0200 Subject: [PATCH 41/51] This PR will close #46 (super small edit to make that comment) --- src/js/easymde.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/js/easymde.js b/src/js/easymde.js index 489d4ff..99d42c1 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -2232,11 +2232,10 @@ EasyMDE.prototype.createStatusbar = function (status) { var options = this.options; var cm = this.codemirror; - // Make sure the status variable is valid - if (!status || status.length === 0) + if (!status || status.length === 0) { return; - + } // Set up the built-in items var items = []; From cd7c9b8d4dcefdbb571a692e149007523257dc1d Mon Sep 17 00:00:00 2001 From: Jeroen Akkerman Date: Thu, 18 Jul 2019 12:56:51 +0200 Subject: [PATCH 42/51] Fixed errorMessages --- README.md | 6 +++--- types/easymde-test.ts | 6 +++--- types/easymde.d.ts | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index d240400..3a7249d 100644 --- a/README.md +++ b/README.md @@ -166,9 +166,9 @@ easyMDE.value('New input for **EasyMDE**'); - **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, using the `errorCallback` option, 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#.`. + - **typeNotAllowed**: 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.`. + - **fileTooLarge**: 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#.`. + - **importError**: An unexpected error occurred when uploading the image. Defaults to `Something went wrong when uploading the image #image_name#.`. - **errorCallback**: A callback function used to define how to display an error message. Defaults to `function(errorMessage) {alert(errorMessage);};`. - **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:
``
`` diff --git a/types/easymde-test.ts b/types/easymde-test.ts index b2fc8dc..12b0555 100644 --- a/types/easymde-test.ts +++ b/types/easymde-test.ts @@ -76,9 +76,9 @@ const editorImages = new EasyMDE({ }, errorMessages: { noFileGiven: 'Please select a file', - imageTypeNotAllowed: 'This file type is not allowed!', - imageTooLarge: 'Image too big', - imageImportError: 'Something went oops!', + typeNotAllowed: 'This file type is not allowed!', + fileTooLarge: 'Image too big', + importError: 'Something went oops!', }, errorCallback: (errorMessage) => { console.error(errorMessage); diff --git a/types/easymde.d.ts b/types/easymde.d.ts index 84ba65d..2a7db40 100644 --- a/types/easymde.d.ts +++ b/types/easymde.d.ts @@ -97,9 +97,9 @@ declare namespace EasyMDE { interface ImageErrorTextsOptions { noFileGiven?: string; - imageTypeNotAllowed?: string; - imageTooLarge?: string; - imageImportError?: string; + typeNotAllowed?: string; + fileTooLarge?: string; + importError?: string; } interface Options { From 0558fb0d68536170f4102af2ea128039f24830c3 Mon Sep 17 00:00:00 2001 From: Jeroen Akkerman Date: Thu, 18 Jul 2019 14:29:54 +0200 Subject: [PATCH 43/51] Increase timeout of error message to 10s --- src/js/easymde.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/js/easymde.js b/src/js/easymde.js index 99d42c1..68503af 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -1981,11 +1981,13 @@ EasyMDE.prototype.uploadImage = function (file, onSuccess, onError) { }; function onErrorSup(errorMessage) { - // show error on status bar and reset after 1000ms + // show error on status bar and reset after 10000ms self.updateStatusBar('upload-image', errorMessage); + setTimeout(function () { self.updateStatusBar('upload-image', self.options.imageTexts.sbInit); - }, 1000); + }, 10000); + // run custom error handler if (onError && typeof onError === 'function') { onError(errorMessage); From 63a1825b6e826a744555f7be11f5a57b4539c2ce Mon Sep 17 00:00:00 2001 From: Jeroen Akkerman Date: Thu, 18 Jul 2019 14:46:08 +0200 Subject: [PATCH 44/51] Log errors to console.error --- src/js/easymde.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/js/easymde.js b/src/js/easymde.js index 68503af..8beb664 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -2029,7 +2029,7 @@ EasyMDE.prototype.uploadImage = function (file, onSuccess, onError) { try { var response = JSON.parse(this.responseText); } catch (error) { - console.log('EasyMDE: The server did not return a valid json.'); + console.error('EasyMDE: The server did not return a valid json.'); onErrorSup(fillErrorMessage(self.options.errorMessages.importError)); return; } @@ -2041,7 +2041,7 @@ EasyMDE.prototype.uploadImage = function (file, onSuccess, onError) { } else if (response.error) { // server side generated error message onErrorSup(fillErrorMessage(response.error)); } else { //unknown error - console.log('EasyMDE: Received an unexpected response after uploading the image.' + console.error('EasyMDE: Received an unexpected response after uploading the image.' + this.status + ' (' + this.statusText + ')'); onErrorSup(fillErrorMessage(self.options.errorMessages.importError)); } @@ -2049,7 +2049,7 @@ EasyMDE.prototype.uploadImage = function (file, onSuccess, onError) { }; request.onerror = function (event) { - console.log('EasyMDE: An unexpected error occurred when trying to upload the image.' + console.error('EasyMDE: An unexpected error occurred when trying to upload the image.' + event.target.status + ' (' + event.target.statusText + ')'); onErrorSup(self.options.errorMessages.importError); }; From a8ee1c72816fc3e8e0bee292ed79a7384f369f5c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jul 2019 02:31:16 +0000 Subject: [PATCH 45/51] Bump lodash.template from 4.4.0 to 4.5.0 Bumps [lodash.template](https://github.com/lodash/lodash) from 4.4.0 to 4.5.0. - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](https://github.com/lodash/lodash/compare/4.4.0...4.5.0) Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 98c7c63..f28782f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3472,12 +3472,12 @@ "dev": true }, "lodash.template": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.4.0.tgz", - "integrity": "sha1-5zoDhcg1VZF0bgILmWecaQ5o+6A=", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", + "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", "dev": true, "requires": { - "lodash._reinterpolate": "~3.0.0", + "lodash._reinterpolate": "^3.0.0", "lodash.templatesettings": "^4.0.0" } }, From 0a5b0d3ac4d2c443b71dae247652750e65f681ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastia=CC=81n=20Pe=CC=81rez=20Pe=CC=81rez?= Date: Tue, 23 Jul 2019 12:53:38 +0100 Subject: [PATCH 46/51] Allow custom upload function --- README.md | 4 ++- src/js/easymde.js | 67 +++++++++++++++++++++++++++++++++++++++++-- types/easymde-test.ts | 31 +++++++++++++++++++- types/easymde.d.ts | 1 + 4 files changed, 99 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 3a7249d..00e3be3 100644 --- a/README.md +++ b/README.md @@ -152,11 +152,13 @@ easyMDE.value('New input for **EasyMDE**'); - **uploadImage**: If set to `true`, enables the image upload functionality, which can be triggered by drag&drop, copy-paste and through the browse-file window (opened when the user click on the *upload-image* icon). Defaults to `false`. - **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`. +- **imageUploadFunction**: A custom function for handling the image upload. Using this function will render the options `imageMaxSize`, `imageAccept`, `imageUploadEndpoint` and `imageCSRFToken` ineffective. + - The function gets a file and onSuccess and onError callback functions as parameters. `onSuccess(imageUrl: string)` and `onError(errorMessage: string)` - **imageUploadEndpoint**: The endpoint where the images data will be sent, via an asynchronous *POST* request. The server is supposed to save this image, and return a json response. - if the request was successfully processed (HTTP 200-OK): `{"data": {"filePath": ""}}` where *filePath* is the relative path of the image; - otherwise: `{"error": ""}`, where *errorCode* can be `noFileGiven` (HTTP 400), `typeNotAllowed` (HTTP 415), `fileTooLarge` (HTTP 413) or `importError` (see *errorMessages* below). If *errorCode* is not one of the *errorMessages*, it is alerted unchanged to the user. This allows for server side error messages. No default value. -- **imageCSRFToken**: CSRF token to include with AJAX call to upload image. For instance used with Django backend. +- **imageCSRFToken**: CSRF token to include with AJAX call to upload image. For instance used with Django backend. - **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.`. diff --git a/src/js/easymde.js b/src/js/easymde.js index 8beb664..5e2376c 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -1640,11 +1640,19 @@ function EasyMDE(options) { this.codemirror.on('drop', function (cm, event) { event.stopPropagation(); event.preventDefault(); - self.uploadImages(event.dataTransfer.files); + if (options.imageUploadFunction) { + self.uploadImagesUsingCustomFunction(options.imageUploadFunction, event.dataTransfer.files); + } else { + self.uploadImages(event.dataTransfer.files); + } }); this.codemirror.on('paste', function (cm, event) { - self.uploadImages(event.clipboardData.files); + if (options.imageUploadFunction) { + self.uploadImagesUsingCustomFunction(options.imageUploadFunction, event.clipboardData.files); + } else { + self.uploadImages(event.clipboardData.files); + } }); } } @@ -1669,6 +1677,25 @@ EasyMDE.prototype.uploadImages = function (files, onSuccess, onError) { this.updateStatusBar('upload-image', this.options.imageTexts.sbOnDrop.replace('#images_names#', names.join(', '))); }; +/** + * Upload asynchronously a list of images to a server. + * + * Can be triggered by: + * - drag&drop; + * - copy-paste; + * - the browse-file window (opened when the user clicks on the *upload-image* icon). + * @param imageUploadFunction {Function} The custom function to upload the image passed in options. + * @param {FileList} files The files to upload the the server. + */ +EasyMDE.prototype.uploadImagesUsingCustomFunction = function (imageUploadFunction, files) { + var names = []; + for (var i = 0; i < files.length; i++) { + names.push(files[i].name); + this.uploadImageUsingCustomFunction(imageUploadFunction, files[i]); + } + this.updateStatusBar('upload-image', this.options.imageTexts.sbOnDrop.replace('#images_names#', names.join(', '))); +}; + /** * Update an item in the status bar. * @param itemName {string} The name of the item to update (ie. 'upload-image', 'autosave', etc.). @@ -2058,6 +2085,42 @@ EasyMDE.prototype.uploadImage = function (file, onSuccess, onError) { }; +/** + * Upload an image to the server using a custom upload function. + * + * @param imageUploadFunction {Function} The custom function to upload the image passed in options + * @param file {File} The image to upload, as a HTML5 File object (https://developer.mozilla.org/en-US/docs/Web/API/File). + */ +EasyMDE.prototype.uploadImageUsingCustomFunction = function(imageUploadFunction, file) { + var self = this; + function onSuccess(imageUrl) { + afterImageUploaded(self, imageUrl); + } + + function onError(errorMessage) { + var filledErrorMessage = fillErrorMessage(errorMessage); + // show error on status bar and reset after 10000ms + self.updateStatusBar('upload-image', filledErrorMessage); + + setTimeout(function () { + self.updateStatusBar('upload-image', self.options.imageTexts.sbInit); + }, 10000); + + // run error handler from options, this alerts the message. + self.options.errorCallback(filledErrorMessage); + } + + 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)); + } + + imageUploadFunction(file, onSuccess, onError); +}; + EasyMDE.prototype.createSideBySide = function () { var cm = this.codemirror; var wrapper = cm.getWrapperElement(); diff --git a/types/easymde-test.ts b/types/easymde-test.ts index 12b0555..103569b 100644 --- a/types/easymde-test.ts +++ b/types/easymde-test.ts @@ -1,4 +1,6 @@ // Create new instance +import EasyMDE = require('./easymde'); + const editor = new EasyMDE({ autoDownloadFontAwesome: false, element: document.getElementById('mdEditor')!, @@ -40,7 +42,7 @@ const editor2 = new EasyMDE({ title: 'Bold', }, '|', { // Separator name: 'alert', - action: (editor) => { + action: (editor: EasyMDE) => { alert('This is from a custom button action!'); // Custom functions have access to the `editor` instance. }, @@ -84,3 +86,30 @@ const editorImages = new EasyMDE({ console.error(errorMessage); }, }); + +const editorImagesCustom = new EasyMDE({ + uploadImage: true, + imageAccept: 'image/png, image/bmp', + imageCSRFToken: undefined, + imageMaxSize: 10485760, + imageUploadFunction: (file: File, onSuccess: Function, onError: Function) => { + console.log(file) + }, + imageTexts: { + sbInit: 'Drag & drop images!', + sbOnDragEnter: 'Let it go, let it go', + sbOnDrop: 'Uploading...', + sbProgress: 'Uploading... (#progress#)', + sbOnUploaded: 'Upload complete!', + sizeUnits: 'b,Kb,Mb' + }, + errorMessages: { + noFileGiven: 'Please select a file', + typeNotAllowed: 'This file type is not allowed!', + fileTooLarge: 'Image too big', + importError: 'Something went oops!', + }, + errorCallback: (errorMessage) => { + console.error(errorMessage); + }, + }); diff --git a/types/easymde.d.ts b/types/easymde.d.ts index 2a7db40..1fa121c 100644 --- a/types/easymde.d.ts +++ b/types/easymde.d.ts @@ -134,6 +134,7 @@ declare namespace EasyMDE { uploadImage?: boolean; imageMaxSize?: number; imageAccept?: string; + imageUploadFunction?: (file: File, onSuccess: Function, onError: Function) => void; imageUploadEndpoint?: string; imageCSRFToken?: string; imageTexts?: ImageTextsOptions; From 509763f3b20ebd2530478c3aa875aea631e01fba Mon Sep 17 00:00:00 2001 From: Jeroen Akkerman Date: Wed, 24 Jul 2019 14:26:11 +0200 Subject: [PATCH 47/51] Stricter typings for the onSuccess and onError calls --- types/easymde-test.ts | 6 ++++-- types/easymde.d.ts | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/types/easymde-test.ts b/types/easymde-test.ts index 103569b..75975f8 100644 --- a/types/easymde-test.ts +++ b/types/easymde-test.ts @@ -92,8 +92,10 @@ const editorImagesCustom = new EasyMDE({ imageAccept: 'image/png, image/bmp', imageCSRFToken: undefined, imageMaxSize: 10485760, - imageUploadFunction: (file: File, onSuccess: Function, onError: Function) => { - console.log(file) + imageUploadFunction: (file: File, onSuccess, onError) => { + console.log(file); + onSuccess('http://image.url/9.png'); + onError('Failed because reasons.'); }, imageTexts: { sbInit: 'Drag & drop images!', diff --git a/types/easymde.d.ts b/types/easymde.d.ts index 1fa121c..dd4bd4d 100644 --- a/types/easymde.d.ts +++ b/types/easymde.d.ts @@ -134,7 +134,7 @@ declare namespace EasyMDE { uploadImage?: boolean; imageMaxSize?: number; imageAccept?: string; - imageUploadFunction?: (file: File, onSuccess: Function, onError: Function) => void; + imageUploadFunction?: (file: File, onSuccess: (url: string) => void, onError: (error: string) => void) => void; imageUploadEndpoint?: string; imageCSRFToken?: string; imageTexts?: ImageTextsOptions; From 02d6653cc546ef0dc80d0ab0192c7d602a1a659b Mon Sep 17 00:00:00 2001 From: Jeroen Akkerman Date: Wed, 24 Jul 2019 14:57:25 +0200 Subject: [PATCH 48/51] Updated changelog for PR #106 --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c72fb5..a1283c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added -- Upload images functionality. (Thanks to [@roipoussiere] and [@JeroenvO], [#71], [#101] +- Upload images functionality (Thanks to [@roipoussiere] and [@JeroenvO], [#71], [#101]). +- Allow custom image upload function (Thanks to [@sperezp], [#106]). ## [2.7.0] - 2019-07-13 ### Added @@ -124,6 +125,7 @@ Project forked from [SimpleMDE](https://github.com/sparksuite/simplemde-markdown [#9]: https://github.com/Ionaru/easy-markdown-editor/issues/9 +[#106]: https://github.com/Ionaru/easy-markdown-editor/pull/106 [#101]: https://github.com/Ionaru/easy-markdown-editor/pull/101 [#93]: https://github.com/Ionaru/easy-markdown-editor/pull/93 [#75]: https://github.com/Ionaru/easy-markdown-editor/pull/75 @@ -134,6 +136,7 @@ Project forked from [SimpleMDE](https://github.com/sparksuite/simplemde-markdown [#19]: https://github.com/Ionaru/easy-markdown-editor/pull/19 +[@sperezp]: https://github.com/sperezp [@JeroenvO]: https://github.com/JeroenvO [@sn3p]: https://github.com/sn3p [@roryok]: https://github.com/roryok From efb840c6332a8137491efce3a813ead070d94d29 Mon Sep 17 00:00:00 2001 From: Jeremy Fleischman Date: Mon, 29 Jul 2019 02:49:36 -0700 Subject: [PATCH 49/51] Fix `openBrowseFileWindow` to also obey `self.options.imageUploadFunction` if specified. I think this part just got missed in https://github.com/Ionaru/easy-markdown-editor/pull/106. I'm not sure if I should be doing anything with the `onSuccess` and `onError` callbacks here. --- src/js/easymde.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/js/easymde.js b/src/js/easymde.js index 5e2376c..976328a 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -1985,7 +1985,11 @@ EasyMDE.prototype.openBrowseFileWindow = function (onSuccess, onError) { var imageInput = this.gui.toolbar.getElementsByClassName('imageInput')[0]; imageInput.click(); //dispatchEvent(new MouseEvent('click')); // replaced with click() for IE11 compatibility. function onChange(event) { - self.uploadImages(event.target.files, onSuccess, onError); + if (self.options.imageUploadFunction) { + self.uploadImagesUsingCustomFunction(self.options.imageUploadFunction, event.target.files); + } else { + self.uploadImages(event.target.files, onSuccess, onError); + } imageInput.removeEventListener('change', onChange); } From 8a2283cf274b106c001f035209b457ee389013ab Mon Sep 17 00:00:00 2001 From: Jeremy Fleischman Date: Mon, 29 Jul 2019 02:54:20 -0700 Subject: [PATCH 50/51] Bail out if there are no files to upload. Without this change, if you either: - Click and drag some text into the markdown editor, or - Copy paste some text into the markdown editor The status bar will get updated to say "Uploading image ...", and will never stop. --- src/js/easymde.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/js/easymde.js b/src/js/easymde.js index 976328a..c675335 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -1669,6 +1669,9 @@ function EasyMDE(options) { * @param [onError] {function} see EasyMDE.prototype.uploadImage */ EasyMDE.prototype.uploadImages = function (files, onSuccess, onError) { + if (files.length === 0) { + return; + } var names = []; for (var i = 0; i < files.length; i++) { names.push(files[i].name); @@ -1688,6 +1691,9 @@ EasyMDE.prototype.uploadImages = function (files, onSuccess, onError) { * @param {FileList} files The files to upload the the server. */ EasyMDE.prototype.uploadImagesUsingCustomFunction = function (imageUploadFunction, files) { + if (files.length === 0) { + return; + } var names = []; for (var i = 0; i < files.length; i++) { names.push(files[i].name); From 78b2083c9e6625b00c5f8e9a678fd9c42487420a Mon Sep 17 00:00:00 2001 From: Jeroen Akkerman Date: Tue, 20 Aug 2019 00:26:27 +0200 Subject: [PATCH 51/51] Updated changelog for PR #109 --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1283c2..6db6f79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Upload images functionality (Thanks to [@roipoussiere] and [@JeroenvO], [#71], [#101]). - Allow custom image upload function (Thanks to [@sperezp], [#106]). +- More polish to the upload images functionality (Thanks to [@jfly], [#109]). ## [2.7.0] - 2019-07-13 ### Added @@ -125,6 +126,7 @@ Project forked from [SimpleMDE](https://github.com/sparksuite/simplemde-markdown [#9]: https://github.com/Ionaru/easy-markdown-editor/issues/9 +[#109]: https://github.com/Ionaru/easy-markdown-editor/pull/109 [#106]: https://github.com/Ionaru/easy-markdown-editor/pull/106 [#101]: https://github.com/Ionaru/easy-markdown-editor/pull/101 [#93]: https://github.com/Ionaru/easy-markdown-editor/pull/93 @@ -136,6 +138,7 @@ Project forked from [SimpleMDE](https://github.com/sparksuite/simplemde-markdown [#19]: https://github.com/Ionaru/easy-markdown-editor/pull/19 +[@jfly]: https://github.com/jfly [@sperezp]: https://github.com/sperezp [@JeroenvO]: https://github.com/JeroenvO [@sn3p]: https://github.com/sn3p